162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* SCTP kernel implementation
362306a36Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004
462306a36Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc.
562306a36Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc.
662306a36Sopenharmony_ci * Copyright (c) 2001-2002 Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This file is part of the SCTP kernel implementation
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * These functions work with the state functions in sctp_sm_statefuns.c
1162306a36Sopenharmony_ci * to implement the state operations.  These functions implement the
1262306a36Sopenharmony_ci * steps which require modifying existing data structures.
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 *    C. Robin              <chris@hundredacre.ac.uk>
2262306a36Sopenharmony_ci *    Jon Grimm             <jgrimm@us.ibm.com>
2362306a36Sopenharmony_ci *    Xingang Guo           <xingang.guo@intel.com>
2462306a36Sopenharmony_ci *    Dajiang Zhang	    <dajiang.zhang@nokia.com>
2562306a36Sopenharmony_ci *    Sridhar Samudrala	    <sri@us.ibm.com>
2662306a36Sopenharmony_ci *    Daisy Chang	    <daisyc@us.ibm.com>
2762306a36Sopenharmony_ci *    Ardelle Fan	    <ardelle.fan@intel.com>
2862306a36Sopenharmony_ci *    Kevin Gao             <kevin.gao@intel.com>
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <crypto/hash.h>
3462306a36Sopenharmony_ci#include <linux/types.h>
3562306a36Sopenharmony_ci#include <linux/kernel.h>
3662306a36Sopenharmony_ci#include <linux/ip.h>
3762306a36Sopenharmony_ci#include <linux/ipv6.h>
3862306a36Sopenharmony_ci#include <linux/net.h>
3962306a36Sopenharmony_ci#include <linux/inet.h>
4062306a36Sopenharmony_ci#include <linux/scatterlist.h>
4162306a36Sopenharmony_ci#include <linux/slab.h>
4262306a36Sopenharmony_ci#include <net/sock.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include <linux/skbuff.h>
4562306a36Sopenharmony_ci#include <linux/random.h>	/* for get_random_bytes */
4662306a36Sopenharmony_ci#include <net/sctp/sctp.h>
4762306a36Sopenharmony_ci#include <net/sctp/sm.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
5062306a36Sopenharmony_ci					    __u8 type, __u8 flags, int paylen,
5162306a36Sopenharmony_ci					    gfp_t gfp);
5262306a36Sopenharmony_cistatic struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
5362306a36Sopenharmony_ci					 __u8 flags, int paylen, gfp_t gfp);
5462306a36Sopenharmony_cistatic struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
5562306a36Sopenharmony_ci					   __u8 type, __u8 flags, int paylen,
5662306a36Sopenharmony_ci					   gfp_t gfp);
5762306a36Sopenharmony_cistatic struct sctp_cookie_param *sctp_pack_cookie(
5862306a36Sopenharmony_ci					const struct sctp_endpoint *ep,
5962306a36Sopenharmony_ci					const struct sctp_association *asoc,
6062306a36Sopenharmony_ci					const struct sctp_chunk *init_chunk,
6162306a36Sopenharmony_ci					int *cookie_len,
6262306a36Sopenharmony_ci					const __u8 *raw_addrs, int addrs_len);
6362306a36Sopenharmony_cistatic int sctp_process_param(struct sctp_association *asoc,
6462306a36Sopenharmony_ci			      union sctp_params param,
6562306a36Sopenharmony_ci			      const union sctp_addr *peer_addr,
6662306a36Sopenharmony_ci			      gfp_t gfp);
6762306a36Sopenharmony_cistatic void *sctp_addto_param(struct sctp_chunk *chunk, int len,
6862306a36Sopenharmony_ci			      const void *data);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* Control chunk destructor */
7162306a36Sopenharmony_cistatic void sctp_control_release_owner(struct sk_buff *skb)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (chunk->shkey) {
7662306a36Sopenharmony_ci		struct sctp_shared_key *shkey = chunk->shkey;
7762306a36Sopenharmony_ci		struct sctp_association *asoc = chunk->asoc;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		/* refcnt == 2 and !list_empty mean after this release, it's
8062306a36Sopenharmony_ci		 * not being used anywhere, and it's time to notify userland
8162306a36Sopenharmony_ci		 * that this shkey can be freed if it's been deactivated.
8262306a36Sopenharmony_ci		 */
8362306a36Sopenharmony_ci		if (shkey->deactivated && !list_empty(&shkey->key_list) &&
8462306a36Sopenharmony_ci		    refcount_read(&shkey->refcnt) == 2) {
8562306a36Sopenharmony_ci			struct sctp_ulpevent *ev;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci			ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id,
8862306a36Sopenharmony_ci							SCTP_AUTH_FREE_KEY,
8962306a36Sopenharmony_ci							GFP_KERNEL);
9062306a36Sopenharmony_ci			if (ev)
9162306a36Sopenharmony_ci				asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
9262306a36Sopenharmony_ci		}
9362306a36Sopenharmony_ci		sctp_auth_shkey_release(chunk->shkey);
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void sctp_control_set_owner_w(struct sctp_chunk *chunk)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct sctp_association *asoc = chunk->asoc;
10062306a36Sopenharmony_ci	struct sk_buff *skb = chunk->skb;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* TODO: properly account for control chunks.
10362306a36Sopenharmony_ci	 * To do it right we'll need:
10462306a36Sopenharmony_ci	 *  1) endpoint if association isn't known.
10562306a36Sopenharmony_ci	 *  2) proper memory accounting.
10662306a36Sopenharmony_ci	 *
10762306a36Sopenharmony_ci	 *  For now don't do anything for now.
10862306a36Sopenharmony_ci	 */
10962306a36Sopenharmony_ci	if (chunk->auth) {
11062306a36Sopenharmony_ci		chunk->shkey = asoc->shkey;
11162306a36Sopenharmony_ci		sctp_auth_shkey_hold(chunk->shkey);
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci	skb->sk = asoc ? asoc->base.sk : NULL;
11462306a36Sopenharmony_ci	skb_shinfo(skb)->destructor_arg = chunk;
11562306a36Sopenharmony_ci	skb->destructor = sctp_control_release_owner;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/* What was the inbound interface for this chunk? */
11962306a36Sopenharmony_ciint sctp_chunk_iif(const struct sctp_chunk *chunk)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct sk_buff *skb = chunk->skb;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return SCTP_INPUT_CB(skb)->af->skb_iif(skb);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/* RFC 2960 3.3.2 Initiation (INIT) (1)
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci * Note 2: The ECN capable field is reserved for future use of
12962306a36Sopenharmony_ci * Explicit Congestion Notification.
13062306a36Sopenharmony_ci */
13162306a36Sopenharmony_cistatic const struct sctp_paramhdr ecap_param = {
13262306a36Sopenharmony_ci	SCTP_PARAM_ECN_CAPABLE,
13362306a36Sopenharmony_ci	cpu_to_be16(sizeof(struct sctp_paramhdr)),
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_cistatic const struct sctp_paramhdr prsctp_param = {
13662306a36Sopenharmony_ci	SCTP_PARAM_FWD_TSN_SUPPORT,
13762306a36Sopenharmony_ci	cpu_to_be16(sizeof(struct sctp_paramhdr)),
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* A helper to initialize an op error inside a provided chunk, as most
14162306a36Sopenharmony_ci * cause codes will be embedded inside an abort chunk.
14262306a36Sopenharmony_ci */
14362306a36Sopenharmony_ciint sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
14462306a36Sopenharmony_ci		    size_t paylen)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct sctp_errhdr err;
14762306a36Sopenharmony_ci	__u16 len;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Cause code constants are now defined in network order.  */
15062306a36Sopenharmony_ci	err.cause = cause_code;
15162306a36Sopenharmony_ci	len = sizeof(err) + paylen;
15262306a36Sopenharmony_ci	err.length = htons(len);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (skb_tailroom(chunk->skb) < len)
15562306a36Sopenharmony_ci		return -ENOSPC;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(err), &err);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/* 3.3.2 Initiation (INIT) (1)
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * This chunk is used to initiate a SCTP association between two
16562306a36Sopenharmony_ci * endpoints. The format of the INIT chunk is shown below:
16662306a36Sopenharmony_ci *
16762306a36Sopenharmony_ci *     0                   1                   2                   3
16862306a36Sopenharmony_ci *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
16962306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17062306a36Sopenharmony_ci *    |   Type = 1    |  Chunk Flags  |      Chunk Length             |
17162306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17262306a36Sopenharmony_ci *    |                         Initiate Tag                          |
17362306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17462306a36Sopenharmony_ci *    |           Advertised Receiver Window Credit (a_rwnd)          |
17562306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17662306a36Sopenharmony_ci *    |  Number of Outbound Streams   |  Number of Inbound Streams    |
17762306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17862306a36Sopenharmony_ci *    |                          Initial TSN                          |
17962306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18062306a36Sopenharmony_ci *    \                                                               \
18162306a36Sopenharmony_ci *    /              Optional/Variable-Length Parameters              /
18262306a36Sopenharmony_ci *    \                                                               \
18362306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci *
18662306a36Sopenharmony_ci * The INIT chunk contains the following parameters. Unless otherwise
18762306a36Sopenharmony_ci * noted, each parameter MUST only be included once in the INIT chunk.
18862306a36Sopenharmony_ci *
18962306a36Sopenharmony_ci * Fixed Parameters                     Status
19062306a36Sopenharmony_ci * ----------------------------------------------
19162306a36Sopenharmony_ci * Initiate Tag                        Mandatory
19262306a36Sopenharmony_ci * Advertised Receiver Window Credit   Mandatory
19362306a36Sopenharmony_ci * Number of Outbound Streams          Mandatory
19462306a36Sopenharmony_ci * Number of Inbound Streams           Mandatory
19562306a36Sopenharmony_ci * Initial TSN                         Mandatory
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci * Variable Parameters                  Status     Type Value
19862306a36Sopenharmony_ci * -------------------------------------------------------------
19962306a36Sopenharmony_ci * IPv4 Address (Note 1)               Optional    5
20062306a36Sopenharmony_ci * IPv6 Address (Note 1)               Optional    6
20162306a36Sopenharmony_ci * Cookie Preservative                 Optional    9
20262306a36Sopenharmony_ci * Reserved for ECN Capable (Note 2)   Optional    32768 (0x8000)
20362306a36Sopenharmony_ci * Host Name Address (Note 3)          Optional    11
20462306a36Sopenharmony_ci * Supported Address Types (Note 4)    Optional    12
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_cistruct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
20762306a36Sopenharmony_ci				  const struct sctp_bind_addr *bp,
20862306a36Sopenharmony_ci				  gfp_t gfp, int vparam_len)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct sctp_supported_ext_param ext_param;
21162306a36Sopenharmony_ci	struct sctp_adaptation_ind_param aiparam;
21262306a36Sopenharmony_ci	struct sctp_paramhdr *auth_chunks = NULL;
21362306a36Sopenharmony_ci	struct sctp_paramhdr *auth_hmacs = NULL;
21462306a36Sopenharmony_ci	struct sctp_supported_addrs_param sat;
21562306a36Sopenharmony_ci	struct sctp_endpoint *ep = asoc->ep;
21662306a36Sopenharmony_ci	struct sctp_chunk *retval = NULL;
21762306a36Sopenharmony_ci	int num_types, addrs_len = 0;
21862306a36Sopenharmony_ci	struct sctp_inithdr init;
21962306a36Sopenharmony_ci	union sctp_params addrs;
22062306a36Sopenharmony_ci	struct sctp_sock *sp;
22162306a36Sopenharmony_ci	__u8 extensions[5];
22262306a36Sopenharmony_ci	size_t chunksize;
22362306a36Sopenharmony_ci	__be16 types[2];
22462306a36Sopenharmony_ci	int num_ext = 0;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* RFC 2960 3.3.2 Initiation (INIT) (1)
22762306a36Sopenharmony_ci	 *
22862306a36Sopenharmony_ci	 * Note 1: The INIT chunks can contain multiple addresses that
22962306a36Sopenharmony_ci	 * can be IPv4 and/or IPv6 in any combination.
23062306a36Sopenharmony_ci	 */
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* Convert the provided bind address list to raw format. */
23362306a36Sopenharmony_ci	addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	init.init_tag		   = htonl(asoc->c.my_vtag);
23662306a36Sopenharmony_ci	init.a_rwnd		   = htonl(asoc->rwnd);
23762306a36Sopenharmony_ci	init.num_outbound_streams  = htons(asoc->c.sinit_num_ostreams);
23862306a36Sopenharmony_ci	init.num_inbound_streams   = htons(asoc->c.sinit_max_instreams);
23962306a36Sopenharmony_ci	init.initial_tsn	   = htonl(asoc->c.initial_tsn);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/* How many address types are needed? */
24262306a36Sopenharmony_ci	sp = sctp_sk(asoc->base.sk);
24362306a36Sopenharmony_ci	num_types = sp->pf->supported_addrs(sp, types);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	chunksize = sizeof(init) + addrs_len;
24662306a36Sopenharmony_ci	chunksize += SCTP_PAD4(SCTP_SAT_LEN(num_types));
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (asoc->ep->ecn_enable)
24962306a36Sopenharmony_ci		chunksize += sizeof(ecap_param);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (asoc->ep->prsctp_enable)
25262306a36Sopenharmony_ci		chunksize += sizeof(prsctp_param);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* ADDIP: Section 4.2.7:
25562306a36Sopenharmony_ci	 *  An implementation supporting this extension [ADDIP] MUST list
25662306a36Sopenharmony_ci	 *  the ASCONF,the ASCONF-ACK, and the AUTH  chunks in its INIT and
25762306a36Sopenharmony_ci	 *  INIT-ACK parameters.
25862306a36Sopenharmony_ci	 */
25962306a36Sopenharmony_ci	if (asoc->ep->asconf_enable) {
26062306a36Sopenharmony_ci		extensions[num_ext] = SCTP_CID_ASCONF;
26162306a36Sopenharmony_ci		extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
26262306a36Sopenharmony_ci		num_ext += 2;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (asoc->ep->reconf_enable) {
26662306a36Sopenharmony_ci		extensions[num_ext] = SCTP_CID_RECONF;
26762306a36Sopenharmony_ci		num_ext += 1;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (sp->adaptation_ind)
27162306a36Sopenharmony_ci		chunksize += sizeof(aiparam);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (asoc->ep->intl_enable) {
27462306a36Sopenharmony_ci		extensions[num_ext] = SCTP_CID_I_DATA;
27562306a36Sopenharmony_ci		num_ext += 1;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	chunksize += vparam_len;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* Account for AUTH related parameters */
28162306a36Sopenharmony_ci	if (ep->auth_enable) {
28262306a36Sopenharmony_ci		/* Add random parameter length*/
28362306a36Sopenharmony_ci		chunksize += sizeof(asoc->c.auth_random);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		/* Add HMACS parameter length if any were defined */
28662306a36Sopenharmony_ci		auth_hmacs = (struct sctp_paramhdr *)asoc->c.auth_hmacs;
28762306a36Sopenharmony_ci		if (auth_hmacs->length)
28862306a36Sopenharmony_ci			chunksize += SCTP_PAD4(ntohs(auth_hmacs->length));
28962306a36Sopenharmony_ci		else
29062306a36Sopenharmony_ci			auth_hmacs = NULL;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		/* Add CHUNKS parameter length */
29362306a36Sopenharmony_ci		auth_chunks = (struct sctp_paramhdr *)asoc->c.auth_chunks;
29462306a36Sopenharmony_ci		if (auth_chunks->length)
29562306a36Sopenharmony_ci			chunksize += SCTP_PAD4(ntohs(auth_chunks->length));
29662306a36Sopenharmony_ci		else
29762306a36Sopenharmony_ci			auth_chunks = NULL;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		extensions[num_ext] = SCTP_CID_AUTH;
30062306a36Sopenharmony_ci		num_ext += 1;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* If we have any extensions to report, account for that */
30462306a36Sopenharmony_ci	if (num_ext)
30562306a36Sopenharmony_ci		chunksize += SCTP_PAD4(sizeof(ext_param) + num_ext);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* RFC 2960 3.3.2 Initiation (INIT) (1)
30862306a36Sopenharmony_ci	 *
30962306a36Sopenharmony_ci	 * Note 3: An INIT chunk MUST NOT contain more than one Host
31062306a36Sopenharmony_ci	 * Name address parameter. Moreover, the sender of the INIT
31162306a36Sopenharmony_ci	 * MUST NOT combine any other address types with the Host Name
31262306a36Sopenharmony_ci	 * address in the INIT. The receiver of INIT MUST ignore any
31362306a36Sopenharmony_ci	 * other address types if the Host Name address parameter is
31462306a36Sopenharmony_ci	 * present in the received INIT chunk.
31562306a36Sopenharmony_ci	 *
31662306a36Sopenharmony_ci	 * PLEASE DO NOT FIXME [This version does not support Host Name.]
31762306a36Sopenharmony_ci	 */
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize, gfp);
32062306a36Sopenharmony_ci	if (!retval)
32162306a36Sopenharmony_ci		goto nodata;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	retval->subh.init_hdr =
32462306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(init), &init);
32562306a36Sopenharmony_ci	retval->param_hdr.v =
32662306a36Sopenharmony_ci		sctp_addto_chunk(retval, addrs_len, addrs.v);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* RFC 2960 3.3.2 Initiation (INIT) (1)
32962306a36Sopenharmony_ci	 *
33062306a36Sopenharmony_ci	 * Note 4: This parameter, when present, specifies all the
33162306a36Sopenharmony_ci	 * address types the sending endpoint can support. The absence
33262306a36Sopenharmony_ci	 * of this parameter indicates that the sending endpoint can
33362306a36Sopenharmony_ci	 * support any address type.
33462306a36Sopenharmony_ci	 */
33562306a36Sopenharmony_ci	sat.param_hdr.type = SCTP_PARAM_SUPPORTED_ADDRESS_TYPES;
33662306a36Sopenharmony_ci	sat.param_hdr.length = htons(SCTP_SAT_LEN(num_types));
33762306a36Sopenharmony_ci	sctp_addto_chunk(retval, sizeof(sat), &sat);
33862306a36Sopenharmony_ci	sctp_addto_chunk(retval, num_types * sizeof(__u16), &types);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (asoc->ep->ecn_enable)
34162306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* Add the supported extensions parameter.  Be nice and add this
34462306a36Sopenharmony_ci	 * fist before addiding the parameters for the extensions themselves
34562306a36Sopenharmony_ci	 */
34662306a36Sopenharmony_ci	if (num_ext) {
34762306a36Sopenharmony_ci		ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT;
34862306a36Sopenharmony_ci		ext_param.param_hdr.length = htons(sizeof(ext_param) + num_ext);
34962306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(ext_param), &ext_param);
35062306a36Sopenharmony_ci		sctp_addto_param(retval, num_ext, extensions);
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (asoc->ep->prsctp_enable)
35462306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (sp->adaptation_ind) {
35762306a36Sopenharmony_ci		aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
35862306a36Sopenharmony_ci		aiparam.param_hdr.length = htons(sizeof(aiparam));
35962306a36Sopenharmony_ci		aiparam.adaptation_ind = htonl(sp->adaptation_ind);
36062306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* Add SCTP-AUTH chunks to the parameter list */
36462306a36Sopenharmony_ci	if (ep->auth_enable) {
36562306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
36662306a36Sopenharmony_ci				 asoc->c.auth_random);
36762306a36Sopenharmony_ci		if (auth_hmacs)
36862306a36Sopenharmony_ci			sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
36962306a36Sopenharmony_ci					auth_hmacs);
37062306a36Sopenharmony_ci		if (auth_chunks)
37162306a36Sopenharmony_ci			sctp_addto_chunk(retval, ntohs(auth_chunks->length),
37262306a36Sopenharmony_ci					auth_chunks);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_cinodata:
37562306a36Sopenharmony_ci	kfree(addrs.v);
37662306a36Sopenharmony_ci	return retval;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistruct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
38062306a36Sopenharmony_ci				      const struct sctp_chunk *chunk,
38162306a36Sopenharmony_ci				      gfp_t gfp, int unkparam_len)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct sctp_supported_ext_param ext_param;
38462306a36Sopenharmony_ci	struct sctp_adaptation_ind_param aiparam;
38562306a36Sopenharmony_ci	struct sctp_paramhdr *auth_chunks = NULL;
38662306a36Sopenharmony_ci	struct sctp_paramhdr *auth_random = NULL;
38762306a36Sopenharmony_ci	struct sctp_paramhdr *auth_hmacs = NULL;
38862306a36Sopenharmony_ci	struct sctp_chunk *retval = NULL;
38962306a36Sopenharmony_ci	struct sctp_cookie_param *cookie;
39062306a36Sopenharmony_ci	struct sctp_inithdr initack;
39162306a36Sopenharmony_ci	union sctp_params addrs;
39262306a36Sopenharmony_ci	struct sctp_sock *sp;
39362306a36Sopenharmony_ci	__u8 extensions[5];
39462306a36Sopenharmony_ci	size_t chunksize;
39562306a36Sopenharmony_ci	int num_ext = 0;
39662306a36Sopenharmony_ci	int cookie_len;
39762306a36Sopenharmony_ci	int addrs_len;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Note: there may be no addresses to embed. */
40062306a36Sopenharmony_ci	addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	initack.init_tag	        = htonl(asoc->c.my_vtag);
40362306a36Sopenharmony_ci	initack.a_rwnd			= htonl(asoc->rwnd);
40462306a36Sopenharmony_ci	initack.num_outbound_streams	= htons(asoc->c.sinit_num_ostreams);
40562306a36Sopenharmony_ci	initack.num_inbound_streams	= htons(asoc->c.sinit_max_instreams);
40662306a36Sopenharmony_ci	initack.initial_tsn		= htonl(asoc->c.initial_tsn);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* FIXME:  We really ought to build the cookie right
40962306a36Sopenharmony_ci	 * into the packet instead of allocating more fresh memory.
41062306a36Sopenharmony_ci	 */
41162306a36Sopenharmony_ci	cookie = sctp_pack_cookie(asoc->ep, asoc, chunk, &cookie_len,
41262306a36Sopenharmony_ci				  addrs.v, addrs_len);
41362306a36Sopenharmony_ci	if (!cookie)
41462306a36Sopenharmony_ci		goto nomem_cookie;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	/* Calculate the total size of allocation, include the reserved
41762306a36Sopenharmony_ci	 * space for reporting unknown parameters if it is specified.
41862306a36Sopenharmony_ci	 */
41962306a36Sopenharmony_ci	sp = sctp_sk(asoc->base.sk);
42062306a36Sopenharmony_ci	chunksize = sizeof(initack) + addrs_len + cookie_len + unkparam_len;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* Tell peer that we'll do ECN only if peer advertised such cap.  */
42362306a36Sopenharmony_ci	if (asoc->peer.ecn_capable)
42462306a36Sopenharmony_ci		chunksize += sizeof(ecap_param);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (asoc->peer.prsctp_capable)
42762306a36Sopenharmony_ci		chunksize += sizeof(prsctp_param);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (asoc->peer.asconf_capable) {
43062306a36Sopenharmony_ci		extensions[num_ext] = SCTP_CID_ASCONF;
43162306a36Sopenharmony_ci		extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
43262306a36Sopenharmony_ci		num_ext += 2;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (asoc->peer.reconf_capable) {
43662306a36Sopenharmony_ci		extensions[num_ext] = SCTP_CID_RECONF;
43762306a36Sopenharmony_ci		num_ext += 1;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (sp->adaptation_ind)
44162306a36Sopenharmony_ci		chunksize += sizeof(aiparam);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (asoc->peer.intl_capable) {
44462306a36Sopenharmony_ci		extensions[num_ext] = SCTP_CID_I_DATA;
44562306a36Sopenharmony_ci		num_ext += 1;
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (asoc->peer.auth_capable) {
44962306a36Sopenharmony_ci		auth_random = (struct sctp_paramhdr *)asoc->c.auth_random;
45062306a36Sopenharmony_ci		chunksize += ntohs(auth_random->length);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci		auth_hmacs = (struct sctp_paramhdr *)asoc->c.auth_hmacs;
45362306a36Sopenharmony_ci		if (auth_hmacs->length)
45462306a36Sopenharmony_ci			chunksize += SCTP_PAD4(ntohs(auth_hmacs->length));
45562306a36Sopenharmony_ci		else
45662306a36Sopenharmony_ci			auth_hmacs = NULL;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		auth_chunks = (struct sctp_paramhdr *)asoc->c.auth_chunks;
45962306a36Sopenharmony_ci		if (auth_chunks->length)
46062306a36Sopenharmony_ci			chunksize += SCTP_PAD4(ntohs(auth_chunks->length));
46162306a36Sopenharmony_ci		else
46262306a36Sopenharmony_ci			auth_chunks = NULL;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		extensions[num_ext] = SCTP_CID_AUTH;
46562306a36Sopenharmony_ci		num_ext += 1;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (num_ext)
46962306a36Sopenharmony_ci		chunksize += SCTP_PAD4(sizeof(ext_param) + num_ext);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* Now allocate and fill out the chunk.  */
47262306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize, gfp);
47362306a36Sopenharmony_ci	if (!retval)
47462306a36Sopenharmony_ci		goto nomem_chunk;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
47762306a36Sopenharmony_ci	 *
47862306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
47962306a36Sopenharmony_ci	 * HEARTBEAT ACK, * etc.) to the same destination transport
48062306a36Sopenharmony_ci	 * address from which it received the DATA or control chunk
48162306a36Sopenharmony_ci	 * to which it is replying.
48262306a36Sopenharmony_ci	 *
48362306a36Sopenharmony_ci	 * [INIT ACK back to where the INIT came from.]
48462306a36Sopenharmony_ci	 */
48562306a36Sopenharmony_ci	if (chunk->transport)
48662306a36Sopenharmony_ci		retval->transport =
48762306a36Sopenharmony_ci			sctp_assoc_lookup_paddr(asoc,
48862306a36Sopenharmony_ci						&chunk->transport->ipaddr);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	retval->subh.init_hdr =
49162306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(initack), &initack);
49262306a36Sopenharmony_ci	retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v);
49362306a36Sopenharmony_ci	sctp_addto_chunk(retval, cookie_len, cookie);
49462306a36Sopenharmony_ci	if (asoc->peer.ecn_capable)
49562306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
49662306a36Sopenharmony_ci	if (num_ext) {
49762306a36Sopenharmony_ci		ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT;
49862306a36Sopenharmony_ci		ext_param.param_hdr.length = htons(sizeof(ext_param) + num_ext);
49962306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(ext_param), &ext_param);
50062306a36Sopenharmony_ci		sctp_addto_param(retval, num_ext, extensions);
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci	if (asoc->peer.prsctp_capable)
50362306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (sp->adaptation_ind) {
50662306a36Sopenharmony_ci		aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
50762306a36Sopenharmony_ci		aiparam.param_hdr.length = htons(sizeof(aiparam));
50862306a36Sopenharmony_ci		aiparam.adaptation_ind = htonl(sp->adaptation_ind);
50962306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	if (asoc->peer.auth_capable) {
51362306a36Sopenharmony_ci		sctp_addto_chunk(retval, ntohs(auth_random->length),
51462306a36Sopenharmony_ci				 auth_random);
51562306a36Sopenharmony_ci		if (auth_hmacs)
51662306a36Sopenharmony_ci			sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
51762306a36Sopenharmony_ci					auth_hmacs);
51862306a36Sopenharmony_ci		if (auth_chunks)
51962306a36Sopenharmony_ci			sctp_addto_chunk(retval, ntohs(auth_chunks->length),
52062306a36Sopenharmony_ci					auth_chunks);
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* We need to remove the const qualifier at this point.  */
52462306a36Sopenharmony_ci	retval->asoc = (struct sctp_association *) asoc;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cinomem_chunk:
52762306a36Sopenharmony_ci	kfree(cookie);
52862306a36Sopenharmony_cinomem_cookie:
52962306a36Sopenharmony_ci	kfree(addrs.v);
53062306a36Sopenharmony_ci	return retval;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci/* 3.3.11 Cookie Echo (COOKIE ECHO) (10):
53462306a36Sopenharmony_ci *
53562306a36Sopenharmony_ci * This chunk is used only during the initialization of an association.
53662306a36Sopenharmony_ci * It is sent by the initiator of an association to its peer to complete
53762306a36Sopenharmony_ci * the initialization process. This chunk MUST precede any DATA chunk
53862306a36Sopenharmony_ci * sent within the association, but MAY be bundled with one or more DATA
53962306a36Sopenharmony_ci * chunks in the same packet.
54062306a36Sopenharmony_ci *
54162306a36Sopenharmony_ci *      0                   1                   2                   3
54262306a36Sopenharmony_ci *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
54362306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54462306a36Sopenharmony_ci *     |   Type = 10   |Chunk  Flags   |         Length                |
54562306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54662306a36Sopenharmony_ci *     /                     Cookie                                    /
54762306a36Sopenharmony_ci *     \                                                               \
54862306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54962306a36Sopenharmony_ci *
55062306a36Sopenharmony_ci * Chunk Flags: 8 bit
55162306a36Sopenharmony_ci *
55262306a36Sopenharmony_ci *   Set to zero on transmit and ignored on receipt.
55362306a36Sopenharmony_ci *
55462306a36Sopenharmony_ci * Length: 16 bits (unsigned integer)
55562306a36Sopenharmony_ci *
55662306a36Sopenharmony_ci *   Set to the size of the chunk in bytes, including the 4 bytes of
55762306a36Sopenharmony_ci *   the chunk header and the size of the Cookie.
55862306a36Sopenharmony_ci *
55962306a36Sopenharmony_ci * Cookie: variable size
56062306a36Sopenharmony_ci *
56162306a36Sopenharmony_ci *   This field must contain the exact cookie received in the
56262306a36Sopenharmony_ci *   State Cookie parameter from the previous INIT ACK.
56362306a36Sopenharmony_ci *
56462306a36Sopenharmony_ci *   An implementation SHOULD make the cookie as small as possible
56562306a36Sopenharmony_ci *   to insure interoperability.
56662306a36Sopenharmony_ci */
56762306a36Sopenharmony_cistruct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc,
56862306a36Sopenharmony_ci					 const struct sctp_chunk *chunk)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct sctp_chunk *retval;
57162306a36Sopenharmony_ci	int cookie_len;
57262306a36Sopenharmony_ci	void *cookie;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	cookie = asoc->peer.cookie;
57562306a36Sopenharmony_ci	cookie_len = asoc->peer.cookie_len;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	/* Build a cookie echo chunk.  */
57862306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0,
57962306a36Sopenharmony_ci				   cookie_len, GFP_ATOMIC);
58062306a36Sopenharmony_ci	if (!retval)
58162306a36Sopenharmony_ci		goto nodata;
58262306a36Sopenharmony_ci	retval->subh.cookie_hdr =
58362306a36Sopenharmony_ci		sctp_addto_chunk(retval, cookie_len, cookie);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
58662306a36Sopenharmony_ci	 *
58762306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
58862306a36Sopenharmony_ci	 * HEARTBEAT ACK, * etc.) to the same destination transport
58962306a36Sopenharmony_ci	 * address from which it * received the DATA or control chunk
59062306a36Sopenharmony_ci	 * to which it is replying.
59162306a36Sopenharmony_ci	 *
59262306a36Sopenharmony_ci	 * [COOKIE ECHO back to where the INIT ACK came from.]
59362306a36Sopenharmony_ci	 */
59462306a36Sopenharmony_ci	if (chunk)
59562306a36Sopenharmony_ci		retval->transport = chunk->transport;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cinodata:
59862306a36Sopenharmony_ci	return retval;
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci/* 3.3.12 Cookie Acknowledgement (COOKIE ACK) (11):
60262306a36Sopenharmony_ci *
60362306a36Sopenharmony_ci * This chunk is used only during the initialization of an
60462306a36Sopenharmony_ci * association.  It is used to acknowledge the receipt of a COOKIE
60562306a36Sopenharmony_ci * ECHO chunk.  This chunk MUST precede any DATA or SACK chunk sent
60662306a36Sopenharmony_ci * within the association, but MAY be bundled with one or more DATA
60762306a36Sopenharmony_ci * chunks or SACK chunk in the same SCTP packet.
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci *      0                   1                   2                   3
61062306a36Sopenharmony_ci *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
61162306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61262306a36Sopenharmony_ci *     |   Type = 11   |Chunk  Flags   |     Length = 4                |
61362306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61462306a36Sopenharmony_ci *
61562306a36Sopenharmony_ci * Chunk Flags: 8 bits
61662306a36Sopenharmony_ci *
61762306a36Sopenharmony_ci *   Set to zero on transmit and ignored on receipt.
61862306a36Sopenharmony_ci */
61962306a36Sopenharmony_cistruct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc,
62062306a36Sopenharmony_ci					const struct sctp_chunk *chunk)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	struct sctp_chunk *retval;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0, GFP_ATOMIC);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
62762306a36Sopenharmony_ci	 *
62862306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
62962306a36Sopenharmony_ci	 * HEARTBEAT ACK, * etc.) to the same destination transport
63062306a36Sopenharmony_ci	 * address from which it * received the DATA or control chunk
63162306a36Sopenharmony_ci	 * to which it is replying.
63262306a36Sopenharmony_ci	 *
63362306a36Sopenharmony_ci	 * [COOKIE ACK back to where the COOKIE ECHO came from.]
63462306a36Sopenharmony_ci	 */
63562306a36Sopenharmony_ci	if (retval && chunk && chunk->transport)
63662306a36Sopenharmony_ci		retval->transport =
63762306a36Sopenharmony_ci			sctp_assoc_lookup_paddr(asoc,
63862306a36Sopenharmony_ci						&chunk->transport->ipaddr);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	return retval;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/*
64462306a36Sopenharmony_ci *  Appendix A: Explicit Congestion Notification:
64562306a36Sopenharmony_ci *  CWR:
64662306a36Sopenharmony_ci *
64762306a36Sopenharmony_ci *  RFC 2481 details a specific bit for a sender to send in the header of
64862306a36Sopenharmony_ci *  its next outbound TCP segment to indicate to its peer that it has
64962306a36Sopenharmony_ci *  reduced its congestion window.  This is termed the CWR bit.  For
65062306a36Sopenharmony_ci *  SCTP the same indication is made by including the CWR chunk.
65162306a36Sopenharmony_ci *  This chunk contains one data element, i.e. the TSN number that
65262306a36Sopenharmony_ci *  was sent in the ECNE chunk.  This element represents the lowest
65362306a36Sopenharmony_ci *  TSN number in the datagram that was originally marked with the
65462306a36Sopenharmony_ci *  CE bit.
65562306a36Sopenharmony_ci *
65662306a36Sopenharmony_ci *     0                   1                   2                   3
65762306a36Sopenharmony_ci *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
65862306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65962306a36Sopenharmony_ci *    | Chunk Type=13 | Flags=00000000|    Chunk Length = 8           |
66062306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66162306a36Sopenharmony_ci *    |                      Lowest TSN Number                        |
66262306a36Sopenharmony_ci *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66362306a36Sopenharmony_ci *
66462306a36Sopenharmony_ci *     Note: The CWR is considered a Control chunk.
66562306a36Sopenharmony_ci */
66662306a36Sopenharmony_cistruct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc,
66762306a36Sopenharmony_ci				 const __u32 lowest_tsn,
66862306a36Sopenharmony_ci				 const struct sctp_chunk *chunk)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	struct sctp_chunk *retval;
67162306a36Sopenharmony_ci	struct sctp_cwrhdr cwr;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	cwr.lowest_tsn = htonl(lowest_tsn);
67462306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0,
67562306a36Sopenharmony_ci				   sizeof(cwr), GFP_ATOMIC);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (!retval)
67862306a36Sopenharmony_ci		goto nodata;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	retval->subh.ecn_cwr_hdr =
68162306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(cwr), &cwr);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
68462306a36Sopenharmony_ci	 *
68562306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
68662306a36Sopenharmony_ci	 * HEARTBEAT ACK, * etc.) to the same destination transport
68762306a36Sopenharmony_ci	 * address from which it * received the DATA or control chunk
68862306a36Sopenharmony_ci	 * to which it is replying.
68962306a36Sopenharmony_ci	 *
69062306a36Sopenharmony_ci	 * [Report a reduced congestion window back to where the ECNE
69162306a36Sopenharmony_ci	 * came from.]
69262306a36Sopenharmony_ci	 */
69362306a36Sopenharmony_ci	if (chunk)
69462306a36Sopenharmony_ci		retval->transport = chunk->transport;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cinodata:
69762306a36Sopenharmony_ci	return retval;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci/* Make an ECNE chunk.  This is a congestion experienced report.  */
70162306a36Sopenharmony_cistruct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc,
70262306a36Sopenharmony_ci				  const __u32 lowest_tsn)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct sctp_chunk *retval;
70562306a36Sopenharmony_ci	struct sctp_ecnehdr ecne;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	ecne.lowest_tsn = htonl(lowest_tsn);
70862306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0,
70962306a36Sopenharmony_ci				   sizeof(ecne), GFP_ATOMIC);
71062306a36Sopenharmony_ci	if (!retval)
71162306a36Sopenharmony_ci		goto nodata;
71262306a36Sopenharmony_ci	retval->subh.ecne_hdr =
71362306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(ecne), &ecne);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cinodata:
71662306a36Sopenharmony_ci	return retval;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci/* Make a DATA chunk for the given association from the provided
72062306a36Sopenharmony_ci * parameters.  However, do not populate the data payload.
72162306a36Sopenharmony_ci */
72262306a36Sopenharmony_cistruct sctp_chunk *sctp_make_datafrag_empty(const struct sctp_association *asoc,
72362306a36Sopenharmony_ci					    const struct sctp_sndrcvinfo *sinfo,
72462306a36Sopenharmony_ci					    int len, __u8 flags, gfp_t gfp)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	struct sctp_chunk *retval;
72762306a36Sopenharmony_ci	struct sctp_datahdr dp;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	/* We assign the TSN as LATE as possible, not here when
73062306a36Sopenharmony_ci	 * creating the chunk.
73162306a36Sopenharmony_ci	 */
73262306a36Sopenharmony_ci	memset(&dp, 0, sizeof(dp));
73362306a36Sopenharmony_ci	dp.ppid = sinfo->sinfo_ppid;
73462306a36Sopenharmony_ci	dp.stream = htons(sinfo->sinfo_stream);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	/* Set the flags for an unordered send.  */
73762306a36Sopenharmony_ci	if (sinfo->sinfo_flags & SCTP_UNORDERED)
73862306a36Sopenharmony_ci		flags |= SCTP_DATA_UNORDERED;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	retval = sctp_make_data(asoc, flags, sizeof(dp) + len, gfp);
74162306a36Sopenharmony_ci	if (!retval)
74262306a36Sopenharmony_ci		return NULL;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp);
74562306a36Sopenharmony_ci	memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo));
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return retval;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci/* Create a selective ackowledgement (SACK) for the given
75162306a36Sopenharmony_ci * association.  This reports on which TSN's we've seen to date,
75262306a36Sopenharmony_ci * including duplicates and gaps.
75362306a36Sopenharmony_ci */
75462306a36Sopenharmony_cistruct sctp_chunk *sctp_make_sack(struct sctp_association *asoc)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
75762306a36Sopenharmony_ci	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
75862306a36Sopenharmony_ci	__u16 num_gabs, num_dup_tsns;
75962306a36Sopenharmony_ci	struct sctp_transport *trans;
76062306a36Sopenharmony_ci	struct sctp_chunk *retval;
76162306a36Sopenharmony_ci	struct sctp_sackhdr sack;
76262306a36Sopenharmony_ci	__u32 ctsn;
76362306a36Sopenharmony_ci	int len;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	memset(gabs, 0, sizeof(gabs));
76662306a36Sopenharmony_ci	ctsn = sctp_tsnmap_get_ctsn(map);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	pr_debug("%s: sackCTSNAck sent:0x%x\n", __func__, ctsn);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	/* How much room is needed in the chunk? */
77162306a36Sopenharmony_ci	num_gabs = sctp_tsnmap_num_gabs(map, gabs);
77262306a36Sopenharmony_ci	num_dup_tsns = sctp_tsnmap_num_dups(map);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/* Initialize the SACK header.  */
77562306a36Sopenharmony_ci	sack.cum_tsn_ack	    = htonl(ctsn);
77662306a36Sopenharmony_ci	sack.a_rwnd 		    = htonl(asoc->a_rwnd);
77762306a36Sopenharmony_ci	sack.num_gap_ack_blocks     = htons(num_gabs);
77862306a36Sopenharmony_ci	sack.num_dup_tsns           = htons(num_dup_tsns);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	len = sizeof(sack)
78162306a36Sopenharmony_ci		+ sizeof(struct sctp_gap_ack_block) * num_gabs
78262306a36Sopenharmony_ci		+ sizeof(__u32) * num_dup_tsns;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	/* Create the chunk.  */
78562306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len, GFP_ATOMIC);
78662306a36Sopenharmony_ci	if (!retval)
78762306a36Sopenharmony_ci		goto nodata;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
79062306a36Sopenharmony_ci	 *
79162306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
79262306a36Sopenharmony_ci	 * HEARTBEAT ACK, etc.) to the same destination transport
79362306a36Sopenharmony_ci	 * address from which it received the DATA or control chunk to
79462306a36Sopenharmony_ci	 * which it is replying.  This rule should also be followed if
79562306a36Sopenharmony_ci	 * the endpoint is bundling DATA chunks together with the
79662306a36Sopenharmony_ci	 * reply chunk.
79762306a36Sopenharmony_ci	 *
79862306a36Sopenharmony_ci	 * However, when acknowledging multiple DATA chunks received
79962306a36Sopenharmony_ci	 * in packets from different source addresses in a single
80062306a36Sopenharmony_ci	 * SACK, the SACK chunk may be transmitted to one of the
80162306a36Sopenharmony_ci	 * destination transport addresses from which the DATA or
80262306a36Sopenharmony_ci	 * control chunks being acknowledged were received.
80362306a36Sopenharmony_ci	 *
80462306a36Sopenharmony_ci	 * [BUG:  We do not implement the following paragraph.
80562306a36Sopenharmony_ci	 * Perhaps we should remember the last transport we used for a
80662306a36Sopenharmony_ci	 * SACK and avoid that (if possible) if we have seen any
80762306a36Sopenharmony_ci	 * duplicates. --piggy]
80862306a36Sopenharmony_ci	 *
80962306a36Sopenharmony_ci	 * When a receiver of a duplicate DATA chunk sends a SACK to a
81062306a36Sopenharmony_ci	 * multi- homed endpoint it MAY be beneficial to vary the
81162306a36Sopenharmony_ci	 * destination address and not use the source address of the
81262306a36Sopenharmony_ci	 * DATA chunk.  The reason being that receiving a duplicate
81362306a36Sopenharmony_ci	 * from a multi-homed endpoint might indicate that the return
81462306a36Sopenharmony_ci	 * path (as specified in the source address of the DATA chunk)
81562306a36Sopenharmony_ci	 * for the SACK is broken.
81662306a36Sopenharmony_ci	 *
81762306a36Sopenharmony_ci	 * [Send to the address from which we last received a DATA chunk.]
81862306a36Sopenharmony_ci	 */
81962306a36Sopenharmony_ci	retval->transport = asoc->peer.last_data_from;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	retval->subh.sack_hdr =
82262306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(sack), &sack);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	/* Add the gap ack block information.   */
82562306a36Sopenharmony_ci	if (num_gabs)
82662306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(__u32) * num_gabs,
82762306a36Sopenharmony_ci				 gabs);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/* Add the duplicate TSN information.  */
83062306a36Sopenharmony_ci	if (num_dup_tsns) {
83162306a36Sopenharmony_ci		asoc->stats.idupchunks += num_dup_tsns;
83262306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
83362306a36Sopenharmony_ci				 sctp_tsnmap_get_dups(map));
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci	/* Once we have a sack generated, check to see what our sack
83662306a36Sopenharmony_ci	 * generation is, if its 0, reset the transports to 0, and reset
83762306a36Sopenharmony_ci	 * the association generation to 1
83862306a36Sopenharmony_ci	 *
83962306a36Sopenharmony_ci	 * The idea is that zero is never used as a valid generation for the
84062306a36Sopenharmony_ci	 * association so no transport will match after a wrap event like this,
84162306a36Sopenharmony_ci	 * Until the next sack
84262306a36Sopenharmony_ci	 */
84362306a36Sopenharmony_ci	if (++asoc->peer.sack_generation == 0) {
84462306a36Sopenharmony_ci		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
84562306a36Sopenharmony_ci				    transports)
84662306a36Sopenharmony_ci			trans->sack_generation = 0;
84762306a36Sopenharmony_ci		asoc->peer.sack_generation = 1;
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_cinodata:
85062306a36Sopenharmony_ci	return retval;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci/* Make a SHUTDOWN chunk. */
85462306a36Sopenharmony_cistruct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc,
85562306a36Sopenharmony_ci				      const struct sctp_chunk *chunk)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	struct sctp_shutdownhdr shut;
85862306a36Sopenharmony_ci	struct sctp_chunk *retval;
85962306a36Sopenharmony_ci	__u32 ctsn;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
86262306a36Sopenharmony_ci	shut.cum_tsn_ack = htonl(ctsn);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0,
86562306a36Sopenharmony_ci				   sizeof(shut), GFP_ATOMIC);
86662306a36Sopenharmony_ci	if (!retval)
86762306a36Sopenharmony_ci		goto nodata;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	retval->subh.shutdown_hdr =
87062306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(shut), &shut);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	if (chunk)
87362306a36Sopenharmony_ci		retval->transport = chunk->transport;
87462306a36Sopenharmony_cinodata:
87562306a36Sopenharmony_ci	return retval;
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistruct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
87962306a36Sopenharmony_ci					  const struct sctp_chunk *chunk)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	struct sctp_chunk *retval;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0,
88462306a36Sopenharmony_ci				   GFP_ATOMIC);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
88762306a36Sopenharmony_ci	 *
88862306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
88962306a36Sopenharmony_ci	 * HEARTBEAT ACK, * etc.) to the same destination transport
89062306a36Sopenharmony_ci	 * address from which it * received the DATA or control chunk
89162306a36Sopenharmony_ci	 * to which it is replying.
89262306a36Sopenharmony_ci	 *
89362306a36Sopenharmony_ci	 * [ACK back to where the SHUTDOWN came from.]
89462306a36Sopenharmony_ci	 */
89562306a36Sopenharmony_ci	if (retval && chunk)
89662306a36Sopenharmony_ci		retval->transport = chunk->transport;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	return retval;
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cistruct sctp_chunk *sctp_make_shutdown_complete(
90262306a36Sopenharmony_ci					const struct sctp_association *asoc,
90362306a36Sopenharmony_ci					const struct sctp_chunk *chunk)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	struct sctp_chunk *retval;
90662306a36Sopenharmony_ci	__u8 flags = 0;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/* Set the T-bit if we have no association (vtag will be
90962306a36Sopenharmony_ci	 * reflected)
91062306a36Sopenharmony_ci	 */
91162306a36Sopenharmony_ci	flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags,
91462306a36Sopenharmony_ci				   0, GFP_ATOMIC);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
91762306a36Sopenharmony_ci	 *
91862306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
91962306a36Sopenharmony_ci	 * HEARTBEAT ACK, * etc.) to the same destination transport
92062306a36Sopenharmony_ci	 * address from which it * received the DATA or control chunk
92162306a36Sopenharmony_ci	 * to which it is replying.
92262306a36Sopenharmony_ci	 *
92362306a36Sopenharmony_ci	 * [Report SHUTDOWN COMPLETE back to where the SHUTDOWN ACK
92462306a36Sopenharmony_ci	 * came from.]
92562306a36Sopenharmony_ci	 */
92662306a36Sopenharmony_ci	if (retval && chunk)
92762306a36Sopenharmony_ci		retval->transport = chunk->transport;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	return retval;
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci/* Create an ABORT.  Note that we set the T bit if we have no
93362306a36Sopenharmony_ci * association, except when responding to an INIT (sctpimpguide 2.41).
93462306a36Sopenharmony_ci */
93562306a36Sopenharmony_cistruct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
93662306a36Sopenharmony_ci				   const struct sctp_chunk *chunk,
93762306a36Sopenharmony_ci				   const size_t hint)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	struct sctp_chunk *retval;
94062306a36Sopenharmony_ci	__u8 flags = 0;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	/* Set the T-bit if we have no association and 'chunk' is not
94362306a36Sopenharmony_ci	 * an INIT (vtag will be reflected).
94462306a36Sopenharmony_ci	 */
94562306a36Sopenharmony_ci	if (!asoc) {
94662306a36Sopenharmony_ci		if (chunk && chunk->chunk_hdr &&
94762306a36Sopenharmony_ci		    chunk->chunk_hdr->type == SCTP_CID_INIT)
94862306a36Sopenharmony_ci			flags = 0;
94962306a36Sopenharmony_ci		else
95062306a36Sopenharmony_ci			flags = SCTP_CHUNK_FLAG_T;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint,
95462306a36Sopenharmony_ci				   GFP_ATOMIC);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
95762306a36Sopenharmony_ci	 *
95862306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
95962306a36Sopenharmony_ci	 * HEARTBEAT ACK, * etc.) to the same destination transport
96062306a36Sopenharmony_ci	 * address from which it * received the DATA or control chunk
96162306a36Sopenharmony_ci	 * to which it is replying.
96262306a36Sopenharmony_ci	 *
96362306a36Sopenharmony_ci	 * [ABORT back to where the offender came from.]
96462306a36Sopenharmony_ci	 */
96562306a36Sopenharmony_ci	if (retval && chunk)
96662306a36Sopenharmony_ci		retval->transport = chunk->transport;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	return retval;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci/* Helper to create ABORT with a NO_USER_DATA error.  */
97262306a36Sopenharmony_cistruct sctp_chunk *sctp_make_abort_no_data(
97362306a36Sopenharmony_ci					const struct sctp_association *asoc,
97462306a36Sopenharmony_ci					const struct sctp_chunk *chunk,
97562306a36Sopenharmony_ci					__u32 tsn)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	struct sctp_chunk *retval;
97862306a36Sopenharmony_ci	__be32 payload;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	retval = sctp_make_abort(asoc, chunk,
98162306a36Sopenharmony_ci				 sizeof(struct sctp_errhdr) + sizeof(tsn));
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	if (!retval)
98462306a36Sopenharmony_ci		goto no_mem;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	/* Put the tsn back into network byte order.  */
98762306a36Sopenharmony_ci	payload = htonl(tsn);
98862306a36Sopenharmony_ci	sctp_init_cause(retval, SCTP_ERROR_NO_DATA, sizeof(payload));
98962306a36Sopenharmony_ci	sctp_addto_chunk(retval, sizeof(payload), (const void *)&payload);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
99262306a36Sopenharmony_ci	 *
99362306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
99462306a36Sopenharmony_ci	 * HEARTBEAT ACK, * etc.) to the same destination transport
99562306a36Sopenharmony_ci	 * address from which it * received the DATA or control chunk
99662306a36Sopenharmony_ci	 * to which it is replying.
99762306a36Sopenharmony_ci	 *
99862306a36Sopenharmony_ci	 * [ABORT back to where the offender came from.]
99962306a36Sopenharmony_ci	 */
100062306a36Sopenharmony_ci	if (chunk)
100162306a36Sopenharmony_ci		retval->transport = chunk->transport;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cino_mem:
100462306a36Sopenharmony_ci	return retval;
100562306a36Sopenharmony_ci}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci/* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error.  */
100862306a36Sopenharmony_cistruct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc,
100962306a36Sopenharmony_ci					struct msghdr *msg,
101062306a36Sopenharmony_ci					size_t paylen)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	struct sctp_chunk *retval;
101362306a36Sopenharmony_ci	void *payload = NULL;
101462306a36Sopenharmony_ci	int err;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	retval = sctp_make_abort(asoc, NULL,
101762306a36Sopenharmony_ci				 sizeof(struct sctp_errhdr) + paylen);
101862306a36Sopenharmony_ci	if (!retval)
101962306a36Sopenharmony_ci		goto err_chunk;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	if (paylen) {
102262306a36Sopenharmony_ci		/* Put the msg_iov together into payload.  */
102362306a36Sopenharmony_ci		payload = kmalloc(paylen, GFP_KERNEL);
102462306a36Sopenharmony_ci		if (!payload)
102562306a36Sopenharmony_ci			goto err_payload;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci		err = memcpy_from_msg(payload, msg, paylen);
102862306a36Sopenharmony_ci		if (err < 0)
102962306a36Sopenharmony_ci			goto err_copy;
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, paylen);
103362306a36Sopenharmony_ci	sctp_addto_chunk(retval, paylen, payload);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	if (paylen)
103662306a36Sopenharmony_ci		kfree(payload);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	return retval;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cierr_copy:
104162306a36Sopenharmony_ci	kfree(payload);
104262306a36Sopenharmony_cierr_payload:
104362306a36Sopenharmony_ci	sctp_chunk_free(retval);
104462306a36Sopenharmony_ci	retval = NULL;
104562306a36Sopenharmony_cierr_chunk:
104662306a36Sopenharmony_ci	return retval;
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci/* Append bytes to the end of a parameter.  Will panic if chunk is not big
105062306a36Sopenharmony_ci * enough.
105162306a36Sopenharmony_ci */
105262306a36Sopenharmony_cistatic void *sctp_addto_param(struct sctp_chunk *chunk, int len,
105362306a36Sopenharmony_ci			      const void *data)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	int chunklen = ntohs(chunk->chunk_hdr->length);
105662306a36Sopenharmony_ci	void *target;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	target = skb_put(chunk->skb, len);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	if (data)
106162306a36Sopenharmony_ci		memcpy(target, data, len);
106262306a36Sopenharmony_ci	else
106362306a36Sopenharmony_ci		memset(target, 0, len);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	/* Adjust the chunk length field.  */
106662306a36Sopenharmony_ci	chunk->chunk_hdr->length = htons(chunklen + len);
106762306a36Sopenharmony_ci	chunk->chunk_end = skb_tail_pointer(chunk->skb);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	return target;
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci/* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */
107362306a36Sopenharmony_cistruct sctp_chunk *sctp_make_abort_violation(
107462306a36Sopenharmony_ci					const struct sctp_association *asoc,
107562306a36Sopenharmony_ci					const struct sctp_chunk *chunk,
107662306a36Sopenharmony_ci					const __u8 *payload,
107762306a36Sopenharmony_ci					const size_t paylen)
107862306a36Sopenharmony_ci{
107962306a36Sopenharmony_ci	struct sctp_chunk  *retval;
108062306a36Sopenharmony_ci	struct sctp_paramhdr phdr;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	retval = sctp_make_abort(asoc, chunk, sizeof(struct sctp_errhdr) +
108362306a36Sopenharmony_ci					      paylen + sizeof(phdr));
108462306a36Sopenharmony_ci	if (!retval)
108562306a36Sopenharmony_ci		goto end;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen +
108862306a36Sopenharmony_ci							    sizeof(phdr));
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	phdr.type = htons(chunk->chunk_hdr->type);
109162306a36Sopenharmony_ci	phdr.length = chunk->chunk_hdr->length;
109262306a36Sopenharmony_ci	sctp_addto_chunk(retval, paylen, payload);
109362306a36Sopenharmony_ci	sctp_addto_param(retval, sizeof(phdr), &phdr);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ciend:
109662306a36Sopenharmony_ci	return retval;
109762306a36Sopenharmony_ci}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistruct sctp_chunk *sctp_make_violation_paramlen(
110062306a36Sopenharmony_ci					const struct sctp_association *asoc,
110162306a36Sopenharmony_ci					const struct sctp_chunk *chunk,
110262306a36Sopenharmony_ci					struct sctp_paramhdr *param)
110362306a36Sopenharmony_ci{
110462306a36Sopenharmony_ci	static const char error[] = "The following parameter had invalid length:";
110562306a36Sopenharmony_ci	size_t payload_len = sizeof(error) + sizeof(struct sctp_errhdr) +
110662306a36Sopenharmony_ci			     sizeof(*param);
110762306a36Sopenharmony_ci	struct sctp_chunk *retval;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	retval = sctp_make_abort(asoc, chunk, payload_len);
111062306a36Sopenharmony_ci	if (!retval)
111162306a36Sopenharmony_ci		goto nodata;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION,
111462306a36Sopenharmony_ci			sizeof(error) + sizeof(*param));
111562306a36Sopenharmony_ci	sctp_addto_chunk(retval, sizeof(error), error);
111662306a36Sopenharmony_ci	sctp_addto_param(retval, sizeof(*param), param);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cinodata:
111962306a36Sopenharmony_ci	return retval;
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_cistruct sctp_chunk *sctp_make_violation_max_retrans(
112362306a36Sopenharmony_ci					const struct sctp_association *asoc,
112462306a36Sopenharmony_ci					const struct sctp_chunk *chunk)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	static const char error[] = "Association exceeded its max_retrans count";
112762306a36Sopenharmony_ci	size_t payload_len = sizeof(error) + sizeof(struct sctp_errhdr);
112862306a36Sopenharmony_ci	struct sctp_chunk *retval;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	retval = sctp_make_abort(asoc, chunk, payload_len);
113162306a36Sopenharmony_ci	if (!retval)
113262306a36Sopenharmony_ci		goto nodata;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, sizeof(error));
113562306a36Sopenharmony_ci	sctp_addto_chunk(retval, sizeof(error), error);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_cinodata:
113862306a36Sopenharmony_ci	return retval;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistruct sctp_chunk *sctp_make_new_encap_port(const struct sctp_association *asoc,
114262306a36Sopenharmony_ci					    const struct sctp_chunk *chunk)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct sctp_new_encap_port_hdr nep;
114562306a36Sopenharmony_ci	struct sctp_chunk *retval;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	retval = sctp_make_abort(asoc, chunk,
114862306a36Sopenharmony_ci				 sizeof(struct sctp_errhdr) + sizeof(nep));
114962306a36Sopenharmony_ci	if (!retval)
115062306a36Sopenharmony_ci		goto nodata;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	sctp_init_cause(retval, SCTP_ERROR_NEW_ENCAP_PORT, sizeof(nep));
115362306a36Sopenharmony_ci	nep.cur_port = SCTP_INPUT_CB(chunk->skb)->encap_port;
115462306a36Sopenharmony_ci	nep.new_port = chunk->transport->encap_port;
115562306a36Sopenharmony_ci	sctp_addto_chunk(retval, sizeof(nep), &nep);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cinodata:
115862306a36Sopenharmony_ci	return retval;
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci/* Make a HEARTBEAT chunk.  */
116262306a36Sopenharmony_cistruct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
116362306a36Sopenharmony_ci				       const struct sctp_transport *transport,
116462306a36Sopenharmony_ci				       __u32 probe_size)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	struct sctp_sender_hb_info hbinfo = {};
116762306a36Sopenharmony_ci	struct sctp_chunk *retval;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0,
117062306a36Sopenharmony_ci				   sizeof(hbinfo), GFP_ATOMIC);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	if (!retval)
117362306a36Sopenharmony_ci		goto nodata;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;
117662306a36Sopenharmony_ci	hbinfo.param_hdr.length = htons(sizeof(hbinfo));
117762306a36Sopenharmony_ci	hbinfo.daddr = transport->ipaddr;
117862306a36Sopenharmony_ci	hbinfo.sent_at = jiffies;
117962306a36Sopenharmony_ci	hbinfo.hb_nonce = transport->hb_nonce;
118062306a36Sopenharmony_ci	hbinfo.probe_size = probe_size;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/* Cast away the 'const', as this is just telling the chunk
118362306a36Sopenharmony_ci	 * what transport it belongs to.
118462306a36Sopenharmony_ci	 */
118562306a36Sopenharmony_ci	retval->transport = (struct sctp_transport *) transport;
118662306a36Sopenharmony_ci	retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo),
118762306a36Sopenharmony_ci						&hbinfo);
118862306a36Sopenharmony_ci	retval->pmtu_probe = !!probe_size;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cinodata:
119162306a36Sopenharmony_ci	return retval;
119262306a36Sopenharmony_ci}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_cistruct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
119562306a36Sopenharmony_ci					   const struct sctp_chunk *chunk,
119662306a36Sopenharmony_ci					   const void *payload,
119762306a36Sopenharmony_ci					   const size_t paylen)
119862306a36Sopenharmony_ci{
119962306a36Sopenharmony_ci	struct sctp_chunk *retval;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	retval  = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen,
120262306a36Sopenharmony_ci				    GFP_ATOMIC);
120362306a36Sopenharmony_ci	if (!retval)
120462306a36Sopenharmony_ci		goto nodata;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
120962306a36Sopenharmony_ci	 *
121062306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
121162306a36Sopenharmony_ci	 * HEARTBEAT ACK, * etc.) to the same destination transport
121262306a36Sopenharmony_ci	 * address from which it * received the DATA or control chunk
121362306a36Sopenharmony_ci	 * to which it is replying.
121462306a36Sopenharmony_ci	 *
121562306a36Sopenharmony_ci	 * [HBACK back to where the HEARTBEAT came from.]
121662306a36Sopenharmony_ci	 */
121762306a36Sopenharmony_ci	if (chunk)
121862306a36Sopenharmony_ci		retval->transport = chunk->transport;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_cinodata:
122162306a36Sopenharmony_ci	return retval;
122262306a36Sopenharmony_ci}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci/* RFC4820 3. Padding Chunk (PAD)
122562306a36Sopenharmony_ci *  0                   1                   2                   3
122662306a36Sopenharmony_ci *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
122762306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122862306a36Sopenharmony_ci * | Type = 0x84   |   Flags=0     |             Length            |
122962306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
123062306a36Sopenharmony_ci * |                                                               |
123162306a36Sopenharmony_ci * \                         Padding Data                          /
123262306a36Sopenharmony_ci * /                                                               \
123362306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
123462306a36Sopenharmony_ci */
123562306a36Sopenharmony_cistruct sctp_chunk *sctp_make_pad(const struct sctp_association *asoc, int len)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct sctp_chunk *retval;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_PAD, 0, len, GFP_ATOMIC);
124062306a36Sopenharmony_ci	if (!retval)
124162306a36Sopenharmony_ci		return NULL;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	skb_put_zero(retval->skb, len);
124462306a36Sopenharmony_ci	retval->chunk_hdr->length = htons(ntohs(retval->chunk_hdr->length) + len);
124562306a36Sopenharmony_ci	retval->chunk_end = skb_tail_pointer(retval->skb);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	return retval;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci/* Create an Operation Error chunk with the specified space reserved.
125162306a36Sopenharmony_ci * This routine can be used for containing multiple causes in the chunk.
125262306a36Sopenharmony_ci */
125362306a36Sopenharmony_cistatic struct sctp_chunk *sctp_make_op_error_space(
125462306a36Sopenharmony_ci					const struct sctp_association *asoc,
125562306a36Sopenharmony_ci					const struct sctp_chunk *chunk,
125662306a36Sopenharmony_ci					size_t size)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	struct sctp_chunk *retval;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0,
126162306a36Sopenharmony_ci				   sizeof(struct sctp_errhdr) + size,
126262306a36Sopenharmony_ci				   GFP_ATOMIC);
126362306a36Sopenharmony_ci	if (!retval)
126462306a36Sopenharmony_ci		goto nodata;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
126762306a36Sopenharmony_ci	 *
126862306a36Sopenharmony_ci	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
126962306a36Sopenharmony_ci	 * HEARTBEAT ACK, etc.) to the same destination transport
127062306a36Sopenharmony_ci	 * address from which it received the DATA or control chunk
127162306a36Sopenharmony_ci	 * to which it is replying.
127262306a36Sopenharmony_ci	 *
127362306a36Sopenharmony_ci	 */
127462306a36Sopenharmony_ci	if (chunk)
127562306a36Sopenharmony_ci		retval->transport = chunk->transport;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cinodata:
127862306a36Sopenharmony_ci	return retval;
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci/* Create an Operation Error chunk of a fixed size, specifically,
128262306a36Sopenharmony_ci * min(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT) - overheads.
128362306a36Sopenharmony_ci * This is a helper function to allocate an error chunk for those
128462306a36Sopenharmony_ci * invalid parameter codes in which we may not want to report all the
128562306a36Sopenharmony_ci * errors, if the incoming chunk is large. If it can't fit in a single
128662306a36Sopenharmony_ci * packet, we ignore it.
128762306a36Sopenharmony_ci */
128862306a36Sopenharmony_cistatic inline struct sctp_chunk *sctp_make_op_error_limited(
128962306a36Sopenharmony_ci					const struct sctp_association *asoc,
129062306a36Sopenharmony_ci					const struct sctp_chunk *chunk)
129162306a36Sopenharmony_ci{
129262306a36Sopenharmony_ci	size_t size = SCTP_DEFAULT_MAXSEGMENT;
129362306a36Sopenharmony_ci	struct sctp_sock *sp = NULL;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	if (asoc) {
129662306a36Sopenharmony_ci		size = min_t(size_t, size, asoc->pathmtu);
129762306a36Sopenharmony_ci		sp = sctp_sk(asoc->base.sk);
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	size = sctp_mtu_payload(sp, size, sizeof(struct sctp_errhdr));
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	return sctp_make_op_error_space(asoc, chunk, size);
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci/* Create an Operation Error chunk.  */
130662306a36Sopenharmony_cistruct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
130762306a36Sopenharmony_ci				      const struct sctp_chunk *chunk,
130862306a36Sopenharmony_ci				      __be16 cause_code, const void *payload,
130962306a36Sopenharmony_ci				      size_t paylen, size_t reserve_tail)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	struct sctp_chunk *retval;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	retval = sctp_make_op_error_space(asoc, chunk, paylen + reserve_tail);
131462306a36Sopenharmony_ci	if (!retval)
131562306a36Sopenharmony_ci		goto nodata;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	sctp_init_cause(retval, cause_code, paylen + reserve_tail);
131862306a36Sopenharmony_ci	sctp_addto_chunk(retval, paylen, payload);
131962306a36Sopenharmony_ci	if (reserve_tail)
132062306a36Sopenharmony_ci		sctp_addto_param(retval, reserve_tail, NULL);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_cinodata:
132362306a36Sopenharmony_ci	return retval;
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistruct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc,
132762306a36Sopenharmony_ci				  __u16 key_id)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	struct sctp_authhdr auth_hdr;
133062306a36Sopenharmony_ci	struct sctp_hmac *hmac_desc;
133162306a36Sopenharmony_ci	struct sctp_chunk *retval;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	/* Get the first hmac that the peer told us to use */
133462306a36Sopenharmony_ci	hmac_desc = sctp_auth_asoc_get_hmac(asoc);
133562306a36Sopenharmony_ci	if (unlikely(!hmac_desc))
133662306a36Sopenharmony_ci		return NULL;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0,
133962306a36Sopenharmony_ci				   hmac_desc->hmac_len + sizeof(auth_hdr),
134062306a36Sopenharmony_ci				   GFP_ATOMIC);
134162306a36Sopenharmony_ci	if (!retval)
134262306a36Sopenharmony_ci		return NULL;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	auth_hdr.hmac_id = htons(hmac_desc->hmac_id);
134562306a36Sopenharmony_ci	auth_hdr.shkey_id = htons(key_id);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(auth_hdr),
134862306a36Sopenharmony_ci						 &auth_hdr);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	skb_put_zero(retval->skb, hmac_desc->hmac_len);
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	/* Adjust the chunk header to include the empty MAC */
135362306a36Sopenharmony_ci	retval->chunk_hdr->length =
135462306a36Sopenharmony_ci		htons(ntohs(retval->chunk_hdr->length) + hmac_desc->hmac_len);
135562306a36Sopenharmony_ci	retval->chunk_end = skb_tail_pointer(retval->skb);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	return retval;
135862306a36Sopenharmony_ci}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci/********************************************************************
136262306a36Sopenharmony_ci * 2nd Level Abstractions
136362306a36Sopenharmony_ci ********************************************************************/
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci/* Turn an skb into a chunk.
136662306a36Sopenharmony_ci * FIXME: Eventually move the structure directly inside the skb->cb[].
136762306a36Sopenharmony_ci *
136862306a36Sopenharmony_ci * sctpimpguide-05.txt Section 2.8.2
136962306a36Sopenharmony_ci * M1) Each time a new DATA chunk is transmitted
137062306a36Sopenharmony_ci * set the 'TSN.Missing.Report' count for that TSN to 0. The
137162306a36Sopenharmony_ci * 'TSN.Missing.Report' count will be used to determine missing chunks
137262306a36Sopenharmony_ci * and when to fast retransmit.
137362306a36Sopenharmony_ci *
137462306a36Sopenharmony_ci */
137562306a36Sopenharmony_cistruct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
137662306a36Sopenharmony_ci				 const struct sctp_association *asoc,
137762306a36Sopenharmony_ci				 struct sock *sk, gfp_t gfp)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	struct sctp_chunk *retval;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	retval = kmem_cache_zalloc(sctp_chunk_cachep, gfp);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	if (!retval)
138462306a36Sopenharmony_ci		goto nodata;
138562306a36Sopenharmony_ci	if (!sk)
138662306a36Sopenharmony_ci		pr_debug("%s: chunkifying skb:%p w/o an sk\n", __func__, skb);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	INIT_LIST_HEAD(&retval->list);
138962306a36Sopenharmony_ci	retval->skb		= skb;
139062306a36Sopenharmony_ci	retval->asoc		= (struct sctp_association *)asoc;
139162306a36Sopenharmony_ci	retval->singleton	= 1;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	retval->fast_retransmit = SCTP_CAN_FRTX;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	/* Polish the bead hole.  */
139662306a36Sopenharmony_ci	INIT_LIST_HEAD(&retval->transmitted_list);
139762306a36Sopenharmony_ci	INIT_LIST_HEAD(&retval->frag_list);
139862306a36Sopenharmony_ci	SCTP_DBG_OBJCNT_INC(chunk);
139962306a36Sopenharmony_ci	refcount_set(&retval->refcnt, 1);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cinodata:
140262306a36Sopenharmony_ci	return retval;
140362306a36Sopenharmony_ci}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci/* Set chunk->source and dest based on the IP header in chunk->skb.  */
140662306a36Sopenharmony_civoid sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src,
140762306a36Sopenharmony_ci		     union sctp_addr *dest)
140862306a36Sopenharmony_ci{
140962306a36Sopenharmony_ci	memcpy(&chunk->source, src, sizeof(union sctp_addr));
141062306a36Sopenharmony_ci	memcpy(&chunk->dest, dest, sizeof(union sctp_addr));
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci/* Extract the source address from a chunk.  */
141462306a36Sopenharmony_ciconst union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	/* If we have a known transport, use that.  */
141762306a36Sopenharmony_ci	if (chunk->transport) {
141862306a36Sopenharmony_ci		return &chunk->transport->ipaddr;
141962306a36Sopenharmony_ci	} else {
142062306a36Sopenharmony_ci		/* Otherwise, extract it from the IP header.  */
142162306a36Sopenharmony_ci		return &chunk->source;
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci/* Create a new chunk, setting the type and flags headers from the
142662306a36Sopenharmony_ci * arguments, reserving enough space for a 'paylen' byte payload.
142762306a36Sopenharmony_ci */
142862306a36Sopenharmony_cistatic struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
142962306a36Sopenharmony_ci					   __u8 type, __u8 flags, int paylen,
143062306a36Sopenharmony_ci					   gfp_t gfp)
143162306a36Sopenharmony_ci{
143262306a36Sopenharmony_ci	struct sctp_chunkhdr *chunk_hdr;
143362306a36Sopenharmony_ci	struct sctp_chunk *retval;
143462306a36Sopenharmony_ci	struct sk_buff *skb;
143562306a36Sopenharmony_ci	struct sock *sk;
143662306a36Sopenharmony_ci	int chunklen;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	chunklen = SCTP_PAD4(sizeof(*chunk_hdr) + paylen);
143962306a36Sopenharmony_ci	if (chunklen > SCTP_MAX_CHUNK_LEN)
144062306a36Sopenharmony_ci		goto nodata;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	/* No need to allocate LL here, as this is only a chunk. */
144362306a36Sopenharmony_ci	skb = alloc_skb(chunklen, gfp);
144462306a36Sopenharmony_ci	if (!skb)
144562306a36Sopenharmony_ci		goto nodata;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	/* Make room for the chunk header.  */
144862306a36Sopenharmony_ci	chunk_hdr = (struct sctp_chunkhdr *)skb_put(skb, sizeof(*chunk_hdr));
144962306a36Sopenharmony_ci	chunk_hdr->type	  = type;
145062306a36Sopenharmony_ci	chunk_hdr->flags  = flags;
145162306a36Sopenharmony_ci	chunk_hdr->length = htons(sizeof(*chunk_hdr));
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	sk = asoc ? asoc->base.sk : NULL;
145462306a36Sopenharmony_ci	retval = sctp_chunkify(skb, asoc, sk, gfp);
145562306a36Sopenharmony_ci	if (!retval) {
145662306a36Sopenharmony_ci		kfree_skb(skb);
145762306a36Sopenharmony_ci		goto nodata;
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	retval->chunk_hdr = chunk_hdr;
146162306a36Sopenharmony_ci	retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(*chunk_hdr);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	/* Determine if the chunk needs to be authenticated */
146462306a36Sopenharmony_ci	if (sctp_auth_send_cid(type, asoc))
146562306a36Sopenharmony_ci		retval->auth = 1;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	return retval;
146862306a36Sopenharmony_cinodata:
146962306a36Sopenharmony_ci	return NULL;
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_cistatic struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
147362306a36Sopenharmony_ci					 __u8 flags, int paylen, gfp_t gfp)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen, gfp);
147662306a36Sopenharmony_ci}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cistruct sctp_chunk *sctp_make_idata(const struct sctp_association *asoc,
147962306a36Sopenharmony_ci				   __u8 flags, int paylen, gfp_t gfp)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	return _sctp_make_chunk(asoc, SCTP_CID_I_DATA, flags, paylen, gfp);
148262306a36Sopenharmony_ci}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_cistatic struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
148562306a36Sopenharmony_ci					    __u8 type, __u8 flags, int paylen,
148662306a36Sopenharmony_ci					    gfp_t gfp)
148762306a36Sopenharmony_ci{
148862306a36Sopenharmony_ci	struct sctp_chunk *chunk;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	chunk = _sctp_make_chunk(asoc, type, flags, paylen, gfp);
149162306a36Sopenharmony_ci	if (chunk)
149262306a36Sopenharmony_ci		sctp_control_set_owner_w(chunk);
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	return chunk;
149562306a36Sopenharmony_ci}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci/* Release the memory occupied by a chunk.  */
149862306a36Sopenharmony_cistatic void sctp_chunk_destroy(struct sctp_chunk *chunk)
149962306a36Sopenharmony_ci{
150062306a36Sopenharmony_ci	BUG_ON(!list_empty(&chunk->list));
150162306a36Sopenharmony_ci	list_del_init(&chunk->transmitted_list);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	consume_skb(chunk->skb);
150462306a36Sopenharmony_ci	consume_skb(chunk->auth_chunk);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	SCTP_DBG_OBJCNT_DEC(chunk);
150762306a36Sopenharmony_ci	kmem_cache_free(sctp_chunk_cachep, chunk);
150862306a36Sopenharmony_ci}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci/* Possibly, free the chunk.  */
151162306a36Sopenharmony_civoid sctp_chunk_free(struct sctp_chunk *chunk)
151262306a36Sopenharmony_ci{
151362306a36Sopenharmony_ci	/* Release our reference on the message tracker. */
151462306a36Sopenharmony_ci	if (chunk->msg)
151562306a36Sopenharmony_ci		sctp_datamsg_put(chunk->msg);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	sctp_chunk_put(chunk);
151862306a36Sopenharmony_ci}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci/* Grab a reference to the chunk. */
152162306a36Sopenharmony_civoid sctp_chunk_hold(struct sctp_chunk *ch)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	refcount_inc(&ch->refcnt);
152462306a36Sopenharmony_ci}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci/* Release a reference to the chunk. */
152762306a36Sopenharmony_civoid sctp_chunk_put(struct sctp_chunk *ch)
152862306a36Sopenharmony_ci{
152962306a36Sopenharmony_ci	if (refcount_dec_and_test(&ch->refcnt))
153062306a36Sopenharmony_ci		sctp_chunk_destroy(ch);
153162306a36Sopenharmony_ci}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci/* Append bytes to the end of a chunk.  Will panic if chunk is not big
153462306a36Sopenharmony_ci * enough.
153562306a36Sopenharmony_ci */
153662306a36Sopenharmony_civoid *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	int chunklen = ntohs(chunk->chunk_hdr->length);
153962306a36Sopenharmony_ci	int padlen = SCTP_PAD4(chunklen) - chunklen;
154062306a36Sopenharmony_ci	void *target;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	skb_put_zero(chunk->skb, padlen);
154362306a36Sopenharmony_ci	target = skb_put_data(chunk->skb, data, len);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	/* Adjust the chunk length field.  */
154662306a36Sopenharmony_ci	chunk->chunk_hdr->length = htons(chunklen + padlen + len);
154762306a36Sopenharmony_ci	chunk->chunk_end = skb_tail_pointer(chunk->skb);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	return target;
155062306a36Sopenharmony_ci}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci/* Append bytes from user space to the end of a chunk.  Will panic if
155362306a36Sopenharmony_ci * chunk is not big enough.
155462306a36Sopenharmony_ci * Returns a kernel err value.
155562306a36Sopenharmony_ci */
155662306a36Sopenharmony_ciint sctp_user_addto_chunk(struct sctp_chunk *chunk, int len,
155762306a36Sopenharmony_ci			  struct iov_iter *from)
155862306a36Sopenharmony_ci{
155962306a36Sopenharmony_ci	void *target;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	/* Make room in chunk for data.  */
156262306a36Sopenharmony_ci	target = skb_put(chunk->skb, len);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	/* Copy data (whole iovec) into chunk */
156562306a36Sopenharmony_ci	if (!copy_from_iter_full(target, len, from))
156662306a36Sopenharmony_ci		return -EFAULT;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	/* Adjust the chunk length field.  */
156962306a36Sopenharmony_ci	chunk->chunk_hdr->length =
157062306a36Sopenharmony_ci		htons(ntohs(chunk->chunk_hdr->length) + len);
157162306a36Sopenharmony_ci	chunk->chunk_end = skb_tail_pointer(chunk->skb);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	return 0;
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci/* Helper function to assign a TSN if needed.  This assumes that both
157762306a36Sopenharmony_ci * the data_hdr and association have already been assigned.
157862306a36Sopenharmony_ci */
157962306a36Sopenharmony_civoid sctp_chunk_assign_ssn(struct sctp_chunk *chunk)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	struct sctp_stream *stream;
158262306a36Sopenharmony_ci	struct sctp_chunk *lchunk;
158362306a36Sopenharmony_ci	struct sctp_datamsg *msg;
158462306a36Sopenharmony_ci	__u16 ssn, sid;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	if (chunk->has_ssn)
158762306a36Sopenharmony_ci		return;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	/* All fragments will be on the same stream */
159062306a36Sopenharmony_ci	sid = ntohs(chunk->subh.data_hdr->stream);
159162306a36Sopenharmony_ci	stream = &chunk->asoc->stream;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	/* Now assign the sequence number to the entire message.
159462306a36Sopenharmony_ci	 * All fragments must have the same stream sequence number.
159562306a36Sopenharmony_ci	 */
159662306a36Sopenharmony_ci	msg = chunk->msg;
159762306a36Sopenharmony_ci	list_for_each_entry(lchunk, &msg->chunks, frag_list) {
159862306a36Sopenharmony_ci		if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
159962306a36Sopenharmony_ci			ssn = 0;
160062306a36Sopenharmony_ci		} else {
160162306a36Sopenharmony_ci			if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG)
160262306a36Sopenharmony_ci				ssn = sctp_ssn_next(stream, out, sid);
160362306a36Sopenharmony_ci			else
160462306a36Sopenharmony_ci				ssn = sctp_ssn_peek(stream, out, sid);
160562306a36Sopenharmony_ci		}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci		lchunk->subh.data_hdr->ssn = htons(ssn);
160862306a36Sopenharmony_ci		lchunk->has_ssn = 1;
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci/* Helper function to assign a TSN if needed.  This assumes that both
161362306a36Sopenharmony_ci * the data_hdr and association have already been assigned.
161462306a36Sopenharmony_ci */
161562306a36Sopenharmony_civoid sctp_chunk_assign_tsn(struct sctp_chunk *chunk)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	if (!chunk->has_tsn) {
161862306a36Sopenharmony_ci		/* This is the last possible instant to
161962306a36Sopenharmony_ci		 * assign a TSN.
162062306a36Sopenharmony_ci		 */
162162306a36Sopenharmony_ci		chunk->subh.data_hdr->tsn =
162262306a36Sopenharmony_ci			htonl(sctp_association_get_next_tsn(chunk->asoc));
162362306a36Sopenharmony_ci		chunk->has_tsn = 1;
162462306a36Sopenharmony_ci	}
162562306a36Sopenharmony_ci}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci/* Create a CLOSED association to use with an incoming packet.  */
162862306a36Sopenharmony_cistruct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
162962306a36Sopenharmony_ci					     struct sctp_chunk *chunk,
163062306a36Sopenharmony_ci					     gfp_t gfp)
163162306a36Sopenharmony_ci{
163262306a36Sopenharmony_ci	struct sctp_association *asoc;
163362306a36Sopenharmony_ci	enum sctp_scope scope;
163462306a36Sopenharmony_ci	struct sk_buff *skb;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	/* Create the bare association.  */
163762306a36Sopenharmony_ci	scope = sctp_scope(sctp_source(chunk));
163862306a36Sopenharmony_ci	asoc = sctp_association_new(ep, ep->base.sk, scope, gfp);
163962306a36Sopenharmony_ci	if (!asoc)
164062306a36Sopenharmony_ci		goto nodata;
164162306a36Sopenharmony_ci	asoc->temp = 1;
164262306a36Sopenharmony_ci	skb = chunk->skb;
164362306a36Sopenharmony_ci	/* Create an entry for the source address of the packet.  */
164462306a36Sopenharmony_ci	SCTP_INPUT_CB(skb)->af->from_skb(&asoc->c.peer_addr, skb, 1);
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_cinodata:
164762306a36Sopenharmony_ci	return asoc;
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci/* Build a cookie representing asoc.
165162306a36Sopenharmony_ci * This INCLUDES the param header needed to put the cookie in the INIT ACK.
165262306a36Sopenharmony_ci */
165362306a36Sopenharmony_cistatic struct sctp_cookie_param *sctp_pack_cookie(
165462306a36Sopenharmony_ci					const struct sctp_endpoint *ep,
165562306a36Sopenharmony_ci					const struct sctp_association *asoc,
165662306a36Sopenharmony_ci					const struct sctp_chunk *init_chunk,
165762306a36Sopenharmony_ci					int *cookie_len, const __u8 *raw_addrs,
165862306a36Sopenharmony_ci					int addrs_len)
165962306a36Sopenharmony_ci{
166062306a36Sopenharmony_ci	struct sctp_signed_cookie *cookie;
166162306a36Sopenharmony_ci	struct sctp_cookie_param *retval;
166262306a36Sopenharmony_ci	int headersize, bodysize;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	/* Header size is static data prior to the actual cookie, including
166562306a36Sopenharmony_ci	 * any padding.
166662306a36Sopenharmony_ci	 */
166762306a36Sopenharmony_ci	headersize = sizeof(struct sctp_paramhdr) +
166862306a36Sopenharmony_ci		     (sizeof(struct sctp_signed_cookie) -
166962306a36Sopenharmony_ci		      sizeof(struct sctp_cookie));
167062306a36Sopenharmony_ci	bodysize = sizeof(struct sctp_cookie)
167162306a36Sopenharmony_ci		+ ntohs(init_chunk->chunk_hdr->length) + addrs_len;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	/* Pad out the cookie to a multiple to make the signature
167462306a36Sopenharmony_ci	 * functions simpler to write.
167562306a36Sopenharmony_ci	 */
167662306a36Sopenharmony_ci	if (bodysize % SCTP_COOKIE_MULTIPLE)
167762306a36Sopenharmony_ci		bodysize += SCTP_COOKIE_MULTIPLE
167862306a36Sopenharmony_ci			- (bodysize % SCTP_COOKIE_MULTIPLE);
167962306a36Sopenharmony_ci	*cookie_len = headersize + bodysize;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	/* Clear this memory since we are sending this data structure
168262306a36Sopenharmony_ci	 * out on the network.
168362306a36Sopenharmony_ci	 */
168462306a36Sopenharmony_ci	retval = kzalloc(*cookie_len, GFP_ATOMIC);
168562306a36Sopenharmony_ci	if (!retval)
168662306a36Sopenharmony_ci		goto nodata;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	cookie = (struct sctp_signed_cookie *) retval->body;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	/* Set up the parameter header.  */
169162306a36Sopenharmony_ci	retval->p.type = SCTP_PARAM_STATE_COOKIE;
169262306a36Sopenharmony_ci	retval->p.length = htons(*cookie_len);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	/* Copy the cookie part of the association itself.  */
169562306a36Sopenharmony_ci	cookie->c = asoc->c;
169662306a36Sopenharmony_ci	/* Save the raw address list length in the cookie. */
169762306a36Sopenharmony_ci	cookie->c.raw_addr_list_len = addrs_len;
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	/* Remember PR-SCTP capability. */
170062306a36Sopenharmony_ci	cookie->c.prsctp_capable = asoc->peer.prsctp_capable;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	/* Save adaptation indication in the cookie. */
170362306a36Sopenharmony_ci	cookie->c.adaptation_ind = asoc->peer.adaptation_ind;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	/* Set an expiration time for the cookie.  */
170662306a36Sopenharmony_ci	cookie->c.expiration = ktime_add(asoc->cookie_life,
170762306a36Sopenharmony_ci					 ktime_get_real());
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	/* Copy the peer's init packet.  */
171062306a36Sopenharmony_ci	memcpy(cookie + 1, init_chunk->chunk_hdr,
171162306a36Sopenharmony_ci	       ntohs(init_chunk->chunk_hdr->length));
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	/* Copy the raw local address list of the association. */
171462306a36Sopenharmony_ci	memcpy((__u8 *)(cookie + 1) +
171562306a36Sopenharmony_ci	       ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len);
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	if (sctp_sk(ep->base.sk)->hmac) {
171862306a36Sopenharmony_ci		struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac;
171962306a36Sopenharmony_ci		int err;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci		/* Sign the message.  */
172262306a36Sopenharmony_ci		err = crypto_shash_setkey(tfm, ep->secret_key,
172362306a36Sopenharmony_ci					  sizeof(ep->secret_key)) ?:
172462306a36Sopenharmony_ci		      crypto_shash_tfm_digest(tfm, (u8 *)&cookie->c, bodysize,
172562306a36Sopenharmony_ci					      cookie->signature);
172662306a36Sopenharmony_ci		if (err)
172762306a36Sopenharmony_ci			goto free_cookie;
172862306a36Sopenharmony_ci	}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	return retval;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_cifree_cookie:
173362306a36Sopenharmony_ci	kfree(retval);
173462306a36Sopenharmony_cinodata:
173562306a36Sopenharmony_ci	*cookie_len = 0;
173662306a36Sopenharmony_ci	return NULL;
173762306a36Sopenharmony_ci}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci/* Unpack the cookie from COOKIE ECHO chunk, recreating the association.  */
174062306a36Sopenharmony_cistruct sctp_association *sctp_unpack_cookie(
174162306a36Sopenharmony_ci					const struct sctp_endpoint *ep,
174262306a36Sopenharmony_ci					const struct sctp_association *asoc,
174362306a36Sopenharmony_ci					struct sctp_chunk *chunk, gfp_t gfp,
174462306a36Sopenharmony_ci					int *error, struct sctp_chunk **errp)
174562306a36Sopenharmony_ci{
174662306a36Sopenharmony_ci	struct sctp_association *retval = NULL;
174762306a36Sopenharmony_ci	int headersize, bodysize, fixed_size;
174862306a36Sopenharmony_ci	struct sctp_signed_cookie *cookie;
174962306a36Sopenharmony_ci	struct sk_buff *skb = chunk->skb;
175062306a36Sopenharmony_ci	struct sctp_cookie *bear_cookie;
175162306a36Sopenharmony_ci	__u8 *digest = ep->digest;
175262306a36Sopenharmony_ci	enum sctp_scope scope;
175362306a36Sopenharmony_ci	unsigned int len;
175462306a36Sopenharmony_ci	ktime_t kt;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	/* Header size is static data prior to the actual cookie, including
175762306a36Sopenharmony_ci	 * any padding.
175862306a36Sopenharmony_ci	 */
175962306a36Sopenharmony_ci	headersize = sizeof(struct sctp_chunkhdr) +
176062306a36Sopenharmony_ci		     (sizeof(struct sctp_signed_cookie) -
176162306a36Sopenharmony_ci		      sizeof(struct sctp_cookie));
176262306a36Sopenharmony_ci	bodysize = ntohs(chunk->chunk_hdr->length) - headersize;
176362306a36Sopenharmony_ci	fixed_size = headersize + sizeof(struct sctp_cookie);
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	/* Verify that the chunk looks like it even has a cookie.
176662306a36Sopenharmony_ci	 * There must be enough room for our cookie and our peer's
176762306a36Sopenharmony_ci	 * INIT chunk.
176862306a36Sopenharmony_ci	 */
176962306a36Sopenharmony_ci	len = ntohs(chunk->chunk_hdr->length);
177062306a36Sopenharmony_ci	if (len < fixed_size + sizeof(struct sctp_chunkhdr))
177162306a36Sopenharmony_ci		goto malformed;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	/* Verify that the cookie has been padded out. */
177462306a36Sopenharmony_ci	if (bodysize % SCTP_COOKIE_MULTIPLE)
177562306a36Sopenharmony_ci		goto malformed;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	/* Process the cookie.  */
177862306a36Sopenharmony_ci	cookie = chunk->subh.cookie_hdr;
177962306a36Sopenharmony_ci	bear_cookie = &cookie->c;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	if (!sctp_sk(ep->base.sk)->hmac)
178262306a36Sopenharmony_ci		goto no_hmac;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	/* Check the signature.  */
178562306a36Sopenharmony_ci	{
178662306a36Sopenharmony_ci		struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac;
178762306a36Sopenharmony_ci		int err;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci		err = crypto_shash_setkey(tfm, ep->secret_key,
179062306a36Sopenharmony_ci					  sizeof(ep->secret_key)) ?:
179162306a36Sopenharmony_ci		      crypto_shash_tfm_digest(tfm, (u8 *)bear_cookie, bodysize,
179262306a36Sopenharmony_ci					      digest);
179362306a36Sopenharmony_ci		if (err) {
179462306a36Sopenharmony_ci			*error = -SCTP_IERROR_NOMEM;
179562306a36Sopenharmony_ci			goto fail;
179662306a36Sopenharmony_ci		}
179762306a36Sopenharmony_ci	}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
180062306a36Sopenharmony_ci		*error = -SCTP_IERROR_BAD_SIG;
180162306a36Sopenharmony_ci		goto fail;
180262306a36Sopenharmony_ci	}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_cino_hmac:
180562306a36Sopenharmony_ci	/* IG Section 2.35.2:
180662306a36Sopenharmony_ci	 *  3) Compare the port numbers and the verification tag contained
180762306a36Sopenharmony_ci	 *     within the COOKIE ECHO chunk to the actual port numbers and the
180862306a36Sopenharmony_ci	 *     verification tag within the SCTP common header of the received
180962306a36Sopenharmony_ci	 *     packet. If these values do not match the packet MUST be silently
181062306a36Sopenharmony_ci	 *     discarded,
181162306a36Sopenharmony_ci	 */
181262306a36Sopenharmony_ci	if (ntohl(chunk->sctp_hdr->vtag) != bear_cookie->my_vtag) {
181362306a36Sopenharmony_ci		*error = -SCTP_IERROR_BAD_TAG;
181462306a36Sopenharmony_ci		goto fail;
181562306a36Sopenharmony_ci	}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	if (chunk->sctp_hdr->source != bear_cookie->peer_addr.v4.sin_port ||
181862306a36Sopenharmony_ci	    ntohs(chunk->sctp_hdr->dest) != bear_cookie->my_port) {
181962306a36Sopenharmony_ci		*error = -SCTP_IERROR_BAD_PORTS;
182062306a36Sopenharmony_ci		goto fail;
182162306a36Sopenharmony_ci	}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	/* Check to see if the cookie is stale.  If there is already
182462306a36Sopenharmony_ci	 * an association, there is no need to check cookie's expiration
182562306a36Sopenharmony_ci	 * for init collision case of lost COOKIE ACK.
182662306a36Sopenharmony_ci	 * If skb has been timestamped, then use the stamp, otherwise
182762306a36Sopenharmony_ci	 * use current time.  This introduces a small possibility that
182862306a36Sopenharmony_ci	 * a cookie may be considered expired, but this would only slow
182962306a36Sopenharmony_ci	 * down the new association establishment instead of every packet.
183062306a36Sopenharmony_ci	 */
183162306a36Sopenharmony_ci	if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))
183262306a36Sopenharmony_ci		kt = skb_get_ktime(skb);
183362306a36Sopenharmony_ci	else
183462306a36Sopenharmony_ci		kt = ktime_get_real();
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	if (!asoc && ktime_before(bear_cookie->expiration, kt)) {
183762306a36Sopenharmony_ci		suseconds_t usecs = ktime_to_us(ktime_sub(kt, bear_cookie->expiration));
183862306a36Sopenharmony_ci		__be32 n = htonl(usecs);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci		/*
184162306a36Sopenharmony_ci		 * Section 3.3.10.3 Stale Cookie Error (3)
184262306a36Sopenharmony_ci		 *
184362306a36Sopenharmony_ci		 * Cause of error
184462306a36Sopenharmony_ci		 * ---------------
184562306a36Sopenharmony_ci		 * Stale Cookie Error:  Indicates the receipt of a valid State
184662306a36Sopenharmony_ci		 * Cookie that has expired.
184762306a36Sopenharmony_ci		 */
184862306a36Sopenharmony_ci		*errp = sctp_make_op_error(asoc, chunk,
184962306a36Sopenharmony_ci					   SCTP_ERROR_STALE_COOKIE, &n,
185062306a36Sopenharmony_ci					   sizeof(n), 0);
185162306a36Sopenharmony_ci		if (*errp)
185262306a36Sopenharmony_ci			*error = -SCTP_IERROR_STALE_COOKIE;
185362306a36Sopenharmony_ci		else
185462306a36Sopenharmony_ci			*error = -SCTP_IERROR_NOMEM;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci		goto fail;
185762306a36Sopenharmony_ci	}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	/* Make a new base association.  */
186062306a36Sopenharmony_ci	scope = sctp_scope(sctp_source(chunk));
186162306a36Sopenharmony_ci	retval = sctp_association_new(ep, ep->base.sk, scope, gfp);
186262306a36Sopenharmony_ci	if (!retval) {
186362306a36Sopenharmony_ci		*error = -SCTP_IERROR_NOMEM;
186462306a36Sopenharmony_ci		goto fail;
186562306a36Sopenharmony_ci	}
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	/* Set up our peer's port number.  */
186862306a36Sopenharmony_ci	retval->peer.port = ntohs(chunk->sctp_hdr->source);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	/* Populate the association from the cookie.  */
187162306a36Sopenharmony_ci	memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie));
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	if (sctp_assoc_set_bind_addr_from_cookie(retval, bear_cookie,
187462306a36Sopenharmony_ci						 GFP_ATOMIC) < 0) {
187562306a36Sopenharmony_ci		*error = -SCTP_IERROR_NOMEM;
187662306a36Sopenharmony_ci		goto fail;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	/* Also, add the destination address. */
188062306a36Sopenharmony_ci	if (list_empty(&retval->base.bind_addr.address_list)) {
188162306a36Sopenharmony_ci		sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest,
188262306a36Sopenharmony_ci				   sizeof(chunk->dest), SCTP_ADDR_SRC,
188362306a36Sopenharmony_ci				   GFP_ATOMIC);
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	retval->next_tsn = retval->c.initial_tsn;
188762306a36Sopenharmony_ci	retval->ctsn_ack_point = retval->next_tsn - 1;
188862306a36Sopenharmony_ci	retval->addip_serial = retval->c.initial_tsn;
188962306a36Sopenharmony_ci	retval->strreset_outseq = retval->c.initial_tsn;
189062306a36Sopenharmony_ci	retval->adv_peer_ack_point = retval->ctsn_ack_point;
189162306a36Sopenharmony_ci	retval->peer.prsctp_capable = retval->c.prsctp_capable;
189262306a36Sopenharmony_ci	retval->peer.adaptation_ind = retval->c.adaptation_ind;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	/* The INIT stuff will be done by the side effects.  */
189562306a36Sopenharmony_ci	return retval;
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_cifail:
189862306a36Sopenharmony_ci	if (retval)
189962306a36Sopenharmony_ci		sctp_association_free(retval);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	return NULL;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_cimalformed:
190462306a36Sopenharmony_ci	/* Yikes!  The packet is either corrupt or deliberately
190562306a36Sopenharmony_ci	 * malformed.
190662306a36Sopenharmony_ci	 */
190762306a36Sopenharmony_ci	*error = -SCTP_IERROR_MALFORMED;
190862306a36Sopenharmony_ci	goto fail;
190962306a36Sopenharmony_ci}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci/********************************************************************
191262306a36Sopenharmony_ci * 3rd Level Abstractions
191362306a36Sopenharmony_ci ********************************************************************/
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_cistruct __sctp_missing {
191662306a36Sopenharmony_ci	__be32 num_missing;
191762306a36Sopenharmony_ci	__be16 type;
191862306a36Sopenharmony_ci}  __packed;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci/*
192162306a36Sopenharmony_ci * Report a missing mandatory parameter.
192262306a36Sopenharmony_ci */
192362306a36Sopenharmony_cistatic int sctp_process_missing_param(const struct sctp_association *asoc,
192462306a36Sopenharmony_ci				      enum sctp_param paramtype,
192562306a36Sopenharmony_ci				      struct sctp_chunk *chunk,
192662306a36Sopenharmony_ci				      struct sctp_chunk **errp)
192762306a36Sopenharmony_ci{
192862306a36Sopenharmony_ci	struct __sctp_missing report;
192962306a36Sopenharmony_ci	__u16 len;
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	len = SCTP_PAD4(sizeof(report));
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	/* Make an ERROR chunk, preparing enough room for
193462306a36Sopenharmony_ci	 * returning multiple unknown parameters.
193562306a36Sopenharmony_ci	 */
193662306a36Sopenharmony_ci	if (!*errp)
193762306a36Sopenharmony_ci		*errp = sctp_make_op_error_space(asoc, chunk, len);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	if (*errp) {
194062306a36Sopenharmony_ci		report.num_missing = htonl(1);
194162306a36Sopenharmony_ci		report.type = paramtype;
194262306a36Sopenharmony_ci		sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM,
194362306a36Sopenharmony_ci				sizeof(report));
194462306a36Sopenharmony_ci		sctp_addto_chunk(*errp, sizeof(report), &report);
194562306a36Sopenharmony_ci	}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	/* Stop processing this chunk. */
194862306a36Sopenharmony_ci	return 0;
194962306a36Sopenharmony_ci}
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci/* Report an Invalid Mandatory Parameter.  */
195262306a36Sopenharmony_cistatic int sctp_process_inv_mandatory(const struct sctp_association *asoc,
195362306a36Sopenharmony_ci				      struct sctp_chunk *chunk,
195462306a36Sopenharmony_ci				      struct sctp_chunk **errp)
195562306a36Sopenharmony_ci{
195662306a36Sopenharmony_ci	/* Invalid Mandatory Parameter Error has no payload. */
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	if (!*errp)
195962306a36Sopenharmony_ci		*errp = sctp_make_op_error_space(asoc, chunk, 0);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	if (*errp)
196262306a36Sopenharmony_ci		sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, 0);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	/* Stop processing this chunk. */
196562306a36Sopenharmony_ci	return 0;
196662306a36Sopenharmony_ci}
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_cistatic int sctp_process_inv_paramlength(const struct sctp_association *asoc,
196962306a36Sopenharmony_ci					struct sctp_paramhdr *param,
197062306a36Sopenharmony_ci					const struct sctp_chunk *chunk,
197162306a36Sopenharmony_ci					struct sctp_chunk **errp)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	/* This is a fatal error.  Any accumulated non-fatal errors are
197462306a36Sopenharmony_ci	 * not reported.
197562306a36Sopenharmony_ci	 */
197662306a36Sopenharmony_ci	if (*errp)
197762306a36Sopenharmony_ci		sctp_chunk_free(*errp);
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	/* Create an error chunk and fill it in with our payload. */
198062306a36Sopenharmony_ci	*errp = sctp_make_violation_paramlen(asoc, chunk, param);
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	return 0;
198362306a36Sopenharmony_ci}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci/* Do not attempt to handle the HOST_NAME parm.  However, do
198762306a36Sopenharmony_ci * send back an indicator to the peer.
198862306a36Sopenharmony_ci */
198962306a36Sopenharmony_cistatic int sctp_process_hn_param(const struct sctp_association *asoc,
199062306a36Sopenharmony_ci				 union sctp_params param,
199162306a36Sopenharmony_ci				 struct sctp_chunk *chunk,
199262306a36Sopenharmony_ci				 struct sctp_chunk **errp)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci	__u16 len = ntohs(param.p->length);
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	/* Processing of the HOST_NAME parameter will generate an
199762306a36Sopenharmony_ci	 * ABORT.  If we've accumulated any non-fatal errors, they
199862306a36Sopenharmony_ci	 * would be unrecognized parameters and we should not include
199962306a36Sopenharmony_ci	 * them in the ABORT.
200062306a36Sopenharmony_ci	 */
200162306a36Sopenharmony_ci	if (*errp)
200262306a36Sopenharmony_ci		sctp_chunk_free(*errp);
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	*errp = sctp_make_op_error(asoc, chunk, SCTP_ERROR_DNS_FAILED,
200562306a36Sopenharmony_ci				   param.v, len, 0);
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	/* Stop processing this chunk. */
200862306a36Sopenharmony_ci	return 0;
200962306a36Sopenharmony_ci}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_cistatic int sctp_verify_ext_param(struct net *net,
201262306a36Sopenharmony_ci				 const struct sctp_endpoint *ep,
201362306a36Sopenharmony_ci				 union sctp_params param)
201462306a36Sopenharmony_ci{
201562306a36Sopenharmony_ci	__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
201662306a36Sopenharmony_ci	int have_asconf = 0;
201762306a36Sopenharmony_ci	int have_auth = 0;
201862306a36Sopenharmony_ci	int i;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	for (i = 0; i < num_ext; i++) {
202162306a36Sopenharmony_ci		switch (param.ext->chunks[i]) {
202262306a36Sopenharmony_ci		case SCTP_CID_AUTH:
202362306a36Sopenharmony_ci			have_auth = 1;
202462306a36Sopenharmony_ci			break;
202562306a36Sopenharmony_ci		case SCTP_CID_ASCONF:
202662306a36Sopenharmony_ci		case SCTP_CID_ASCONF_ACK:
202762306a36Sopenharmony_ci			have_asconf = 1;
202862306a36Sopenharmony_ci			break;
202962306a36Sopenharmony_ci		}
203062306a36Sopenharmony_ci	}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	/* ADD-IP Security: The draft requires us to ABORT or ignore the
203362306a36Sopenharmony_ci	 * INIT/INIT-ACK if ADD-IP is listed, but AUTH is not.  Do this
203462306a36Sopenharmony_ci	 * only if ADD-IP is turned on and we are not backward-compatible
203562306a36Sopenharmony_ci	 * mode.
203662306a36Sopenharmony_ci	 */
203762306a36Sopenharmony_ci	if (net->sctp.addip_noauth)
203862306a36Sopenharmony_ci		return 1;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	if (ep->asconf_enable && !have_auth && have_asconf)
204162306a36Sopenharmony_ci		return 0;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	return 1;
204462306a36Sopenharmony_ci}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_cistatic void sctp_process_ext_param(struct sctp_association *asoc,
204762306a36Sopenharmony_ci				   union sctp_params param)
204862306a36Sopenharmony_ci{
204962306a36Sopenharmony_ci	__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
205062306a36Sopenharmony_ci	int i;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	for (i = 0; i < num_ext; i++) {
205362306a36Sopenharmony_ci		switch (param.ext->chunks[i]) {
205462306a36Sopenharmony_ci		case SCTP_CID_RECONF:
205562306a36Sopenharmony_ci			if (asoc->ep->reconf_enable)
205662306a36Sopenharmony_ci				asoc->peer.reconf_capable = 1;
205762306a36Sopenharmony_ci			break;
205862306a36Sopenharmony_ci		case SCTP_CID_FWD_TSN:
205962306a36Sopenharmony_ci			if (asoc->ep->prsctp_enable)
206062306a36Sopenharmony_ci				asoc->peer.prsctp_capable = 1;
206162306a36Sopenharmony_ci			break;
206262306a36Sopenharmony_ci		case SCTP_CID_AUTH:
206362306a36Sopenharmony_ci			/* if the peer reports AUTH, assume that he
206462306a36Sopenharmony_ci			 * supports AUTH.
206562306a36Sopenharmony_ci			 */
206662306a36Sopenharmony_ci			if (asoc->ep->auth_enable)
206762306a36Sopenharmony_ci				asoc->peer.auth_capable = 1;
206862306a36Sopenharmony_ci			break;
206962306a36Sopenharmony_ci		case SCTP_CID_ASCONF:
207062306a36Sopenharmony_ci		case SCTP_CID_ASCONF_ACK:
207162306a36Sopenharmony_ci			if (asoc->ep->asconf_enable)
207262306a36Sopenharmony_ci				asoc->peer.asconf_capable = 1;
207362306a36Sopenharmony_ci			break;
207462306a36Sopenharmony_ci		case SCTP_CID_I_DATA:
207562306a36Sopenharmony_ci			if (asoc->ep->intl_enable)
207662306a36Sopenharmony_ci				asoc->peer.intl_capable = 1;
207762306a36Sopenharmony_ci			break;
207862306a36Sopenharmony_ci		default:
207962306a36Sopenharmony_ci			break;
208062306a36Sopenharmony_ci		}
208162306a36Sopenharmony_ci	}
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci/* RFC 3.2.1 & the Implementers Guide 2.2.
208562306a36Sopenharmony_ci *
208662306a36Sopenharmony_ci * The Parameter Types are encoded such that the
208762306a36Sopenharmony_ci * highest-order two bits specify the action that must be
208862306a36Sopenharmony_ci * taken if the processing endpoint does not recognize the
208962306a36Sopenharmony_ci * Parameter Type.
209062306a36Sopenharmony_ci *
209162306a36Sopenharmony_ci * 00 - Stop processing this parameter; do not process any further
209262306a36Sopenharmony_ci * 	parameters within this chunk
209362306a36Sopenharmony_ci *
209462306a36Sopenharmony_ci * 01 - Stop processing this parameter, do not process any further
209562306a36Sopenharmony_ci *	parameters within this chunk, and report the unrecognized
209662306a36Sopenharmony_ci *	parameter in an 'Unrecognized Parameter' ERROR chunk.
209762306a36Sopenharmony_ci *
209862306a36Sopenharmony_ci * 10 - Skip this parameter and continue processing.
209962306a36Sopenharmony_ci *
210062306a36Sopenharmony_ci * 11 - Skip this parameter and continue processing but
210162306a36Sopenharmony_ci *	report the unrecognized parameter in an
210262306a36Sopenharmony_ci *	'Unrecognized Parameter' ERROR chunk.
210362306a36Sopenharmony_ci *
210462306a36Sopenharmony_ci * Return value:
210562306a36Sopenharmony_ci * 	SCTP_IERROR_NO_ERROR - continue with the chunk
210662306a36Sopenharmony_ci * 	SCTP_IERROR_ERROR    - stop and report an error.
210762306a36Sopenharmony_ci * 	SCTP_IERROR_NOMEME   - out of memory.
210862306a36Sopenharmony_ci */
210962306a36Sopenharmony_cistatic enum sctp_ierror sctp_process_unk_param(
211062306a36Sopenharmony_ci					const struct sctp_association *asoc,
211162306a36Sopenharmony_ci					union sctp_params param,
211262306a36Sopenharmony_ci					struct sctp_chunk *chunk,
211362306a36Sopenharmony_ci					struct sctp_chunk **errp)
211462306a36Sopenharmony_ci{
211562306a36Sopenharmony_ci	int retval = SCTP_IERROR_NO_ERROR;
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	switch (param.p->type & SCTP_PARAM_ACTION_MASK) {
211862306a36Sopenharmony_ci	case SCTP_PARAM_ACTION_DISCARD:
211962306a36Sopenharmony_ci		retval =  SCTP_IERROR_ERROR;
212062306a36Sopenharmony_ci		break;
212162306a36Sopenharmony_ci	case SCTP_PARAM_ACTION_SKIP:
212262306a36Sopenharmony_ci		break;
212362306a36Sopenharmony_ci	case SCTP_PARAM_ACTION_DISCARD_ERR:
212462306a36Sopenharmony_ci		retval =  SCTP_IERROR_ERROR;
212562306a36Sopenharmony_ci		fallthrough;
212662306a36Sopenharmony_ci	case SCTP_PARAM_ACTION_SKIP_ERR:
212762306a36Sopenharmony_ci		/* Make an ERROR chunk, preparing enough room for
212862306a36Sopenharmony_ci		 * returning multiple unknown parameters.
212962306a36Sopenharmony_ci		 */
213062306a36Sopenharmony_ci		if (!*errp) {
213162306a36Sopenharmony_ci			*errp = sctp_make_op_error_limited(asoc, chunk);
213262306a36Sopenharmony_ci			if (!*errp) {
213362306a36Sopenharmony_ci				/* If there is no memory for generating the
213462306a36Sopenharmony_ci				 * ERROR report as specified, an ABORT will be
213562306a36Sopenharmony_ci				 * triggered to the peer and the association
213662306a36Sopenharmony_ci				 * won't be established.
213762306a36Sopenharmony_ci				 */
213862306a36Sopenharmony_ci				retval = SCTP_IERROR_NOMEM;
213962306a36Sopenharmony_ci				break;
214062306a36Sopenharmony_ci			}
214162306a36Sopenharmony_ci		}
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci		if (!sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
214462306a36Sopenharmony_ci				     ntohs(param.p->length)))
214562306a36Sopenharmony_ci			sctp_addto_chunk(*errp, ntohs(param.p->length),
214662306a36Sopenharmony_ci					 param.v);
214762306a36Sopenharmony_ci		break;
214862306a36Sopenharmony_ci	default:
214962306a36Sopenharmony_ci		break;
215062306a36Sopenharmony_ci	}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	return retval;
215362306a36Sopenharmony_ci}
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci/* Verify variable length parameters
215662306a36Sopenharmony_ci * Return values:
215762306a36Sopenharmony_ci * 	SCTP_IERROR_ABORT - trigger an ABORT
215862306a36Sopenharmony_ci * 	SCTP_IERROR_NOMEM - out of memory (abort)
215962306a36Sopenharmony_ci *	SCTP_IERROR_ERROR - stop processing, trigger an ERROR
216062306a36Sopenharmony_ci * 	SCTP_IERROR_NO_ERROR - continue with the chunk
216162306a36Sopenharmony_ci */
216262306a36Sopenharmony_cistatic enum sctp_ierror sctp_verify_param(struct net *net,
216362306a36Sopenharmony_ci					  const struct sctp_endpoint *ep,
216462306a36Sopenharmony_ci					  const struct sctp_association *asoc,
216562306a36Sopenharmony_ci					  union sctp_params param,
216662306a36Sopenharmony_ci					  enum sctp_cid cid,
216762306a36Sopenharmony_ci					  struct sctp_chunk *chunk,
216862306a36Sopenharmony_ci					  struct sctp_chunk **err_chunk)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	struct sctp_hmac_algo_param *hmacs;
217162306a36Sopenharmony_ci	int retval = SCTP_IERROR_NO_ERROR;
217262306a36Sopenharmony_ci	__u16 n_elt, id = 0;
217362306a36Sopenharmony_ci	int i;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	/* FIXME - This routine is not looking at each parameter per the
217662306a36Sopenharmony_ci	 * chunk type, i.e., unrecognized parameters should be further
217762306a36Sopenharmony_ci	 * identified based on the chunk id.
217862306a36Sopenharmony_ci	 */
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	switch (param.p->type) {
218162306a36Sopenharmony_ci	case SCTP_PARAM_IPV4_ADDRESS:
218262306a36Sopenharmony_ci	case SCTP_PARAM_IPV6_ADDRESS:
218362306a36Sopenharmony_ci	case SCTP_PARAM_COOKIE_PRESERVATIVE:
218462306a36Sopenharmony_ci	case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:
218562306a36Sopenharmony_ci	case SCTP_PARAM_STATE_COOKIE:
218662306a36Sopenharmony_ci	case SCTP_PARAM_HEARTBEAT_INFO:
218762306a36Sopenharmony_ci	case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
218862306a36Sopenharmony_ci	case SCTP_PARAM_ECN_CAPABLE:
218962306a36Sopenharmony_ci	case SCTP_PARAM_ADAPTATION_LAYER_IND:
219062306a36Sopenharmony_ci		break;
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	case SCTP_PARAM_SUPPORTED_EXT:
219362306a36Sopenharmony_ci		if (!sctp_verify_ext_param(net, ep, param))
219462306a36Sopenharmony_ci			return SCTP_IERROR_ABORT;
219562306a36Sopenharmony_ci		break;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	case SCTP_PARAM_SET_PRIMARY:
219862306a36Sopenharmony_ci		if (!ep->asconf_enable)
219962306a36Sopenharmony_ci			goto unhandled;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci		if (ntohs(param.p->length) < sizeof(struct sctp_addip_param) +
220262306a36Sopenharmony_ci					     sizeof(struct sctp_paramhdr)) {
220362306a36Sopenharmony_ci			sctp_process_inv_paramlength(asoc, param.p,
220462306a36Sopenharmony_ci						     chunk, err_chunk);
220562306a36Sopenharmony_ci			retval = SCTP_IERROR_ABORT;
220662306a36Sopenharmony_ci		}
220762306a36Sopenharmony_ci		break;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	case SCTP_PARAM_HOST_NAME_ADDRESS:
221062306a36Sopenharmony_ci		/* This param has been Deprecated, send ABORT.  */
221162306a36Sopenharmony_ci		sctp_process_hn_param(asoc, param, chunk, err_chunk);
221262306a36Sopenharmony_ci		retval = SCTP_IERROR_ABORT;
221362306a36Sopenharmony_ci		break;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	case SCTP_PARAM_FWD_TSN_SUPPORT:
221662306a36Sopenharmony_ci		if (ep->prsctp_enable)
221762306a36Sopenharmony_ci			break;
221862306a36Sopenharmony_ci		goto unhandled;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	case SCTP_PARAM_RANDOM:
222162306a36Sopenharmony_ci		if (!ep->auth_enable)
222262306a36Sopenharmony_ci			goto unhandled;
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci		/* SCTP-AUTH: Secion 6.1
222562306a36Sopenharmony_ci		 * If the random number is not 32 byte long the association
222662306a36Sopenharmony_ci		 * MUST be aborted.  The ABORT chunk SHOULD contain the error
222762306a36Sopenharmony_ci		 * cause 'Protocol Violation'.
222862306a36Sopenharmony_ci		 */
222962306a36Sopenharmony_ci		if (SCTP_AUTH_RANDOM_LENGTH != ntohs(param.p->length) -
223062306a36Sopenharmony_ci					       sizeof(struct sctp_paramhdr)) {
223162306a36Sopenharmony_ci			sctp_process_inv_paramlength(asoc, param.p,
223262306a36Sopenharmony_ci						     chunk, err_chunk);
223362306a36Sopenharmony_ci			retval = SCTP_IERROR_ABORT;
223462306a36Sopenharmony_ci		}
223562306a36Sopenharmony_ci		break;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	case SCTP_PARAM_CHUNKS:
223862306a36Sopenharmony_ci		if (!ep->auth_enable)
223962306a36Sopenharmony_ci			goto unhandled;
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci		/* SCTP-AUTH: Section 3.2
224262306a36Sopenharmony_ci		 * The CHUNKS parameter MUST be included once in the INIT or
224362306a36Sopenharmony_ci		 *  INIT-ACK chunk if the sender wants to receive authenticated
224462306a36Sopenharmony_ci		 *  chunks.  Its maximum length is 260 bytes.
224562306a36Sopenharmony_ci		 */
224662306a36Sopenharmony_ci		if (260 < ntohs(param.p->length)) {
224762306a36Sopenharmony_ci			sctp_process_inv_paramlength(asoc, param.p,
224862306a36Sopenharmony_ci						     chunk, err_chunk);
224962306a36Sopenharmony_ci			retval = SCTP_IERROR_ABORT;
225062306a36Sopenharmony_ci		}
225162306a36Sopenharmony_ci		break;
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	case SCTP_PARAM_HMAC_ALGO:
225462306a36Sopenharmony_ci		if (!ep->auth_enable)
225562306a36Sopenharmony_ci			goto unhandled;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci		hmacs = (struct sctp_hmac_algo_param *)param.p;
225862306a36Sopenharmony_ci		n_elt = (ntohs(param.p->length) -
225962306a36Sopenharmony_ci			 sizeof(struct sctp_paramhdr)) >> 1;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci		/* SCTP-AUTH: Section 6.1
226262306a36Sopenharmony_ci		 * The HMAC algorithm based on SHA-1 MUST be supported and
226362306a36Sopenharmony_ci		 * included in the HMAC-ALGO parameter.
226462306a36Sopenharmony_ci		 */
226562306a36Sopenharmony_ci		for (i = 0; i < n_elt; i++) {
226662306a36Sopenharmony_ci			id = ntohs(hmacs->hmac_ids[i]);
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci			if (id == SCTP_AUTH_HMAC_ID_SHA1)
226962306a36Sopenharmony_ci				break;
227062306a36Sopenharmony_ci		}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci		if (id != SCTP_AUTH_HMAC_ID_SHA1) {
227362306a36Sopenharmony_ci			sctp_process_inv_paramlength(asoc, param.p, chunk,
227462306a36Sopenharmony_ci						     err_chunk);
227562306a36Sopenharmony_ci			retval = SCTP_IERROR_ABORT;
227662306a36Sopenharmony_ci		}
227762306a36Sopenharmony_ci		break;
227862306a36Sopenharmony_ciunhandled:
227962306a36Sopenharmony_ci	default:
228062306a36Sopenharmony_ci		pr_debug("%s: unrecognized param:%d for chunk:%d\n",
228162306a36Sopenharmony_ci			 __func__, ntohs(param.p->type), cid);
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci		retval = sctp_process_unk_param(asoc, param, chunk, err_chunk);
228462306a36Sopenharmony_ci		break;
228562306a36Sopenharmony_ci	}
228662306a36Sopenharmony_ci	return retval;
228762306a36Sopenharmony_ci}
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci/* Verify the INIT packet before we process it.  */
229062306a36Sopenharmony_ciint sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
229162306a36Sopenharmony_ci		     const struct sctp_association *asoc, enum sctp_cid cid,
229262306a36Sopenharmony_ci		     struct sctp_init_chunk *peer_init,
229362306a36Sopenharmony_ci		     struct sctp_chunk *chunk, struct sctp_chunk **errp)
229462306a36Sopenharmony_ci{
229562306a36Sopenharmony_ci	union sctp_params param;
229662306a36Sopenharmony_ci	bool has_cookie = false;
229762306a36Sopenharmony_ci	int result;
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	/* Check for missing mandatory parameters. Note: Initial TSN is
230062306a36Sopenharmony_ci	 * also mandatory, but is not checked here since the valid range
230162306a36Sopenharmony_ci	 * is 0..2**32-1. RFC4960, section 3.3.3.
230262306a36Sopenharmony_ci	 */
230362306a36Sopenharmony_ci	if (peer_init->init_hdr.num_outbound_streams == 0 ||
230462306a36Sopenharmony_ci	    peer_init->init_hdr.num_inbound_streams == 0 ||
230562306a36Sopenharmony_ci	    peer_init->init_hdr.init_tag == 0 ||
230662306a36Sopenharmony_ci	    ntohl(peer_init->init_hdr.a_rwnd) < SCTP_DEFAULT_MINWINDOW)
230762306a36Sopenharmony_ci		return sctp_process_inv_mandatory(asoc, chunk, errp);
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	sctp_walk_params(param, peer_init) {
231062306a36Sopenharmony_ci		if (param.p->type == SCTP_PARAM_STATE_COOKIE)
231162306a36Sopenharmony_ci			has_cookie = true;
231262306a36Sopenharmony_ci	}
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	/* There is a possibility that a parameter length was bad and
231562306a36Sopenharmony_ci	 * in that case we would have stoped walking the parameters.
231662306a36Sopenharmony_ci	 * The current param.p would point at the bad one.
231762306a36Sopenharmony_ci	 * Current consensus on the mailing list is to generate a PROTOCOL
231862306a36Sopenharmony_ci	 * VIOLATION error.  We build the ERROR chunk here and let the normal
231962306a36Sopenharmony_ci	 * error handling code build and send the packet.
232062306a36Sopenharmony_ci	 */
232162306a36Sopenharmony_ci	if (param.v != (void *)chunk->chunk_end)
232262306a36Sopenharmony_ci		return sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	/* The only missing mandatory param possible today is
232562306a36Sopenharmony_ci	 * the state cookie for an INIT-ACK chunk.
232662306a36Sopenharmony_ci	 */
232762306a36Sopenharmony_ci	if ((SCTP_CID_INIT_ACK == cid) && !has_cookie)
232862306a36Sopenharmony_ci		return sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
232962306a36Sopenharmony_ci						  chunk, errp);
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci	/* Verify all the variable length parameters */
233262306a36Sopenharmony_ci	sctp_walk_params(param, peer_init) {
233362306a36Sopenharmony_ci		result = sctp_verify_param(net, ep, asoc, param, cid,
233462306a36Sopenharmony_ci					   chunk, errp);
233562306a36Sopenharmony_ci		switch (result) {
233662306a36Sopenharmony_ci		case SCTP_IERROR_ABORT:
233762306a36Sopenharmony_ci		case SCTP_IERROR_NOMEM:
233862306a36Sopenharmony_ci			return 0;
233962306a36Sopenharmony_ci		case SCTP_IERROR_ERROR:
234062306a36Sopenharmony_ci			return 1;
234162306a36Sopenharmony_ci		case SCTP_IERROR_NO_ERROR:
234262306a36Sopenharmony_ci		default:
234362306a36Sopenharmony_ci			break;
234462306a36Sopenharmony_ci		}
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	} /* for (loop through all parameters) */
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	return 1;
234962306a36Sopenharmony_ci}
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci/* Unpack the parameters in an INIT packet into an association.
235262306a36Sopenharmony_ci * Returns 0 on failure, else success.
235362306a36Sopenharmony_ci * FIXME:  This is an association method.
235462306a36Sopenharmony_ci */
235562306a36Sopenharmony_ciint sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
235662306a36Sopenharmony_ci		      const union sctp_addr *peer_addr,
235762306a36Sopenharmony_ci		      struct sctp_init_chunk *peer_init, gfp_t gfp)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	struct sctp_transport *transport;
236062306a36Sopenharmony_ci	struct list_head *pos, *temp;
236162306a36Sopenharmony_ci	union sctp_params param;
236262306a36Sopenharmony_ci	union sctp_addr addr;
236362306a36Sopenharmony_ci	struct sctp_af *af;
236462306a36Sopenharmony_ci	int src_match = 0;
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	/* We must include the address that the INIT packet came from.
236762306a36Sopenharmony_ci	 * This is the only address that matters for an INIT packet.
236862306a36Sopenharmony_ci	 * When processing a COOKIE ECHO, we retrieve the from address
236962306a36Sopenharmony_ci	 * of the INIT from the cookie.
237062306a36Sopenharmony_ci	 */
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	/* This implementation defaults to making the first transport
237362306a36Sopenharmony_ci	 * added as the primary transport.  The source address seems to
237462306a36Sopenharmony_ci	 * be a better choice than any of the embedded addresses.
237562306a36Sopenharmony_ci	 */
237662306a36Sopenharmony_ci	asoc->encap_port = SCTP_INPUT_CB(chunk->skb)->encap_port;
237762306a36Sopenharmony_ci	if (!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE))
237862306a36Sopenharmony_ci		goto nomem;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr))
238162306a36Sopenharmony_ci		src_match = 1;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	/* Process the initialization parameters.  */
238462306a36Sopenharmony_ci	sctp_walk_params(param, peer_init) {
238562306a36Sopenharmony_ci		if (!src_match &&
238662306a36Sopenharmony_ci		    (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
238762306a36Sopenharmony_ci		     param.p->type == SCTP_PARAM_IPV6_ADDRESS)) {
238862306a36Sopenharmony_ci			af = sctp_get_af_specific(param_type2af(param.p->type));
238962306a36Sopenharmony_ci			if (!af->from_addr_param(&addr, param.addr,
239062306a36Sopenharmony_ci						 chunk->sctp_hdr->source, 0))
239162306a36Sopenharmony_ci				continue;
239262306a36Sopenharmony_ci			if (sctp_cmp_addr_exact(sctp_source(chunk), &addr))
239362306a36Sopenharmony_ci				src_match = 1;
239462306a36Sopenharmony_ci		}
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci		if (!sctp_process_param(asoc, param, peer_addr, gfp))
239762306a36Sopenharmony_ci			goto clean_up;
239862306a36Sopenharmony_ci	}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	/* source address of chunk may not match any valid address */
240162306a36Sopenharmony_ci	if (!src_match)
240262306a36Sopenharmony_ci		goto clean_up;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	/* AUTH: After processing the parameters, make sure that we
240562306a36Sopenharmony_ci	 * have all the required info to potentially do authentications.
240662306a36Sopenharmony_ci	 */
240762306a36Sopenharmony_ci	if (asoc->peer.auth_capable && (!asoc->peer.peer_random ||
240862306a36Sopenharmony_ci					!asoc->peer.peer_hmacs))
240962306a36Sopenharmony_ci		asoc->peer.auth_capable = 0;
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci	/* In a non-backward compatible mode, if the peer claims
241262306a36Sopenharmony_ci	 * support for ADD-IP but not AUTH,  the ADD-IP spec states
241362306a36Sopenharmony_ci	 * that we MUST ABORT the association. Section 6.  The section
241462306a36Sopenharmony_ci	 * also give us an option to silently ignore the packet, which
241562306a36Sopenharmony_ci	 * is what we'll do here.
241662306a36Sopenharmony_ci	 */
241762306a36Sopenharmony_ci	if (!asoc->base.net->sctp.addip_noauth &&
241862306a36Sopenharmony_ci	    (asoc->peer.asconf_capable && !asoc->peer.auth_capable)) {
241962306a36Sopenharmony_ci		asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP |
242062306a36Sopenharmony_ci						  SCTP_PARAM_DEL_IP |
242162306a36Sopenharmony_ci						  SCTP_PARAM_SET_PRIMARY);
242262306a36Sopenharmony_ci		asoc->peer.asconf_capable = 0;
242362306a36Sopenharmony_ci		goto clean_up;
242462306a36Sopenharmony_ci	}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	/* Walk list of transports, removing transports in the UNKNOWN state. */
242762306a36Sopenharmony_ci	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
242862306a36Sopenharmony_ci		transport = list_entry(pos, struct sctp_transport, transports);
242962306a36Sopenharmony_ci		if (transport->state == SCTP_UNKNOWN) {
243062306a36Sopenharmony_ci			sctp_assoc_rm_peer(asoc, transport);
243162306a36Sopenharmony_ci		}
243262306a36Sopenharmony_ci	}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	/* The fixed INIT headers are always in network byte
243562306a36Sopenharmony_ci	 * order.
243662306a36Sopenharmony_ci	 */
243762306a36Sopenharmony_ci	asoc->peer.i.init_tag =
243862306a36Sopenharmony_ci		ntohl(peer_init->init_hdr.init_tag);
243962306a36Sopenharmony_ci	asoc->peer.i.a_rwnd =
244062306a36Sopenharmony_ci		ntohl(peer_init->init_hdr.a_rwnd);
244162306a36Sopenharmony_ci	asoc->peer.i.num_outbound_streams =
244262306a36Sopenharmony_ci		ntohs(peer_init->init_hdr.num_outbound_streams);
244362306a36Sopenharmony_ci	asoc->peer.i.num_inbound_streams =
244462306a36Sopenharmony_ci		ntohs(peer_init->init_hdr.num_inbound_streams);
244562306a36Sopenharmony_ci	asoc->peer.i.initial_tsn =
244662306a36Sopenharmony_ci		ntohl(peer_init->init_hdr.initial_tsn);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	asoc->strreset_inseq = asoc->peer.i.initial_tsn;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	/* Apply the upper bounds for output streams based on peer's
245162306a36Sopenharmony_ci	 * number of inbound streams.
245262306a36Sopenharmony_ci	 */
245362306a36Sopenharmony_ci	if (asoc->c.sinit_num_ostreams  >
245462306a36Sopenharmony_ci	    ntohs(peer_init->init_hdr.num_inbound_streams)) {
245562306a36Sopenharmony_ci		asoc->c.sinit_num_ostreams =
245662306a36Sopenharmony_ci			ntohs(peer_init->init_hdr.num_inbound_streams);
245762306a36Sopenharmony_ci	}
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	if (asoc->c.sinit_max_instreams >
246062306a36Sopenharmony_ci	    ntohs(peer_init->init_hdr.num_outbound_streams)) {
246162306a36Sopenharmony_ci		asoc->c.sinit_max_instreams =
246262306a36Sopenharmony_ci			ntohs(peer_init->init_hdr.num_outbound_streams);
246362306a36Sopenharmony_ci	}
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	/* Copy Initiation tag from INIT to VT_peer in cookie.   */
246662306a36Sopenharmony_ci	asoc->c.peer_vtag = asoc->peer.i.init_tag;
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	/* Peer Rwnd   : Current calculated value of the peer's rwnd.  */
246962306a36Sopenharmony_ci	asoc->peer.rwnd = asoc->peer.i.a_rwnd;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	/* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily
247262306a36Sopenharmony_ci	 * high (for example, implementations MAY use the size of the receiver
247362306a36Sopenharmony_ci	 * advertised window).
247462306a36Sopenharmony_ci	 */
247562306a36Sopenharmony_ci	list_for_each_entry(transport, &asoc->peer.transport_addr_list,
247662306a36Sopenharmony_ci			transports) {
247762306a36Sopenharmony_ci		transport->ssthresh = asoc->peer.i.a_rwnd;
247862306a36Sopenharmony_ci	}
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	/* Set up the TSN tracking pieces.  */
248162306a36Sopenharmony_ci	if (!sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
248262306a36Sopenharmony_ci				asoc->peer.i.initial_tsn, gfp))
248362306a36Sopenharmony_ci		goto clean_up;
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
248662306a36Sopenharmony_ci	 *
248762306a36Sopenharmony_ci	 * The stream sequence number in all the streams shall start
248862306a36Sopenharmony_ci	 * from 0 when the association is established.  Also, when the
248962306a36Sopenharmony_ci	 * stream sequence number reaches the value 65535 the next
249062306a36Sopenharmony_ci	 * stream sequence number shall be set to 0.
249162306a36Sopenharmony_ci	 */
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams,
249462306a36Sopenharmony_ci			     asoc->c.sinit_max_instreams, gfp))
249562306a36Sopenharmony_ci		goto clean_up;
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	/* Update frag_point when stream_interleave may get changed. */
249862306a36Sopenharmony_ci	sctp_assoc_update_frag_point(asoc);
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	if (!asoc->temp && sctp_assoc_set_id(asoc, gfp))
250162306a36Sopenharmony_ci		goto clean_up;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	/* ADDIP Section 4.1 ASCONF Chunk Procedures
250462306a36Sopenharmony_ci	 *
250562306a36Sopenharmony_ci	 * When an endpoint has an ASCONF signaled change to be sent to the
250662306a36Sopenharmony_ci	 * remote endpoint it should do the following:
250762306a36Sopenharmony_ci	 * ...
250862306a36Sopenharmony_ci	 * A2) A serial number should be assigned to the Chunk. The serial
250962306a36Sopenharmony_ci	 * number should be a monotonically increasing number. All serial
251062306a36Sopenharmony_ci	 * numbers are defined to be initialized at the start of the
251162306a36Sopenharmony_ci	 * association to the same value as the Initial TSN.
251262306a36Sopenharmony_ci	 */
251362306a36Sopenharmony_ci	asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1;
251462306a36Sopenharmony_ci	return 1;
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ciclean_up:
251762306a36Sopenharmony_ci	/* Release the transport structures. */
251862306a36Sopenharmony_ci	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
251962306a36Sopenharmony_ci		transport = list_entry(pos, struct sctp_transport, transports);
252062306a36Sopenharmony_ci		if (transport->state != SCTP_ACTIVE)
252162306a36Sopenharmony_ci			sctp_assoc_rm_peer(asoc, transport);
252262306a36Sopenharmony_ci	}
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_cinomem:
252562306a36Sopenharmony_ci	return 0;
252662306a36Sopenharmony_ci}
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci/* Update asoc with the option described in param.
253062306a36Sopenharmony_ci *
253162306a36Sopenharmony_ci * RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT
253262306a36Sopenharmony_ci *
253362306a36Sopenharmony_ci * asoc is the association to update.
253462306a36Sopenharmony_ci * param is the variable length parameter to use for update.
253562306a36Sopenharmony_ci * cid tells us if this is an INIT, INIT ACK or COOKIE ECHO.
253662306a36Sopenharmony_ci * If the current packet is an INIT we want to minimize the amount of
253762306a36Sopenharmony_ci * work we do.  In particular, we should not build transport
253862306a36Sopenharmony_ci * structures for the addresses.
253962306a36Sopenharmony_ci */
254062306a36Sopenharmony_cistatic int sctp_process_param(struct sctp_association *asoc,
254162306a36Sopenharmony_ci			      union sctp_params param,
254262306a36Sopenharmony_ci			      const union sctp_addr *peer_addr,
254362306a36Sopenharmony_ci			      gfp_t gfp)
254462306a36Sopenharmony_ci{
254562306a36Sopenharmony_ci	struct sctp_endpoint *ep = asoc->ep;
254662306a36Sopenharmony_ci	union sctp_addr_param *addr_param;
254762306a36Sopenharmony_ci	struct net *net = asoc->base.net;
254862306a36Sopenharmony_ci	struct sctp_transport *t;
254962306a36Sopenharmony_ci	enum sctp_scope scope;
255062306a36Sopenharmony_ci	union sctp_addr addr;
255162306a36Sopenharmony_ci	struct sctp_af *af;
255262306a36Sopenharmony_ci	int retval = 1, i;
255362306a36Sopenharmony_ci	u32 stale;
255462306a36Sopenharmony_ci	__u16 sat;
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	/* We maintain all INIT parameters in network byte order all the
255762306a36Sopenharmony_ci	 * time.  This allows us to not worry about whether the parameters
255862306a36Sopenharmony_ci	 * came from a fresh INIT, and INIT ACK, or were stored in a cookie.
255962306a36Sopenharmony_ci	 */
256062306a36Sopenharmony_ci	switch (param.p->type) {
256162306a36Sopenharmony_ci	case SCTP_PARAM_IPV6_ADDRESS:
256262306a36Sopenharmony_ci		if (PF_INET6 != asoc->base.sk->sk_family)
256362306a36Sopenharmony_ci			break;
256462306a36Sopenharmony_ci		goto do_addr_param;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	case SCTP_PARAM_IPV4_ADDRESS:
256762306a36Sopenharmony_ci		/* v4 addresses are not allowed on v6-only socket */
256862306a36Sopenharmony_ci		if (ipv6_only_sock(asoc->base.sk))
256962306a36Sopenharmony_ci			break;
257062306a36Sopenharmony_cido_addr_param:
257162306a36Sopenharmony_ci		af = sctp_get_af_specific(param_type2af(param.p->type));
257262306a36Sopenharmony_ci		if (!af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0))
257362306a36Sopenharmony_ci			break;
257462306a36Sopenharmony_ci		scope = sctp_scope(peer_addr);
257562306a36Sopenharmony_ci		if (sctp_in_scope(net, &addr, scope))
257662306a36Sopenharmony_ci			if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
257762306a36Sopenharmony_ci				return 0;
257862306a36Sopenharmony_ci		break;
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	case SCTP_PARAM_COOKIE_PRESERVATIVE:
258162306a36Sopenharmony_ci		if (!net->sctp.cookie_preserve_enable)
258262306a36Sopenharmony_ci			break;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci		stale = ntohl(param.life->lifespan_increment);
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci		/* Suggested Cookie Life span increment's unit is msec,
258762306a36Sopenharmony_ci		 * (1/1000sec).
258862306a36Sopenharmony_ci		 */
258962306a36Sopenharmony_ci		asoc->cookie_life = ktime_add_ms(asoc->cookie_life, stale);
259062306a36Sopenharmony_ci		break;
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:
259362306a36Sopenharmony_ci		/* Turn off the default values first so we'll know which
259462306a36Sopenharmony_ci		 * ones are really set by the peer.
259562306a36Sopenharmony_ci		 */
259662306a36Sopenharmony_ci		asoc->peer.ipv4_address = 0;
259762306a36Sopenharmony_ci		asoc->peer.ipv6_address = 0;
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci		/* Assume that peer supports the address family
260062306a36Sopenharmony_ci		 * by which it sends a packet.
260162306a36Sopenharmony_ci		 */
260262306a36Sopenharmony_ci		if (peer_addr->sa.sa_family == AF_INET6)
260362306a36Sopenharmony_ci			asoc->peer.ipv6_address = 1;
260462306a36Sopenharmony_ci		else if (peer_addr->sa.sa_family == AF_INET)
260562306a36Sopenharmony_ci			asoc->peer.ipv4_address = 1;
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci		/* Cycle through address types; avoid divide by 0. */
260862306a36Sopenharmony_ci		sat = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
260962306a36Sopenharmony_ci		if (sat)
261062306a36Sopenharmony_ci			sat /= sizeof(__u16);
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci		for (i = 0; i < sat; ++i) {
261362306a36Sopenharmony_ci			switch (param.sat->types[i]) {
261462306a36Sopenharmony_ci			case SCTP_PARAM_IPV4_ADDRESS:
261562306a36Sopenharmony_ci				asoc->peer.ipv4_address = 1;
261662306a36Sopenharmony_ci				break;
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci			case SCTP_PARAM_IPV6_ADDRESS:
261962306a36Sopenharmony_ci				if (PF_INET6 == asoc->base.sk->sk_family)
262062306a36Sopenharmony_ci					asoc->peer.ipv6_address = 1;
262162306a36Sopenharmony_ci				break;
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci			default: /* Just ignore anything else.  */
262462306a36Sopenharmony_ci				break;
262562306a36Sopenharmony_ci			}
262662306a36Sopenharmony_ci		}
262762306a36Sopenharmony_ci		break;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	case SCTP_PARAM_STATE_COOKIE:
263062306a36Sopenharmony_ci		asoc->peer.cookie_len =
263162306a36Sopenharmony_ci			ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
263262306a36Sopenharmony_ci		kfree(asoc->peer.cookie);
263362306a36Sopenharmony_ci		asoc->peer.cookie = kmemdup(param.cookie->body, asoc->peer.cookie_len, gfp);
263462306a36Sopenharmony_ci		if (!asoc->peer.cookie)
263562306a36Sopenharmony_ci			retval = 0;
263662306a36Sopenharmony_ci		break;
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci	case SCTP_PARAM_HEARTBEAT_INFO:
263962306a36Sopenharmony_ci		/* Would be odd to receive, but it causes no problems. */
264062306a36Sopenharmony_ci		break;
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_ci	case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
264362306a36Sopenharmony_ci		/* Rejected during verify stage. */
264462306a36Sopenharmony_ci		break;
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	case SCTP_PARAM_ECN_CAPABLE:
264762306a36Sopenharmony_ci		if (asoc->ep->ecn_enable) {
264862306a36Sopenharmony_ci			asoc->peer.ecn_capable = 1;
264962306a36Sopenharmony_ci			break;
265062306a36Sopenharmony_ci		}
265162306a36Sopenharmony_ci		/* Fall Through */
265262306a36Sopenharmony_ci		goto fall_through;
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	case SCTP_PARAM_ADAPTATION_LAYER_IND:
265662306a36Sopenharmony_ci		asoc->peer.adaptation_ind = ntohl(param.aind->adaptation_ind);
265762306a36Sopenharmony_ci		break;
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	case SCTP_PARAM_SET_PRIMARY:
266062306a36Sopenharmony_ci		if (!ep->asconf_enable)
266162306a36Sopenharmony_ci			goto fall_through;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci		addr_param = param.v + sizeof(struct sctp_addip_param);
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci		af = sctp_get_af_specific(param_type2af(addr_param->p.type));
266662306a36Sopenharmony_ci		if (!af)
266762306a36Sopenharmony_ci			break;
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci		if (!af->from_addr_param(&addr, addr_param,
267062306a36Sopenharmony_ci					 htons(asoc->peer.port), 0))
267162306a36Sopenharmony_ci			break;
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci		if (!af->addr_valid(&addr, NULL, NULL))
267462306a36Sopenharmony_ci			break;
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci		t = sctp_assoc_lookup_paddr(asoc, &addr);
267762306a36Sopenharmony_ci		if (!t)
267862306a36Sopenharmony_ci			break;
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci		sctp_assoc_set_primary(asoc, t);
268162306a36Sopenharmony_ci		break;
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	case SCTP_PARAM_SUPPORTED_EXT:
268462306a36Sopenharmony_ci		sctp_process_ext_param(asoc, param);
268562306a36Sopenharmony_ci		break;
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	case SCTP_PARAM_FWD_TSN_SUPPORT:
268862306a36Sopenharmony_ci		if (asoc->ep->prsctp_enable) {
268962306a36Sopenharmony_ci			asoc->peer.prsctp_capable = 1;
269062306a36Sopenharmony_ci			break;
269162306a36Sopenharmony_ci		}
269262306a36Sopenharmony_ci		/* Fall Through */
269362306a36Sopenharmony_ci		goto fall_through;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	case SCTP_PARAM_RANDOM:
269662306a36Sopenharmony_ci		if (!ep->auth_enable)
269762306a36Sopenharmony_ci			goto fall_through;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci		/* Save peer's random parameter */
270062306a36Sopenharmony_ci		kfree(asoc->peer.peer_random);
270162306a36Sopenharmony_ci		asoc->peer.peer_random = kmemdup(param.p,
270262306a36Sopenharmony_ci					    ntohs(param.p->length), gfp);
270362306a36Sopenharmony_ci		if (!asoc->peer.peer_random) {
270462306a36Sopenharmony_ci			retval = 0;
270562306a36Sopenharmony_ci			break;
270662306a36Sopenharmony_ci		}
270762306a36Sopenharmony_ci		break;
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci	case SCTP_PARAM_HMAC_ALGO:
271062306a36Sopenharmony_ci		if (!ep->auth_enable)
271162306a36Sopenharmony_ci			goto fall_through;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci		/* Save peer's HMAC list */
271462306a36Sopenharmony_ci		kfree(asoc->peer.peer_hmacs);
271562306a36Sopenharmony_ci		asoc->peer.peer_hmacs = kmemdup(param.p,
271662306a36Sopenharmony_ci					    ntohs(param.p->length), gfp);
271762306a36Sopenharmony_ci		if (!asoc->peer.peer_hmacs) {
271862306a36Sopenharmony_ci			retval = 0;
271962306a36Sopenharmony_ci			break;
272062306a36Sopenharmony_ci		}
272162306a36Sopenharmony_ci
272262306a36Sopenharmony_ci		/* Set the default HMAC the peer requested*/
272362306a36Sopenharmony_ci		sctp_auth_asoc_set_default_hmac(asoc, param.hmac_algo);
272462306a36Sopenharmony_ci		break;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	case SCTP_PARAM_CHUNKS:
272762306a36Sopenharmony_ci		if (!ep->auth_enable)
272862306a36Sopenharmony_ci			goto fall_through;
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci		kfree(asoc->peer.peer_chunks);
273162306a36Sopenharmony_ci		asoc->peer.peer_chunks = kmemdup(param.p,
273262306a36Sopenharmony_ci					    ntohs(param.p->length), gfp);
273362306a36Sopenharmony_ci		if (!asoc->peer.peer_chunks)
273462306a36Sopenharmony_ci			retval = 0;
273562306a36Sopenharmony_ci		break;
273662306a36Sopenharmony_cifall_through:
273762306a36Sopenharmony_ci	default:
273862306a36Sopenharmony_ci		/* Any unrecognized parameters should have been caught
273962306a36Sopenharmony_ci		 * and handled by sctp_verify_param() which should be
274062306a36Sopenharmony_ci		 * called prior to this routine.  Simply log the error
274162306a36Sopenharmony_ci		 * here.
274262306a36Sopenharmony_ci		 */
274362306a36Sopenharmony_ci		pr_debug("%s: ignoring param:%d for association:%p.\n",
274462306a36Sopenharmony_ci			 __func__, ntohs(param.p->type), asoc);
274562306a36Sopenharmony_ci		break;
274662306a36Sopenharmony_ci	}
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	return retval;
274962306a36Sopenharmony_ci}
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci/* Select a new verification tag.  */
275262306a36Sopenharmony_ci__u32 sctp_generate_tag(const struct sctp_endpoint *ep)
275362306a36Sopenharmony_ci{
275462306a36Sopenharmony_ci	/* I believe that this random number generator complies with RFC1750.
275562306a36Sopenharmony_ci	 * A tag of 0 is reserved for special cases (e.g. INIT).
275662306a36Sopenharmony_ci	 */
275762306a36Sopenharmony_ci	__u32 x;
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci	do {
276062306a36Sopenharmony_ci		get_random_bytes(&x, sizeof(__u32));
276162306a36Sopenharmony_ci	} while (x == 0);
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	return x;
276462306a36Sopenharmony_ci}
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci/* Select an initial TSN to send during startup.  */
276762306a36Sopenharmony_ci__u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
276862306a36Sopenharmony_ci{
276962306a36Sopenharmony_ci	__u32 retval;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	get_random_bytes(&retval, sizeof(__u32));
277262306a36Sopenharmony_ci	return retval;
277362306a36Sopenharmony_ci}
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci/*
277662306a36Sopenharmony_ci * ADDIP 3.1.1 Address Configuration Change Chunk (ASCONF)
277762306a36Sopenharmony_ci *      0                   1                   2                   3
277862306a36Sopenharmony_ci *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
277962306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278062306a36Sopenharmony_ci *     | Type = 0xC1   |  Chunk Flags  |      Chunk Length             |
278162306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278262306a36Sopenharmony_ci *     |                       Serial Number                           |
278362306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278462306a36Sopenharmony_ci *     |                    Address Parameter                          |
278562306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278662306a36Sopenharmony_ci *     |                     ASCONF Parameter #1                       |
278762306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278862306a36Sopenharmony_ci *     \                                                               \
278962306a36Sopenharmony_ci *     /                             ....                              /
279062306a36Sopenharmony_ci *     \                                                               \
279162306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279262306a36Sopenharmony_ci *     |                     ASCONF Parameter #N                       |
279362306a36Sopenharmony_ci *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279462306a36Sopenharmony_ci *
279562306a36Sopenharmony_ci * Address Parameter and other parameter will not be wrapped in this function
279662306a36Sopenharmony_ci */
279762306a36Sopenharmony_cistatic struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
279862306a36Sopenharmony_ci					   union sctp_addr *addr,
279962306a36Sopenharmony_ci					   int vparam_len)
280062306a36Sopenharmony_ci{
280162306a36Sopenharmony_ci	struct sctp_addiphdr asconf;
280262306a36Sopenharmony_ci	struct sctp_chunk *retval;
280362306a36Sopenharmony_ci	int length = sizeof(asconf) + vparam_len;
280462306a36Sopenharmony_ci	union sctp_addr_param addrparam;
280562306a36Sopenharmony_ci	int addrlen;
280662306a36Sopenharmony_ci	struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	addrlen = af->to_addr_param(addr, &addrparam);
280962306a36Sopenharmony_ci	if (!addrlen)
281062306a36Sopenharmony_ci		return NULL;
281162306a36Sopenharmony_ci	length += addrlen;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	/* Create the chunk.  */
281462306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length,
281562306a36Sopenharmony_ci				   GFP_ATOMIC);
281662306a36Sopenharmony_ci	if (!retval)
281762306a36Sopenharmony_ci		return NULL;
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci	asconf.serial = htonl(asoc->addip_serial++);
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	retval->subh.addip_hdr =
282262306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(asconf), &asconf);
282362306a36Sopenharmony_ci	retval->param_hdr.v =
282462306a36Sopenharmony_ci		sctp_addto_chunk(retval, addrlen, &addrparam);
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	return retval;
282762306a36Sopenharmony_ci}
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci/* ADDIP
283062306a36Sopenharmony_ci * 3.2.1 Add IP Address
283162306a36Sopenharmony_ci * 	0                   1                   2                   3
283262306a36Sopenharmony_ci * 	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
283362306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
283462306a36Sopenharmony_ci *     |        Type = 0xC001          |    Length = Variable          |
283562306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
283662306a36Sopenharmony_ci *     |               ASCONF-Request Correlation ID                   |
283762306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
283862306a36Sopenharmony_ci *     |                       Address Parameter                       |
283962306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
284062306a36Sopenharmony_ci *
284162306a36Sopenharmony_ci * 3.2.2 Delete IP Address
284262306a36Sopenharmony_ci * 	0                   1                   2                   3
284362306a36Sopenharmony_ci * 	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
284462306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
284562306a36Sopenharmony_ci *     |        Type = 0xC002          |    Length = Variable          |
284662306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
284762306a36Sopenharmony_ci *     |               ASCONF-Request Correlation ID                   |
284862306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
284962306a36Sopenharmony_ci *     |                       Address Parameter                       |
285062306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
285162306a36Sopenharmony_ci *
285262306a36Sopenharmony_ci */
285362306a36Sopenharmony_cistruct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
285462306a36Sopenharmony_ci					      union sctp_addr *laddr,
285562306a36Sopenharmony_ci					      struct sockaddr *addrs,
285662306a36Sopenharmony_ci					      int addrcnt, __be16 flags)
285762306a36Sopenharmony_ci{
285862306a36Sopenharmony_ci	union sctp_addr_param addr_param;
285962306a36Sopenharmony_ci	struct sctp_addip_param	param;
286062306a36Sopenharmony_ci	int paramlen = sizeof(param);
286162306a36Sopenharmony_ci	struct sctp_chunk *retval;
286262306a36Sopenharmony_ci	int addr_param_len = 0;
286362306a36Sopenharmony_ci	union sctp_addr *addr;
286462306a36Sopenharmony_ci	int totallen = 0, i;
286562306a36Sopenharmony_ci	int del_pickup = 0;
286662306a36Sopenharmony_ci	struct sctp_af *af;
286762306a36Sopenharmony_ci	void *addr_buf;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	/* Get total length of all the address parameters. */
287062306a36Sopenharmony_ci	addr_buf = addrs;
287162306a36Sopenharmony_ci	for (i = 0; i < addrcnt; i++) {
287262306a36Sopenharmony_ci		addr = addr_buf;
287362306a36Sopenharmony_ci		af = sctp_get_af_specific(addr->v4.sin_family);
287462306a36Sopenharmony_ci		addr_param_len = af->to_addr_param(addr, &addr_param);
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci		totallen += paramlen;
287762306a36Sopenharmony_ci		totallen += addr_param_len;
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci		addr_buf += af->sockaddr_len;
288062306a36Sopenharmony_ci		if (asoc->asconf_addr_del_pending && !del_pickup) {
288162306a36Sopenharmony_ci			/* reuse the parameter length from the same scope one */
288262306a36Sopenharmony_ci			totallen += paramlen;
288362306a36Sopenharmony_ci			totallen += addr_param_len;
288462306a36Sopenharmony_ci			del_pickup = 1;
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci			pr_debug("%s: picked same-scope del_pending addr, "
288762306a36Sopenharmony_ci				 "totallen for all addresses is %d\n",
288862306a36Sopenharmony_ci				 __func__, totallen);
288962306a36Sopenharmony_ci		}
289062306a36Sopenharmony_ci	}
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci	/* Create an asconf chunk with the required length. */
289362306a36Sopenharmony_ci	retval = sctp_make_asconf(asoc, laddr, totallen);
289462306a36Sopenharmony_ci	if (!retval)
289562306a36Sopenharmony_ci		return NULL;
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	/* Add the address parameters to the asconf chunk. */
289862306a36Sopenharmony_ci	addr_buf = addrs;
289962306a36Sopenharmony_ci	for (i = 0; i < addrcnt; i++) {
290062306a36Sopenharmony_ci		addr = addr_buf;
290162306a36Sopenharmony_ci		af = sctp_get_af_specific(addr->v4.sin_family);
290262306a36Sopenharmony_ci		addr_param_len = af->to_addr_param(addr, &addr_param);
290362306a36Sopenharmony_ci		param.param_hdr.type = flags;
290462306a36Sopenharmony_ci		param.param_hdr.length = htons(paramlen + addr_param_len);
290562306a36Sopenharmony_ci		param.crr_id = htonl(i);
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci		sctp_addto_chunk(retval, paramlen, &param);
290862306a36Sopenharmony_ci		sctp_addto_chunk(retval, addr_param_len, &addr_param);
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci		addr_buf += af->sockaddr_len;
291162306a36Sopenharmony_ci	}
291262306a36Sopenharmony_ci	if (flags == SCTP_PARAM_ADD_IP && del_pickup) {
291362306a36Sopenharmony_ci		addr = asoc->asconf_addr_del_pending;
291462306a36Sopenharmony_ci		af = sctp_get_af_specific(addr->v4.sin_family);
291562306a36Sopenharmony_ci		addr_param_len = af->to_addr_param(addr, &addr_param);
291662306a36Sopenharmony_ci		param.param_hdr.type = SCTP_PARAM_DEL_IP;
291762306a36Sopenharmony_ci		param.param_hdr.length = htons(paramlen + addr_param_len);
291862306a36Sopenharmony_ci		param.crr_id = htonl(i);
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci		sctp_addto_chunk(retval, paramlen, &param);
292162306a36Sopenharmony_ci		sctp_addto_chunk(retval, addr_param_len, &addr_param);
292262306a36Sopenharmony_ci	}
292362306a36Sopenharmony_ci	return retval;
292462306a36Sopenharmony_ci}
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci/* ADDIP
292762306a36Sopenharmony_ci * 3.2.4 Set Primary IP Address
292862306a36Sopenharmony_ci *	0                   1                   2                   3
292962306a36Sopenharmony_ci *	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
293062306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
293162306a36Sopenharmony_ci *     |        Type =0xC004           |    Length = Variable          |
293262306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
293362306a36Sopenharmony_ci *     |               ASCONF-Request Correlation ID                   |
293462306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
293562306a36Sopenharmony_ci *     |                       Address Parameter                       |
293662306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
293762306a36Sopenharmony_ci *
293862306a36Sopenharmony_ci * Create an ASCONF chunk with Set Primary IP address parameter.
293962306a36Sopenharmony_ci */
294062306a36Sopenharmony_cistruct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
294162306a36Sopenharmony_ci					     union sctp_addr *addr)
294262306a36Sopenharmony_ci{
294362306a36Sopenharmony_ci	struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
294462306a36Sopenharmony_ci	union sctp_addr_param addrparam;
294562306a36Sopenharmony_ci	struct sctp_addip_param	param;
294662306a36Sopenharmony_ci	struct sctp_chunk *retval;
294762306a36Sopenharmony_ci	int len = sizeof(param);
294862306a36Sopenharmony_ci	int addrlen;
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci	addrlen = af->to_addr_param(addr, &addrparam);
295162306a36Sopenharmony_ci	if (!addrlen)
295262306a36Sopenharmony_ci		return NULL;
295362306a36Sopenharmony_ci	len += addrlen;
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci	/* Create the chunk and make asconf header. */
295662306a36Sopenharmony_ci	retval = sctp_make_asconf(asoc, addr, len);
295762306a36Sopenharmony_ci	if (!retval)
295862306a36Sopenharmony_ci		return NULL;
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	param.param_hdr.type = SCTP_PARAM_SET_PRIMARY;
296162306a36Sopenharmony_ci	param.param_hdr.length = htons(len);
296262306a36Sopenharmony_ci	param.crr_id = 0;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	sctp_addto_chunk(retval, sizeof(param), &param);
296562306a36Sopenharmony_ci	sctp_addto_chunk(retval, addrlen, &addrparam);
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci	return retval;
296862306a36Sopenharmony_ci}
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_ci/* ADDIP 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK)
297162306a36Sopenharmony_ci *      0                   1                   2                   3
297262306a36Sopenharmony_ci *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
297362306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
297462306a36Sopenharmony_ci *     | Type = 0x80   |  Chunk Flags  |      Chunk Length             |
297562306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
297662306a36Sopenharmony_ci *     |                       Serial Number                           |
297762306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
297862306a36Sopenharmony_ci *     |                 ASCONF Parameter Response#1                   |
297962306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
298062306a36Sopenharmony_ci *     \                                                               \
298162306a36Sopenharmony_ci *     /                             ....                              /
298262306a36Sopenharmony_ci *     \                                                               \
298362306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
298462306a36Sopenharmony_ci *     |                 ASCONF Parameter Response#N                   |
298562306a36Sopenharmony_ci *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
298662306a36Sopenharmony_ci *
298762306a36Sopenharmony_ci * Create an ASCONF_ACK chunk with enough space for the parameter responses.
298862306a36Sopenharmony_ci */
298962306a36Sopenharmony_cistatic struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
299062306a36Sopenharmony_ci					       __u32 serial, int vparam_len)
299162306a36Sopenharmony_ci{
299262306a36Sopenharmony_ci	struct sctp_addiphdr asconf;
299362306a36Sopenharmony_ci	struct sctp_chunk *retval;
299462306a36Sopenharmony_ci	int length = sizeof(asconf) + vparam_len;
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	/* Create the chunk.  */
299762306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length,
299862306a36Sopenharmony_ci				   GFP_ATOMIC);
299962306a36Sopenharmony_ci	if (!retval)
300062306a36Sopenharmony_ci		return NULL;
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci	asconf.serial = htonl(serial);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	retval->subh.addip_hdr =
300562306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(asconf), &asconf);
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci	return retval;
300862306a36Sopenharmony_ci}
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci/* Add response parameters to an ASCONF_ACK chunk. */
301162306a36Sopenharmony_cistatic void sctp_add_asconf_response(struct sctp_chunk *chunk, __be32 crr_id,
301262306a36Sopenharmony_ci				     __be16 err_code,
301362306a36Sopenharmony_ci				     struct sctp_addip_param *asconf_param)
301462306a36Sopenharmony_ci{
301562306a36Sopenharmony_ci	struct sctp_addip_param ack_param;
301662306a36Sopenharmony_ci	struct sctp_errhdr err_param;
301762306a36Sopenharmony_ci	int asconf_param_len = 0;
301862306a36Sopenharmony_ci	int err_param_len = 0;
301962306a36Sopenharmony_ci	__be16 response_type;
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci	if (SCTP_ERROR_NO_ERROR == err_code) {
302262306a36Sopenharmony_ci		response_type = SCTP_PARAM_SUCCESS_REPORT;
302362306a36Sopenharmony_ci	} else {
302462306a36Sopenharmony_ci		response_type = SCTP_PARAM_ERR_CAUSE;
302562306a36Sopenharmony_ci		err_param_len = sizeof(err_param);
302662306a36Sopenharmony_ci		if (asconf_param)
302762306a36Sopenharmony_ci			asconf_param_len =
302862306a36Sopenharmony_ci				 ntohs(asconf_param->param_hdr.length);
302962306a36Sopenharmony_ci	}
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	/* Add Success Indication or Error Cause Indication parameter. */
303262306a36Sopenharmony_ci	ack_param.param_hdr.type = response_type;
303362306a36Sopenharmony_ci	ack_param.param_hdr.length = htons(sizeof(ack_param) +
303462306a36Sopenharmony_ci					   err_param_len +
303562306a36Sopenharmony_ci					   asconf_param_len);
303662306a36Sopenharmony_ci	ack_param.crr_id = crr_id;
303762306a36Sopenharmony_ci	sctp_addto_chunk(chunk, sizeof(ack_param), &ack_param);
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci	if (SCTP_ERROR_NO_ERROR == err_code)
304062306a36Sopenharmony_ci		return;
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	/* Add Error Cause parameter. */
304362306a36Sopenharmony_ci	err_param.cause = err_code;
304462306a36Sopenharmony_ci	err_param.length = htons(err_param_len + asconf_param_len);
304562306a36Sopenharmony_ci	sctp_addto_chunk(chunk, err_param_len, &err_param);
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	/* Add the failed TLV copied from ASCONF chunk. */
304862306a36Sopenharmony_ci	if (asconf_param)
304962306a36Sopenharmony_ci		sctp_addto_chunk(chunk, asconf_param_len, asconf_param);
305062306a36Sopenharmony_ci}
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci/* Process a asconf parameter. */
305362306a36Sopenharmony_cistatic __be16 sctp_process_asconf_param(struct sctp_association *asoc,
305462306a36Sopenharmony_ci					struct sctp_chunk *asconf,
305562306a36Sopenharmony_ci					struct sctp_addip_param *asconf_param)
305662306a36Sopenharmony_ci{
305762306a36Sopenharmony_ci	union sctp_addr_param *addr_param;
305862306a36Sopenharmony_ci	struct sctp_transport *peer;
305962306a36Sopenharmony_ci	union sctp_addr	addr;
306062306a36Sopenharmony_ci	struct sctp_af *af;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	addr_param = (void *)asconf_param + sizeof(*asconf_param);
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP &&
306562306a36Sopenharmony_ci	    asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP &&
306662306a36Sopenharmony_ci	    asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY)
306762306a36Sopenharmony_ci		return SCTP_ERROR_UNKNOWN_PARAM;
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	switch (addr_param->p.type) {
307062306a36Sopenharmony_ci	case SCTP_PARAM_IPV6_ADDRESS:
307162306a36Sopenharmony_ci		if (!asoc->peer.ipv6_address)
307262306a36Sopenharmony_ci			return SCTP_ERROR_DNS_FAILED;
307362306a36Sopenharmony_ci		break;
307462306a36Sopenharmony_ci	case SCTP_PARAM_IPV4_ADDRESS:
307562306a36Sopenharmony_ci		if (!asoc->peer.ipv4_address)
307662306a36Sopenharmony_ci			return SCTP_ERROR_DNS_FAILED;
307762306a36Sopenharmony_ci		break;
307862306a36Sopenharmony_ci	default:
307962306a36Sopenharmony_ci		return SCTP_ERROR_DNS_FAILED;
308062306a36Sopenharmony_ci	}
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	af = sctp_get_af_specific(param_type2af(addr_param->p.type));
308362306a36Sopenharmony_ci	if (unlikely(!af))
308462306a36Sopenharmony_ci		return SCTP_ERROR_DNS_FAILED;
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	if (!af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0))
308762306a36Sopenharmony_ci		return SCTP_ERROR_DNS_FAILED;
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci	/* ADDIP 4.2.1  This parameter MUST NOT contain a broadcast
309062306a36Sopenharmony_ci	 * or multicast address.
309162306a36Sopenharmony_ci	 * (note: wildcard is permitted and requires special handling so
309262306a36Sopenharmony_ci	 *  make sure we check for that)
309362306a36Sopenharmony_ci	 */
309462306a36Sopenharmony_ci	if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb))
309562306a36Sopenharmony_ci		return SCTP_ERROR_DNS_FAILED;
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_ci	switch (asconf_param->param_hdr.type) {
309862306a36Sopenharmony_ci	case SCTP_PARAM_ADD_IP:
309962306a36Sopenharmony_ci		/* Section 4.2.1:
310062306a36Sopenharmony_ci		 * If the address 0.0.0.0 or ::0 is provided, the source
310162306a36Sopenharmony_ci		 * address of the packet MUST be added.
310262306a36Sopenharmony_ci		 */
310362306a36Sopenharmony_ci		if (af->is_any(&addr))
310462306a36Sopenharmony_ci			memcpy(&addr, &asconf->source, sizeof(addr));
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci		if (security_sctp_bind_connect(asoc->ep->base.sk,
310762306a36Sopenharmony_ci					       SCTP_PARAM_ADD_IP,
310862306a36Sopenharmony_ci					       (struct sockaddr *)&addr,
310962306a36Sopenharmony_ci					       af->sockaddr_len))
311062306a36Sopenharmony_ci			return SCTP_ERROR_REQ_REFUSED;
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci		/* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
311362306a36Sopenharmony_ci		 * request and does not have the local resources to add this
311462306a36Sopenharmony_ci		 * new address to the association, it MUST return an Error
311562306a36Sopenharmony_ci		 * Cause TLV set to the new error code 'Operation Refused
311662306a36Sopenharmony_ci		 * Due to Resource Shortage'.
311762306a36Sopenharmony_ci		 */
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci		peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_UNCONFIRMED);
312062306a36Sopenharmony_ci		if (!peer)
312162306a36Sopenharmony_ci			return SCTP_ERROR_RSRC_LOW;
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci		/* Start the heartbeat timer. */
312462306a36Sopenharmony_ci		sctp_transport_reset_hb_timer(peer);
312562306a36Sopenharmony_ci		asoc->new_transport = peer;
312662306a36Sopenharmony_ci		break;
312762306a36Sopenharmony_ci	case SCTP_PARAM_DEL_IP:
312862306a36Sopenharmony_ci		/* ADDIP 4.3 D7) If a request is received to delete the
312962306a36Sopenharmony_ci		 * last remaining IP address of a peer endpoint, the receiver
313062306a36Sopenharmony_ci		 * MUST send an Error Cause TLV with the error cause set to the
313162306a36Sopenharmony_ci		 * new error code 'Request to Delete Last Remaining IP Address'.
313262306a36Sopenharmony_ci		 */
313362306a36Sopenharmony_ci		if (asoc->peer.transport_count == 1)
313462306a36Sopenharmony_ci			return SCTP_ERROR_DEL_LAST_IP;
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci		/* ADDIP 4.3 D8) If a request is received to delete an IP
313762306a36Sopenharmony_ci		 * address which is also the source address of the IP packet
313862306a36Sopenharmony_ci		 * which contained the ASCONF chunk, the receiver MUST reject
313962306a36Sopenharmony_ci		 * this request. To reject the request the receiver MUST send
314062306a36Sopenharmony_ci		 * an Error Cause TLV set to the new error code 'Request to
314162306a36Sopenharmony_ci		 * Delete Source IP Address'
314262306a36Sopenharmony_ci		 */
314362306a36Sopenharmony_ci		if (sctp_cmp_addr_exact(&asconf->source, &addr))
314462306a36Sopenharmony_ci			return SCTP_ERROR_DEL_SRC_IP;
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci		/* Section 4.2.2
314762306a36Sopenharmony_ci		 * If the address 0.0.0.0 or ::0 is provided, all
314862306a36Sopenharmony_ci		 * addresses of the peer except	the source address of the
314962306a36Sopenharmony_ci		 * packet MUST be deleted.
315062306a36Sopenharmony_ci		 */
315162306a36Sopenharmony_ci		if (af->is_any(&addr)) {
315262306a36Sopenharmony_ci			sctp_assoc_set_primary(asoc, asconf->transport);
315362306a36Sopenharmony_ci			sctp_assoc_del_nonprimary_peers(asoc,
315462306a36Sopenharmony_ci							asconf->transport);
315562306a36Sopenharmony_ci			return SCTP_ERROR_NO_ERROR;
315662306a36Sopenharmony_ci		}
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci		/* If the address is not part of the association, the
315962306a36Sopenharmony_ci		 * ASCONF-ACK with Error Cause Indication Parameter
316062306a36Sopenharmony_ci		 * which including cause of Unresolvable Address should
316162306a36Sopenharmony_ci		 * be sent.
316262306a36Sopenharmony_ci		 */
316362306a36Sopenharmony_ci		peer = sctp_assoc_lookup_paddr(asoc, &addr);
316462306a36Sopenharmony_ci		if (!peer)
316562306a36Sopenharmony_ci			return SCTP_ERROR_DNS_FAILED;
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci		sctp_assoc_rm_peer(asoc, peer);
316862306a36Sopenharmony_ci		break;
316962306a36Sopenharmony_ci	case SCTP_PARAM_SET_PRIMARY:
317062306a36Sopenharmony_ci		/* ADDIP Section 4.2.4
317162306a36Sopenharmony_ci		 * If the address 0.0.0.0 or ::0 is provided, the receiver
317262306a36Sopenharmony_ci		 * MAY mark the source address of the packet as its
317362306a36Sopenharmony_ci		 * primary.
317462306a36Sopenharmony_ci		 */
317562306a36Sopenharmony_ci		if (af->is_any(&addr))
317662306a36Sopenharmony_ci			memcpy(&addr, sctp_source(asconf), sizeof(addr));
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci		if (security_sctp_bind_connect(asoc->ep->base.sk,
317962306a36Sopenharmony_ci					       SCTP_PARAM_SET_PRIMARY,
318062306a36Sopenharmony_ci					       (struct sockaddr *)&addr,
318162306a36Sopenharmony_ci					       af->sockaddr_len))
318262306a36Sopenharmony_ci			return SCTP_ERROR_REQ_REFUSED;
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci		peer = sctp_assoc_lookup_paddr(asoc, &addr);
318562306a36Sopenharmony_ci		if (!peer)
318662306a36Sopenharmony_ci			return SCTP_ERROR_DNS_FAILED;
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci		sctp_assoc_set_primary(asoc, peer);
318962306a36Sopenharmony_ci		break;
319062306a36Sopenharmony_ci	}
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	return SCTP_ERROR_NO_ERROR;
319362306a36Sopenharmony_ci}
319462306a36Sopenharmony_ci
319562306a36Sopenharmony_ci/* Verify the ASCONF packet before we process it. */
319662306a36Sopenharmony_cibool sctp_verify_asconf(const struct sctp_association *asoc,
319762306a36Sopenharmony_ci			struct sctp_chunk *chunk, bool addr_param_needed,
319862306a36Sopenharmony_ci			struct sctp_paramhdr **errp)
319962306a36Sopenharmony_ci{
320062306a36Sopenharmony_ci	struct sctp_addip_chunk *addip;
320162306a36Sopenharmony_ci	bool addr_param_seen = false;
320262306a36Sopenharmony_ci	union sctp_params param;
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci	addip = (struct sctp_addip_chunk *)chunk->chunk_hdr;
320562306a36Sopenharmony_ci	sctp_walk_params(param, addip) {
320662306a36Sopenharmony_ci		size_t length = ntohs(param.p->length);
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_ci		*errp = param.p;
320962306a36Sopenharmony_ci		switch (param.p->type) {
321062306a36Sopenharmony_ci		case SCTP_PARAM_ERR_CAUSE:
321162306a36Sopenharmony_ci			break;
321262306a36Sopenharmony_ci		case SCTP_PARAM_IPV4_ADDRESS:
321362306a36Sopenharmony_ci			if (length != sizeof(struct sctp_ipv4addr_param))
321462306a36Sopenharmony_ci				return false;
321562306a36Sopenharmony_ci			/* ensure there is only one addr param and it's in the
321662306a36Sopenharmony_ci			 * beginning of addip_hdr params, or we reject it.
321762306a36Sopenharmony_ci			 */
321862306a36Sopenharmony_ci			if (param.v != (addip + 1))
321962306a36Sopenharmony_ci				return false;
322062306a36Sopenharmony_ci			addr_param_seen = true;
322162306a36Sopenharmony_ci			break;
322262306a36Sopenharmony_ci		case SCTP_PARAM_IPV6_ADDRESS:
322362306a36Sopenharmony_ci			if (length != sizeof(struct sctp_ipv6addr_param))
322462306a36Sopenharmony_ci				return false;
322562306a36Sopenharmony_ci			if (param.v != (addip + 1))
322662306a36Sopenharmony_ci				return false;
322762306a36Sopenharmony_ci			addr_param_seen = true;
322862306a36Sopenharmony_ci			break;
322962306a36Sopenharmony_ci		case SCTP_PARAM_ADD_IP:
323062306a36Sopenharmony_ci		case SCTP_PARAM_DEL_IP:
323162306a36Sopenharmony_ci		case SCTP_PARAM_SET_PRIMARY:
323262306a36Sopenharmony_ci			/* In ASCONF chunks, these need to be first. */
323362306a36Sopenharmony_ci			if (addr_param_needed && !addr_param_seen)
323462306a36Sopenharmony_ci				return false;
323562306a36Sopenharmony_ci			length = ntohs(param.addip->param_hdr.length);
323662306a36Sopenharmony_ci			if (length < sizeof(struct sctp_addip_param) +
323762306a36Sopenharmony_ci				     sizeof(**errp))
323862306a36Sopenharmony_ci				return false;
323962306a36Sopenharmony_ci			break;
324062306a36Sopenharmony_ci		case SCTP_PARAM_SUCCESS_REPORT:
324162306a36Sopenharmony_ci		case SCTP_PARAM_ADAPTATION_LAYER_IND:
324262306a36Sopenharmony_ci			if (length != sizeof(struct sctp_addip_param))
324362306a36Sopenharmony_ci				return false;
324462306a36Sopenharmony_ci			break;
324562306a36Sopenharmony_ci		default:
324662306a36Sopenharmony_ci			/* This is unknown to us, reject! */
324762306a36Sopenharmony_ci			return false;
324862306a36Sopenharmony_ci		}
324962306a36Sopenharmony_ci	}
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	/* Remaining sanity checks. */
325262306a36Sopenharmony_ci	if (addr_param_needed && !addr_param_seen)
325362306a36Sopenharmony_ci		return false;
325462306a36Sopenharmony_ci	if (!addr_param_needed && addr_param_seen)
325562306a36Sopenharmony_ci		return false;
325662306a36Sopenharmony_ci	if (param.v != chunk->chunk_end)
325762306a36Sopenharmony_ci		return false;
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	return true;
326062306a36Sopenharmony_ci}
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci/* Process an incoming ASCONF chunk with the next expected serial no. and
326362306a36Sopenharmony_ci * return an ASCONF_ACK chunk to be sent in response.
326462306a36Sopenharmony_ci */
326562306a36Sopenharmony_cistruct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
326662306a36Sopenharmony_ci				       struct sctp_chunk *asconf)
326762306a36Sopenharmony_ci{
326862306a36Sopenharmony_ci	union sctp_addr_param *addr_param;
326962306a36Sopenharmony_ci	struct sctp_addip_chunk *addip;
327062306a36Sopenharmony_ci	struct sctp_chunk *asconf_ack;
327162306a36Sopenharmony_ci	bool all_param_pass = true;
327262306a36Sopenharmony_ci	struct sctp_addiphdr *hdr;
327362306a36Sopenharmony_ci	int length = 0, chunk_len;
327462306a36Sopenharmony_ci	union sctp_params param;
327562306a36Sopenharmony_ci	__be16 err_code;
327662306a36Sopenharmony_ci	__u32 serial;
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	addip = (struct sctp_addip_chunk *)asconf->chunk_hdr;
327962306a36Sopenharmony_ci	chunk_len = ntohs(asconf->chunk_hdr->length) -
328062306a36Sopenharmony_ci		    sizeof(struct sctp_chunkhdr);
328162306a36Sopenharmony_ci	hdr = (struct sctp_addiphdr *)asconf->skb->data;
328262306a36Sopenharmony_ci	serial = ntohl(hdr->serial);
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	/* Skip the addiphdr and store a pointer to address parameter.  */
328562306a36Sopenharmony_ci	length = sizeof(*hdr);
328662306a36Sopenharmony_ci	addr_param = (union sctp_addr_param *)(asconf->skb->data + length);
328762306a36Sopenharmony_ci	chunk_len -= length;
328862306a36Sopenharmony_ci
328962306a36Sopenharmony_ci	/* Skip the address parameter and store a pointer to the first
329062306a36Sopenharmony_ci	 * asconf parameter.
329162306a36Sopenharmony_ci	 */
329262306a36Sopenharmony_ci	length = ntohs(addr_param->p.length);
329362306a36Sopenharmony_ci	chunk_len -= length;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	/* create an ASCONF_ACK chunk.
329662306a36Sopenharmony_ci	 * Based on the definitions of parameters, we know that the size of
329762306a36Sopenharmony_ci	 * ASCONF_ACK parameters are less than or equal to the fourfold of ASCONF
329862306a36Sopenharmony_ci	 * parameters.
329962306a36Sopenharmony_ci	 */
330062306a36Sopenharmony_ci	asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 4);
330162306a36Sopenharmony_ci	if (!asconf_ack)
330262306a36Sopenharmony_ci		goto done;
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	/* Process the TLVs contained within the ASCONF chunk. */
330562306a36Sopenharmony_ci	sctp_walk_params(param, addip) {
330662306a36Sopenharmony_ci		/* Skip preceeding address parameters. */
330762306a36Sopenharmony_ci		if (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
330862306a36Sopenharmony_ci		    param.p->type == SCTP_PARAM_IPV6_ADDRESS)
330962306a36Sopenharmony_ci			continue;
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci		err_code = sctp_process_asconf_param(asoc, asconf,
331262306a36Sopenharmony_ci						     param.addip);
331362306a36Sopenharmony_ci		/* ADDIP 4.1 A7)
331462306a36Sopenharmony_ci		 * If an error response is received for a TLV parameter,
331562306a36Sopenharmony_ci		 * all TLVs with no response before the failed TLV are
331662306a36Sopenharmony_ci		 * considered successful if not reported.  All TLVs after
331762306a36Sopenharmony_ci		 * the failed response are considered unsuccessful unless
331862306a36Sopenharmony_ci		 * a specific success indication is present for the parameter.
331962306a36Sopenharmony_ci		 */
332062306a36Sopenharmony_ci		if (err_code != SCTP_ERROR_NO_ERROR)
332162306a36Sopenharmony_ci			all_param_pass = false;
332262306a36Sopenharmony_ci		if (!all_param_pass)
332362306a36Sopenharmony_ci			sctp_add_asconf_response(asconf_ack, param.addip->crr_id,
332462306a36Sopenharmony_ci						 err_code, param.addip);
332562306a36Sopenharmony_ci
332662306a36Sopenharmony_ci		/* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add
332762306a36Sopenharmony_ci		 * an IP address sends an 'Out of Resource' in its response, it
332862306a36Sopenharmony_ci		 * MUST also fail any subsequent add or delete requests bundled
332962306a36Sopenharmony_ci		 * in the ASCONF.
333062306a36Sopenharmony_ci		 */
333162306a36Sopenharmony_ci		if (err_code == SCTP_ERROR_RSRC_LOW)
333262306a36Sopenharmony_ci			goto done;
333362306a36Sopenharmony_ci	}
333462306a36Sopenharmony_cidone:
333562306a36Sopenharmony_ci	asoc->peer.addip_serial++;
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	/* If we are sending a new ASCONF_ACK hold a reference to it in assoc
333862306a36Sopenharmony_ci	 * after freeing the reference to old asconf ack if any.
333962306a36Sopenharmony_ci	 */
334062306a36Sopenharmony_ci	if (asconf_ack) {
334162306a36Sopenharmony_ci		sctp_chunk_hold(asconf_ack);
334262306a36Sopenharmony_ci		list_add_tail(&asconf_ack->transmitted_list,
334362306a36Sopenharmony_ci			      &asoc->asconf_ack_list);
334462306a36Sopenharmony_ci	}
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	return asconf_ack;
334762306a36Sopenharmony_ci}
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci/* Process a asconf parameter that is successfully acked. */
335062306a36Sopenharmony_cistatic void sctp_asconf_param_success(struct sctp_association *asoc,
335162306a36Sopenharmony_ci				      struct sctp_addip_param *asconf_param)
335262306a36Sopenharmony_ci{
335362306a36Sopenharmony_ci	struct sctp_bind_addr *bp = &asoc->base.bind_addr;
335462306a36Sopenharmony_ci	union sctp_addr_param *addr_param;
335562306a36Sopenharmony_ci	struct sctp_sockaddr_entry *saddr;
335662306a36Sopenharmony_ci	struct sctp_transport *transport;
335762306a36Sopenharmony_ci	union sctp_addr	addr;
335862306a36Sopenharmony_ci	struct sctp_af *af;
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	addr_param = (void *)asconf_param + sizeof(*asconf_param);
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_ci	/* We have checked the packet before, so we do not check again.	*/
336362306a36Sopenharmony_ci	af = sctp_get_af_specific(param_type2af(addr_param->p.type));
336462306a36Sopenharmony_ci	if (!af->from_addr_param(&addr, addr_param, htons(bp->port), 0))
336562306a36Sopenharmony_ci		return;
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci	switch (asconf_param->param_hdr.type) {
336862306a36Sopenharmony_ci	case SCTP_PARAM_ADD_IP:
336962306a36Sopenharmony_ci		/* This is always done in BH context with a socket lock
337062306a36Sopenharmony_ci		 * held, so the list can not change.
337162306a36Sopenharmony_ci		 */
337262306a36Sopenharmony_ci		local_bh_disable();
337362306a36Sopenharmony_ci		list_for_each_entry(saddr, &bp->address_list, list) {
337462306a36Sopenharmony_ci			if (sctp_cmp_addr_exact(&saddr->a, &addr))
337562306a36Sopenharmony_ci				saddr->state = SCTP_ADDR_SRC;
337662306a36Sopenharmony_ci		}
337762306a36Sopenharmony_ci		local_bh_enable();
337862306a36Sopenharmony_ci		list_for_each_entry(transport, &asoc->peer.transport_addr_list,
337962306a36Sopenharmony_ci				transports) {
338062306a36Sopenharmony_ci			sctp_transport_dst_release(transport);
338162306a36Sopenharmony_ci		}
338262306a36Sopenharmony_ci		break;
338362306a36Sopenharmony_ci	case SCTP_PARAM_DEL_IP:
338462306a36Sopenharmony_ci		local_bh_disable();
338562306a36Sopenharmony_ci		sctp_del_bind_addr(bp, &addr);
338662306a36Sopenharmony_ci		if (asoc->asconf_addr_del_pending != NULL &&
338762306a36Sopenharmony_ci		    sctp_cmp_addr_exact(asoc->asconf_addr_del_pending, &addr)) {
338862306a36Sopenharmony_ci			kfree(asoc->asconf_addr_del_pending);
338962306a36Sopenharmony_ci			asoc->asconf_addr_del_pending = NULL;
339062306a36Sopenharmony_ci		}
339162306a36Sopenharmony_ci		local_bh_enable();
339262306a36Sopenharmony_ci		list_for_each_entry(transport, &asoc->peer.transport_addr_list,
339362306a36Sopenharmony_ci				transports) {
339462306a36Sopenharmony_ci			sctp_transport_dst_release(transport);
339562306a36Sopenharmony_ci		}
339662306a36Sopenharmony_ci		break;
339762306a36Sopenharmony_ci	default:
339862306a36Sopenharmony_ci		break;
339962306a36Sopenharmony_ci	}
340062306a36Sopenharmony_ci}
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci/* Get the corresponding ASCONF response error code from the ASCONF_ACK chunk
340362306a36Sopenharmony_ci * for the given asconf parameter.  If there is no response for this parameter,
340462306a36Sopenharmony_ci * return the error code based on the third argument 'no_err'.
340562306a36Sopenharmony_ci * ADDIP 4.1
340662306a36Sopenharmony_ci * A7) If an error response is received for a TLV parameter, all TLVs with no
340762306a36Sopenharmony_ci * response before the failed TLV are considered successful if not reported.
340862306a36Sopenharmony_ci * All TLVs after the failed response are considered unsuccessful unless a
340962306a36Sopenharmony_ci * specific success indication is present for the parameter.
341062306a36Sopenharmony_ci */
341162306a36Sopenharmony_cistatic __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
341262306a36Sopenharmony_ci				       struct sctp_addip_param *asconf_param,
341362306a36Sopenharmony_ci				       int no_err)
341462306a36Sopenharmony_ci{
341562306a36Sopenharmony_ci	struct sctp_addip_param	*asconf_ack_param;
341662306a36Sopenharmony_ci	struct sctp_errhdr *err_param;
341762306a36Sopenharmony_ci	int asconf_ack_len;
341862306a36Sopenharmony_ci	__be16 err_code;
341962306a36Sopenharmony_ci	int length;
342062306a36Sopenharmony_ci
342162306a36Sopenharmony_ci	if (no_err)
342262306a36Sopenharmony_ci		err_code = SCTP_ERROR_NO_ERROR;
342362306a36Sopenharmony_ci	else
342462306a36Sopenharmony_ci		err_code = SCTP_ERROR_REQ_REFUSED;
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci	asconf_ack_len = ntohs(asconf_ack->chunk_hdr->length) -
342762306a36Sopenharmony_ci			 sizeof(struct sctp_chunkhdr);
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	/* Skip the addiphdr from the asconf_ack chunk and store a pointer to
343062306a36Sopenharmony_ci	 * the first asconf_ack parameter.
343162306a36Sopenharmony_ci	 */
343262306a36Sopenharmony_ci	length = sizeof(struct sctp_addiphdr);
343362306a36Sopenharmony_ci	asconf_ack_param = (struct sctp_addip_param *)(asconf_ack->skb->data +
343462306a36Sopenharmony_ci						       length);
343562306a36Sopenharmony_ci	asconf_ack_len -= length;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	while (asconf_ack_len > 0) {
343862306a36Sopenharmony_ci		if (asconf_ack_param->crr_id == asconf_param->crr_id) {
343962306a36Sopenharmony_ci			switch (asconf_ack_param->param_hdr.type) {
344062306a36Sopenharmony_ci			case SCTP_PARAM_SUCCESS_REPORT:
344162306a36Sopenharmony_ci				return SCTP_ERROR_NO_ERROR;
344262306a36Sopenharmony_ci			case SCTP_PARAM_ERR_CAUSE:
344362306a36Sopenharmony_ci				length = sizeof(*asconf_ack_param);
344462306a36Sopenharmony_ci				err_param = (void *)asconf_ack_param + length;
344562306a36Sopenharmony_ci				asconf_ack_len -= length;
344662306a36Sopenharmony_ci				if (asconf_ack_len > 0)
344762306a36Sopenharmony_ci					return err_param->cause;
344862306a36Sopenharmony_ci				else
344962306a36Sopenharmony_ci					return SCTP_ERROR_INV_PARAM;
345062306a36Sopenharmony_ci				break;
345162306a36Sopenharmony_ci			default:
345262306a36Sopenharmony_ci				return SCTP_ERROR_INV_PARAM;
345362306a36Sopenharmony_ci			}
345462306a36Sopenharmony_ci		}
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci		length = ntohs(asconf_ack_param->param_hdr.length);
345762306a36Sopenharmony_ci		asconf_ack_param = (void *)asconf_ack_param + length;
345862306a36Sopenharmony_ci		asconf_ack_len -= length;
345962306a36Sopenharmony_ci	}
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci	return err_code;
346262306a36Sopenharmony_ci}
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci/* Process an incoming ASCONF_ACK chunk against the cached last ASCONF chunk. */
346562306a36Sopenharmony_ciint sctp_process_asconf_ack(struct sctp_association *asoc,
346662306a36Sopenharmony_ci			    struct sctp_chunk *asconf_ack)
346762306a36Sopenharmony_ci{
346862306a36Sopenharmony_ci	struct sctp_chunk *asconf = asoc->addip_last_asconf;
346962306a36Sopenharmony_ci	struct sctp_addip_param *asconf_param;
347062306a36Sopenharmony_ci	__be16 err_code = SCTP_ERROR_NO_ERROR;
347162306a36Sopenharmony_ci	union sctp_addr_param *addr_param;
347262306a36Sopenharmony_ci	int asconf_len = asconf->skb->len;
347362306a36Sopenharmony_ci	int all_param_pass = 0;
347462306a36Sopenharmony_ci	int length = 0;
347562306a36Sopenharmony_ci	int no_err = 1;
347662306a36Sopenharmony_ci	int retval = 0;
347762306a36Sopenharmony_ci
347862306a36Sopenharmony_ci	/* Skip the chunkhdr and addiphdr from the last asconf sent and store
347962306a36Sopenharmony_ci	 * a pointer to address parameter.
348062306a36Sopenharmony_ci	 */
348162306a36Sopenharmony_ci	length = sizeof(struct sctp_addip_chunk);
348262306a36Sopenharmony_ci	addr_param = (union sctp_addr_param *)(asconf->skb->data + length);
348362306a36Sopenharmony_ci	asconf_len -= length;
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	/* Skip the address parameter in the last asconf sent and store a
348662306a36Sopenharmony_ci	 * pointer to the first asconf parameter.
348762306a36Sopenharmony_ci	 */
348862306a36Sopenharmony_ci	length = ntohs(addr_param->p.length);
348962306a36Sopenharmony_ci	asconf_param = (void *)addr_param + length;
349062306a36Sopenharmony_ci	asconf_len -= length;
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ci	/* ADDIP 4.1
349362306a36Sopenharmony_ci	 * A8) If there is no response(s) to specific TLV parameter(s), and no
349462306a36Sopenharmony_ci	 * failures are indicated, then all request(s) are considered
349562306a36Sopenharmony_ci	 * successful.
349662306a36Sopenharmony_ci	 */
349762306a36Sopenharmony_ci	if (asconf_ack->skb->len == sizeof(struct sctp_addiphdr))
349862306a36Sopenharmony_ci		all_param_pass = 1;
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci	/* Process the TLVs contained in the last sent ASCONF chunk. */
350162306a36Sopenharmony_ci	while (asconf_len > 0) {
350262306a36Sopenharmony_ci		if (all_param_pass)
350362306a36Sopenharmony_ci			err_code = SCTP_ERROR_NO_ERROR;
350462306a36Sopenharmony_ci		else {
350562306a36Sopenharmony_ci			err_code = sctp_get_asconf_response(asconf_ack,
350662306a36Sopenharmony_ci							    asconf_param,
350762306a36Sopenharmony_ci							    no_err);
350862306a36Sopenharmony_ci			if (no_err && (SCTP_ERROR_NO_ERROR != err_code))
350962306a36Sopenharmony_ci				no_err = 0;
351062306a36Sopenharmony_ci		}
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci		switch (err_code) {
351362306a36Sopenharmony_ci		case SCTP_ERROR_NO_ERROR:
351462306a36Sopenharmony_ci			sctp_asconf_param_success(asoc, asconf_param);
351562306a36Sopenharmony_ci			break;
351662306a36Sopenharmony_ci
351762306a36Sopenharmony_ci		case SCTP_ERROR_RSRC_LOW:
351862306a36Sopenharmony_ci			retval = 1;
351962306a36Sopenharmony_ci			break;
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci		case SCTP_ERROR_UNKNOWN_PARAM:
352262306a36Sopenharmony_ci			/* Disable sending this type of asconf parameter in
352362306a36Sopenharmony_ci			 * future.
352462306a36Sopenharmony_ci			 */
352562306a36Sopenharmony_ci			asoc->peer.addip_disabled_mask |=
352662306a36Sopenharmony_ci				asconf_param->param_hdr.type;
352762306a36Sopenharmony_ci			break;
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_ci		case SCTP_ERROR_REQ_REFUSED:
353062306a36Sopenharmony_ci		case SCTP_ERROR_DEL_LAST_IP:
353162306a36Sopenharmony_ci		case SCTP_ERROR_DEL_SRC_IP:
353262306a36Sopenharmony_ci		default:
353362306a36Sopenharmony_ci			 break;
353462306a36Sopenharmony_ci		}
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci		/* Skip the processed asconf parameter and move to the next
353762306a36Sopenharmony_ci		 * one.
353862306a36Sopenharmony_ci		 */
353962306a36Sopenharmony_ci		length = ntohs(asconf_param->param_hdr.length);
354062306a36Sopenharmony_ci		asconf_param = (void *)asconf_param + length;
354162306a36Sopenharmony_ci		asconf_len -= length;
354262306a36Sopenharmony_ci	}
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	if (no_err && asoc->src_out_of_asoc_ok) {
354562306a36Sopenharmony_ci		asoc->src_out_of_asoc_ok = 0;
354662306a36Sopenharmony_ci		sctp_transport_immediate_rtx(asoc->peer.primary_path);
354762306a36Sopenharmony_ci	}
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	/* Free the cached last sent asconf chunk. */
355062306a36Sopenharmony_ci	list_del_init(&asconf->transmitted_list);
355162306a36Sopenharmony_ci	sctp_chunk_free(asconf);
355262306a36Sopenharmony_ci	asoc->addip_last_asconf = NULL;
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci	return retval;
355562306a36Sopenharmony_ci}
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci/* Make a FWD TSN chunk. */
355862306a36Sopenharmony_cistruct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
355962306a36Sopenharmony_ci				    __u32 new_cum_tsn, size_t nstreams,
356062306a36Sopenharmony_ci				    struct sctp_fwdtsn_skip *skiplist)
356162306a36Sopenharmony_ci{
356262306a36Sopenharmony_ci	struct sctp_chunk *retval = NULL;
356362306a36Sopenharmony_ci	struct sctp_fwdtsn_hdr ftsn_hdr;
356462306a36Sopenharmony_ci	struct sctp_fwdtsn_skip skip;
356562306a36Sopenharmony_ci	size_t hint;
356662306a36Sopenharmony_ci	int i;
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci	hint = (nstreams + 1) * sizeof(__u32);
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint, GFP_ATOMIC);
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci	if (!retval)
357362306a36Sopenharmony_ci		return NULL;
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci	ftsn_hdr.new_cum_tsn = htonl(new_cum_tsn);
357662306a36Sopenharmony_ci	retval->subh.fwdtsn_hdr =
357762306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(ftsn_hdr), &ftsn_hdr);
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci	for (i = 0; i < nstreams; i++) {
358062306a36Sopenharmony_ci		skip.stream = skiplist[i].stream;
358162306a36Sopenharmony_ci		skip.ssn = skiplist[i].ssn;
358262306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(skip), &skip);
358362306a36Sopenharmony_ci	}
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_ci	return retval;
358662306a36Sopenharmony_ci}
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_cistruct sctp_chunk *sctp_make_ifwdtsn(const struct sctp_association *asoc,
358962306a36Sopenharmony_ci				     __u32 new_cum_tsn, size_t nstreams,
359062306a36Sopenharmony_ci				     struct sctp_ifwdtsn_skip *skiplist)
359162306a36Sopenharmony_ci{
359262306a36Sopenharmony_ci	struct sctp_chunk *retval = NULL;
359362306a36Sopenharmony_ci	struct sctp_ifwdtsn_hdr ftsn_hdr;
359462306a36Sopenharmony_ci	size_t hint;
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci	hint = (nstreams + 1) * sizeof(__u32);
359762306a36Sopenharmony_ci
359862306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_I_FWD_TSN, 0, hint,
359962306a36Sopenharmony_ci				   GFP_ATOMIC);
360062306a36Sopenharmony_ci	if (!retval)
360162306a36Sopenharmony_ci		return NULL;
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci	ftsn_hdr.new_cum_tsn = htonl(new_cum_tsn);
360462306a36Sopenharmony_ci	retval->subh.ifwdtsn_hdr =
360562306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(ftsn_hdr), &ftsn_hdr);
360662306a36Sopenharmony_ci
360762306a36Sopenharmony_ci	sctp_addto_chunk(retval, nstreams * sizeof(skiplist[0]), skiplist);
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci	return retval;
361062306a36Sopenharmony_ci}
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci/* RE-CONFIG 3.1 (RE-CONFIG chunk)
361362306a36Sopenharmony_ci *   0                   1                   2                   3
361462306a36Sopenharmony_ci *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
361562306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
361662306a36Sopenharmony_ci *  | Type = 130    |  Chunk Flags  |      Chunk Length             |
361762306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
361862306a36Sopenharmony_ci *  \                                                               \
361962306a36Sopenharmony_ci *  /                  Re-configuration Parameter                   /
362062306a36Sopenharmony_ci *  \                                                               \
362162306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
362262306a36Sopenharmony_ci *  \                                                               \
362362306a36Sopenharmony_ci *  /             Re-configuration Parameter (optional)             /
362462306a36Sopenharmony_ci *  \                                                               \
362562306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
362662306a36Sopenharmony_ci */
362762306a36Sopenharmony_cistatic struct sctp_chunk *sctp_make_reconf(const struct sctp_association *asoc,
362862306a36Sopenharmony_ci					   int length)
362962306a36Sopenharmony_ci{
363062306a36Sopenharmony_ci	struct sctp_reconf_chunk *reconf;
363162306a36Sopenharmony_ci	struct sctp_chunk *retval;
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	retval = sctp_make_control(asoc, SCTP_CID_RECONF, 0, length,
363462306a36Sopenharmony_ci				   GFP_ATOMIC);
363562306a36Sopenharmony_ci	if (!retval)
363662306a36Sopenharmony_ci		return NULL;
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci	reconf = (struct sctp_reconf_chunk *)retval->chunk_hdr;
363962306a36Sopenharmony_ci	retval->param_hdr.v = (u8 *)(reconf + 1);
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_ci	return retval;
364262306a36Sopenharmony_ci}
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci/* RE-CONFIG 4.1 (STREAM OUT RESET)
364562306a36Sopenharmony_ci *   0                   1                   2                   3
364662306a36Sopenharmony_ci *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
364762306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
364862306a36Sopenharmony_ci *  |     Parameter Type = 13       | Parameter Length = 16 + 2 * N |
364962306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365062306a36Sopenharmony_ci *  |           Re-configuration Request Sequence Number            |
365162306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365262306a36Sopenharmony_ci *  |           Re-configuration Response Sequence Number           |
365362306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365462306a36Sopenharmony_ci *  |                Sender's Last Assigned TSN                     |
365562306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365662306a36Sopenharmony_ci *  |  Stream Number 1 (optional)   |    Stream Number 2 (optional) |
365762306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365862306a36Sopenharmony_ci *  /                            ......                             /
365962306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366062306a36Sopenharmony_ci *  |  Stream Number N-1 (optional) |    Stream Number N (optional) |
366162306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366262306a36Sopenharmony_ci *
366362306a36Sopenharmony_ci * RE-CONFIG 4.2 (STREAM IN RESET)
366462306a36Sopenharmony_ci *   0                   1                   2                   3
366562306a36Sopenharmony_ci *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
366662306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366762306a36Sopenharmony_ci *  |     Parameter Type = 14       |  Parameter Length = 8 + 2 * N |
366862306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366962306a36Sopenharmony_ci *  |          Re-configuration Request Sequence Number             |
367062306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367162306a36Sopenharmony_ci *  |  Stream Number 1 (optional)   |    Stream Number 2 (optional) |
367262306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367362306a36Sopenharmony_ci *  /                            ......                             /
367462306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367562306a36Sopenharmony_ci *  |  Stream Number N-1 (optional) |    Stream Number N (optional) |
367662306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367762306a36Sopenharmony_ci */
367862306a36Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_req(
367962306a36Sopenharmony_ci					const struct sctp_association *asoc,
368062306a36Sopenharmony_ci					__u16 stream_num, __be16 *stream_list,
368162306a36Sopenharmony_ci					bool out, bool in)
368262306a36Sopenharmony_ci{
368362306a36Sopenharmony_ci	__u16 stream_len = stream_num * sizeof(__u16);
368462306a36Sopenharmony_ci	struct sctp_strreset_outreq outreq;
368562306a36Sopenharmony_ci	struct sctp_strreset_inreq inreq;
368662306a36Sopenharmony_ci	struct sctp_chunk *retval;
368762306a36Sopenharmony_ci	__u16 outlen, inlen;
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ci	outlen = (sizeof(outreq) + stream_len) * out;
369062306a36Sopenharmony_ci	inlen = (sizeof(inreq) + stream_len) * in;
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci	retval = sctp_make_reconf(asoc, SCTP_PAD4(outlen) + SCTP_PAD4(inlen));
369362306a36Sopenharmony_ci	if (!retval)
369462306a36Sopenharmony_ci		return NULL;
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci	if (outlen) {
369762306a36Sopenharmony_ci		outreq.param_hdr.type = SCTP_PARAM_RESET_OUT_REQUEST;
369862306a36Sopenharmony_ci		outreq.param_hdr.length = htons(outlen);
369962306a36Sopenharmony_ci		outreq.request_seq = htonl(asoc->strreset_outseq);
370062306a36Sopenharmony_ci		outreq.response_seq = htonl(asoc->strreset_inseq - 1);
370162306a36Sopenharmony_ci		outreq.send_reset_at_tsn = htonl(asoc->next_tsn - 1);
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(outreq), &outreq);
370462306a36Sopenharmony_ci
370562306a36Sopenharmony_ci		if (stream_len)
370662306a36Sopenharmony_ci			sctp_addto_chunk(retval, stream_len, stream_list);
370762306a36Sopenharmony_ci	}
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	if (inlen) {
371062306a36Sopenharmony_ci		inreq.param_hdr.type = SCTP_PARAM_RESET_IN_REQUEST;
371162306a36Sopenharmony_ci		inreq.param_hdr.length = htons(inlen);
371262306a36Sopenharmony_ci		inreq.request_seq = htonl(asoc->strreset_outseq + out);
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci		sctp_addto_chunk(retval, sizeof(inreq), &inreq);
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci		if (stream_len)
371762306a36Sopenharmony_ci			sctp_addto_chunk(retval, stream_len, stream_list);
371862306a36Sopenharmony_ci	}
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci	return retval;
372162306a36Sopenharmony_ci}
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci/* RE-CONFIG 4.3 (SSN/TSN RESET ALL)
372462306a36Sopenharmony_ci *   0                   1                   2                   3
372562306a36Sopenharmony_ci *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
372662306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372762306a36Sopenharmony_ci *  |     Parameter Type = 15       |      Parameter Length = 8     |
372862306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372962306a36Sopenharmony_ci *  |         Re-configuration Request Sequence Number              |
373062306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
373162306a36Sopenharmony_ci */
373262306a36Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_tsnreq(
373362306a36Sopenharmony_ci					const struct sctp_association *asoc)
373462306a36Sopenharmony_ci{
373562306a36Sopenharmony_ci	struct sctp_strreset_tsnreq tsnreq;
373662306a36Sopenharmony_ci	__u16 length = sizeof(tsnreq);
373762306a36Sopenharmony_ci	struct sctp_chunk *retval;
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci	retval = sctp_make_reconf(asoc, length);
374062306a36Sopenharmony_ci	if (!retval)
374162306a36Sopenharmony_ci		return NULL;
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci	tsnreq.param_hdr.type = SCTP_PARAM_RESET_TSN_REQUEST;
374462306a36Sopenharmony_ci	tsnreq.param_hdr.length = htons(length);
374562306a36Sopenharmony_ci	tsnreq.request_seq = htonl(asoc->strreset_outseq);
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci	sctp_addto_chunk(retval, sizeof(tsnreq), &tsnreq);
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_ci	return retval;
375062306a36Sopenharmony_ci}
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci/* RE-CONFIG 4.5/4.6 (ADD STREAM)
375362306a36Sopenharmony_ci *   0                   1                   2                   3
375462306a36Sopenharmony_ci *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
375562306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
375662306a36Sopenharmony_ci *  |     Parameter Type = 17       |      Parameter Length = 12    |
375762306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
375862306a36Sopenharmony_ci *  |          Re-configuration Request Sequence Number             |
375962306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376062306a36Sopenharmony_ci *  |      Number of new streams    |         Reserved              |
376162306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376262306a36Sopenharmony_ci */
376362306a36Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_addstrm(
376462306a36Sopenharmony_ci					const struct sctp_association *asoc,
376562306a36Sopenharmony_ci					__u16 out, __u16 in)
376662306a36Sopenharmony_ci{
376762306a36Sopenharmony_ci	struct sctp_strreset_addstrm addstrm;
376862306a36Sopenharmony_ci	__u16 size = sizeof(addstrm);
376962306a36Sopenharmony_ci	struct sctp_chunk *retval;
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_ci	retval = sctp_make_reconf(asoc, (!!out + !!in) * size);
377262306a36Sopenharmony_ci	if (!retval)
377362306a36Sopenharmony_ci		return NULL;
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_ci	if (out) {
377662306a36Sopenharmony_ci		addstrm.param_hdr.type = SCTP_PARAM_RESET_ADD_OUT_STREAMS;
377762306a36Sopenharmony_ci		addstrm.param_hdr.length = htons(size);
377862306a36Sopenharmony_ci		addstrm.number_of_streams = htons(out);
377962306a36Sopenharmony_ci		addstrm.request_seq = htonl(asoc->strreset_outseq);
378062306a36Sopenharmony_ci		addstrm.reserved = 0;
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci		sctp_addto_chunk(retval, size, &addstrm);
378362306a36Sopenharmony_ci	}
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci	if (in) {
378662306a36Sopenharmony_ci		addstrm.param_hdr.type = SCTP_PARAM_RESET_ADD_IN_STREAMS;
378762306a36Sopenharmony_ci		addstrm.param_hdr.length = htons(size);
378862306a36Sopenharmony_ci		addstrm.number_of_streams = htons(in);
378962306a36Sopenharmony_ci		addstrm.request_seq = htonl(asoc->strreset_outseq + !!out);
379062306a36Sopenharmony_ci		addstrm.reserved = 0;
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci		sctp_addto_chunk(retval, size, &addstrm);
379362306a36Sopenharmony_ci	}
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	return retval;
379662306a36Sopenharmony_ci}
379762306a36Sopenharmony_ci
379862306a36Sopenharmony_ci/* RE-CONFIG 4.4 (RESP)
379962306a36Sopenharmony_ci *   0                   1                   2                   3
380062306a36Sopenharmony_ci *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
380162306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
380262306a36Sopenharmony_ci *  |     Parameter Type = 16       |      Parameter Length         |
380362306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
380462306a36Sopenharmony_ci *  |         Re-configuration Response Sequence Number             |
380562306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
380662306a36Sopenharmony_ci *  |                            Result                             |
380762306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
380862306a36Sopenharmony_ci */
380962306a36Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_resp(const struct sctp_association *asoc,
381062306a36Sopenharmony_ci					   __u32 result, __u32 sn)
381162306a36Sopenharmony_ci{
381262306a36Sopenharmony_ci	struct sctp_strreset_resp resp;
381362306a36Sopenharmony_ci	__u16 length = sizeof(resp);
381462306a36Sopenharmony_ci	struct sctp_chunk *retval;
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci	retval = sctp_make_reconf(asoc, length);
381762306a36Sopenharmony_ci	if (!retval)
381862306a36Sopenharmony_ci		return NULL;
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ci	resp.param_hdr.type = SCTP_PARAM_RESET_RESPONSE;
382162306a36Sopenharmony_ci	resp.param_hdr.length = htons(length);
382262306a36Sopenharmony_ci	resp.response_seq = htonl(sn);
382362306a36Sopenharmony_ci	resp.result = htonl(result);
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci	sctp_addto_chunk(retval, sizeof(resp), &resp);
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_ci	return retval;
382862306a36Sopenharmony_ci}
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_ci/* RE-CONFIG 4.4 OPTIONAL (TSNRESP)
383162306a36Sopenharmony_ci *   0                   1                   2                   3
383262306a36Sopenharmony_ci *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
383362306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383462306a36Sopenharmony_ci *  |     Parameter Type = 16       |      Parameter Length         |
383562306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383662306a36Sopenharmony_ci *  |         Re-configuration Response Sequence Number             |
383762306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383862306a36Sopenharmony_ci *  |                            Result                             |
383962306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
384062306a36Sopenharmony_ci *  |                   Sender's Next TSN (optional)                |
384162306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
384262306a36Sopenharmony_ci *  |                  Receiver's Next TSN (optional)               |
384362306a36Sopenharmony_ci *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
384462306a36Sopenharmony_ci */
384562306a36Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_tsnresp(struct sctp_association *asoc,
384662306a36Sopenharmony_ci					      __u32 result, __u32 sn,
384762306a36Sopenharmony_ci					      __u32 sender_tsn,
384862306a36Sopenharmony_ci					      __u32 receiver_tsn)
384962306a36Sopenharmony_ci{
385062306a36Sopenharmony_ci	struct sctp_strreset_resptsn tsnresp;
385162306a36Sopenharmony_ci	__u16 length = sizeof(tsnresp);
385262306a36Sopenharmony_ci	struct sctp_chunk *retval;
385362306a36Sopenharmony_ci
385462306a36Sopenharmony_ci	retval = sctp_make_reconf(asoc, length);
385562306a36Sopenharmony_ci	if (!retval)
385662306a36Sopenharmony_ci		return NULL;
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_ci	tsnresp.param_hdr.type = SCTP_PARAM_RESET_RESPONSE;
385962306a36Sopenharmony_ci	tsnresp.param_hdr.length = htons(length);
386062306a36Sopenharmony_ci
386162306a36Sopenharmony_ci	tsnresp.response_seq = htonl(sn);
386262306a36Sopenharmony_ci	tsnresp.result = htonl(result);
386362306a36Sopenharmony_ci	tsnresp.senders_next_tsn = htonl(sender_tsn);
386462306a36Sopenharmony_ci	tsnresp.receivers_next_tsn = htonl(receiver_tsn);
386562306a36Sopenharmony_ci
386662306a36Sopenharmony_ci	sctp_addto_chunk(retval, sizeof(tsnresp), &tsnresp);
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci	return retval;
386962306a36Sopenharmony_ci}
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_cibool sctp_verify_reconf(const struct sctp_association *asoc,
387262306a36Sopenharmony_ci			struct sctp_chunk *chunk,
387362306a36Sopenharmony_ci			struct sctp_paramhdr **errp)
387462306a36Sopenharmony_ci{
387562306a36Sopenharmony_ci	struct sctp_reconf_chunk *hdr;
387662306a36Sopenharmony_ci	union sctp_params param;
387762306a36Sopenharmony_ci	__be16 last = 0;
387862306a36Sopenharmony_ci	__u16 cnt = 0;
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_ci	hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
388162306a36Sopenharmony_ci	sctp_walk_params(param, hdr) {
388262306a36Sopenharmony_ci		__u16 length = ntohs(param.p->length);
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci		*errp = param.p;
388562306a36Sopenharmony_ci		if (cnt++ > 2)
388662306a36Sopenharmony_ci			return false;
388762306a36Sopenharmony_ci		switch (param.p->type) {
388862306a36Sopenharmony_ci		case SCTP_PARAM_RESET_OUT_REQUEST:
388962306a36Sopenharmony_ci			if (length < sizeof(struct sctp_strreset_outreq) ||
389062306a36Sopenharmony_ci			    (last && last != SCTP_PARAM_RESET_RESPONSE &&
389162306a36Sopenharmony_ci			     last != SCTP_PARAM_RESET_IN_REQUEST))
389262306a36Sopenharmony_ci				return false;
389362306a36Sopenharmony_ci			break;
389462306a36Sopenharmony_ci		case SCTP_PARAM_RESET_IN_REQUEST:
389562306a36Sopenharmony_ci			if (length < sizeof(struct sctp_strreset_inreq) ||
389662306a36Sopenharmony_ci			    (last && last != SCTP_PARAM_RESET_OUT_REQUEST))
389762306a36Sopenharmony_ci				return false;
389862306a36Sopenharmony_ci			break;
389962306a36Sopenharmony_ci		case SCTP_PARAM_RESET_RESPONSE:
390062306a36Sopenharmony_ci			if ((length != sizeof(struct sctp_strreset_resp) &&
390162306a36Sopenharmony_ci			     length != sizeof(struct sctp_strreset_resptsn)) ||
390262306a36Sopenharmony_ci			    (last && last != SCTP_PARAM_RESET_RESPONSE &&
390362306a36Sopenharmony_ci			     last != SCTP_PARAM_RESET_OUT_REQUEST))
390462306a36Sopenharmony_ci				return false;
390562306a36Sopenharmony_ci			break;
390662306a36Sopenharmony_ci		case SCTP_PARAM_RESET_TSN_REQUEST:
390762306a36Sopenharmony_ci			if (length !=
390862306a36Sopenharmony_ci			    sizeof(struct sctp_strreset_tsnreq) || last)
390962306a36Sopenharmony_ci				return false;
391062306a36Sopenharmony_ci			break;
391162306a36Sopenharmony_ci		case SCTP_PARAM_RESET_ADD_IN_STREAMS:
391262306a36Sopenharmony_ci			if (length != sizeof(struct sctp_strreset_addstrm) ||
391362306a36Sopenharmony_ci			    (last && last != SCTP_PARAM_RESET_ADD_OUT_STREAMS))
391462306a36Sopenharmony_ci				return false;
391562306a36Sopenharmony_ci			break;
391662306a36Sopenharmony_ci		case SCTP_PARAM_RESET_ADD_OUT_STREAMS:
391762306a36Sopenharmony_ci			if (length != sizeof(struct sctp_strreset_addstrm) ||
391862306a36Sopenharmony_ci			    (last && last != SCTP_PARAM_RESET_ADD_IN_STREAMS))
391962306a36Sopenharmony_ci				return false;
392062306a36Sopenharmony_ci			break;
392162306a36Sopenharmony_ci		default:
392262306a36Sopenharmony_ci			return false;
392362306a36Sopenharmony_ci		}
392462306a36Sopenharmony_ci
392562306a36Sopenharmony_ci		last = param.p->type;
392662306a36Sopenharmony_ci	}
392762306a36Sopenharmony_ci
392862306a36Sopenharmony_ci	return true;
392962306a36Sopenharmony_ci}
3930