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, ¶m); 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, ¶m); 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), ¶m); 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