18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* SCTP kernel implementation 38c2ecf20Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004 48c2ecf20Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 58c2ecf20Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 68c2ecf20Sopenharmony_ci * Copyright (c) 2001-2002 Intel Corp. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is part of the SCTP kernel implementation 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * These functions work with the state functions in sctp_sm_statefuns.c 118c2ecf20Sopenharmony_ci * to implement the state operations. These functions implement the 128c2ecf20Sopenharmony_ci * steps which require modifying existing data structures. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Please send any bug reports or fixes you make to the 158c2ecf20Sopenharmony_ci * email address(es): 168c2ecf20Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Written or modified by: 198c2ecf20Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 208c2ecf20Sopenharmony_ci * Karl Knutson <karl@athena.chicago.il.us> 218c2ecf20Sopenharmony_ci * C. Robin <chris@hundredacre.ac.uk> 228c2ecf20Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 238c2ecf20Sopenharmony_ci * Xingang Guo <xingang.guo@intel.com> 248c2ecf20Sopenharmony_ci * Dajiang Zhang <dajiang.zhang@nokia.com> 258c2ecf20Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 268c2ecf20Sopenharmony_ci * Daisy Chang <daisyc@us.ibm.com> 278c2ecf20Sopenharmony_ci * Ardelle Fan <ardelle.fan@intel.com> 288c2ecf20Sopenharmony_ci * Kevin Gao <kevin.gao@intel.com> 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <crypto/hash.h> 348c2ecf20Sopenharmony_ci#include <linux/types.h> 358c2ecf20Sopenharmony_ci#include <linux/kernel.h> 368c2ecf20Sopenharmony_ci#include <linux/ip.h> 378c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 388c2ecf20Sopenharmony_ci#include <linux/net.h> 398c2ecf20Sopenharmony_ci#include <linux/inet.h> 408c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci#include <net/sock.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 458c2ecf20Sopenharmony_ci#include <linux/random.h> /* for get_random_bytes */ 468c2ecf20Sopenharmony_ci#include <net/sctp/sctp.h> 478c2ecf20Sopenharmony_ci#include <net/sctp/sm.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, 508c2ecf20Sopenharmony_ci __u8 type, __u8 flags, int paylen, 518c2ecf20Sopenharmony_ci gfp_t gfp); 528c2ecf20Sopenharmony_cistatic struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, 538c2ecf20Sopenharmony_ci __u8 flags, int paylen, gfp_t gfp); 548c2ecf20Sopenharmony_cistatic struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, 558c2ecf20Sopenharmony_ci __u8 type, __u8 flags, int paylen, 568c2ecf20Sopenharmony_ci gfp_t gfp); 578c2ecf20Sopenharmony_cistatic struct sctp_cookie_param *sctp_pack_cookie( 588c2ecf20Sopenharmony_ci const struct sctp_endpoint *ep, 598c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 608c2ecf20Sopenharmony_ci const struct sctp_chunk *init_chunk, 618c2ecf20Sopenharmony_ci int *cookie_len, 628c2ecf20Sopenharmony_ci const __u8 *raw_addrs, int addrs_len); 638c2ecf20Sopenharmony_cistatic int sctp_process_param(struct sctp_association *asoc, 648c2ecf20Sopenharmony_ci union sctp_params param, 658c2ecf20Sopenharmony_ci const union sctp_addr *peer_addr, 668c2ecf20Sopenharmony_ci gfp_t gfp); 678c2ecf20Sopenharmony_cistatic void *sctp_addto_param(struct sctp_chunk *chunk, int len, 688c2ecf20Sopenharmony_ci const void *data); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Control chunk destructor */ 718c2ecf20Sopenharmony_cistatic void sctp_control_release_owner(struct sk_buff *skb) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (chunk->shkey) { 768c2ecf20Sopenharmony_ci struct sctp_shared_key *shkey = chunk->shkey; 778c2ecf20Sopenharmony_ci struct sctp_association *asoc = chunk->asoc; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* refcnt == 2 and !list_empty mean after this release, it's 808c2ecf20Sopenharmony_ci * not being used anywhere, and it's time to notify userland 818c2ecf20Sopenharmony_ci * that this shkey can be freed if it's been deactivated. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci if (shkey->deactivated && !list_empty(&shkey->key_list) && 848c2ecf20Sopenharmony_ci refcount_read(&shkey->refcnt) == 2) { 858c2ecf20Sopenharmony_ci struct sctp_ulpevent *ev; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id, 888c2ecf20Sopenharmony_ci SCTP_AUTH_FREE_KEY, 898c2ecf20Sopenharmony_ci GFP_KERNEL); 908c2ecf20Sopenharmony_ci if (ev) 918c2ecf20Sopenharmony_ci asoc->stream.si->enqueue_event(&asoc->ulpq, ev); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci sctp_auth_shkey_release(chunk->shkey); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void sctp_control_set_owner_w(struct sctp_chunk *chunk) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct sctp_association *asoc = chunk->asoc; 1008c2ecf20Sopenharmony_ci struct sk_buff *skb = chunk->skb; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* TODO: properly account for control chunks. 1038c2ecf20Sopenharmony_ci * To do it right we'll need: 1048c2ecf20Sopenharmony_ci * 1) endpoint if association isn't known. 1058c2ecf20Sopenharmony_ci * 2) proper memory accounting. 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * For now don't do anything for now. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci if (chunk->auth) { 1108c2ecf20Sopenharmony_ci chunk->shkey = asoc->shkey; 1118c2ecf20Sopenharmony_ci sctp_auth_shkey_hold(chunk->shkey); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci skb->sk = asoc ? asoc->base.sk : NULL; 1148c2ecf20Sopenharmony_ci skb_shinfo(skb)->destructor_arg = chunk; 1158c2ecf20Sopenharmony_ci skb->destructor = sctp_control_release_owner; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* What was the inbound interface for this chunk? */ 1198c2ecf20Sopenharmony_ciint sctp_chunk_iif(const struct sctp_chunk *chunk) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct sk_buff *skb = chunk->skb; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return SCTP_INPUT_CB(skb)->af->skb_iif(skb); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* RFC 2960 3.3.2 Initiation (INIT) (1) 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * Note 2: The ECN capable field is reserved for future use of 1298c2ecf20Sopenharmony_ci * Explicit Congestion Notification. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_cistatic const struct sctp_paramhdr ecap_param = { 1328c2ecf20Sopenharmony_ci SCTP_PARAM_ECN_CAPABLE, 1338c2ecf20Sopenharmony_ci cpu_to_be16(sizeof(struct sctp_paramhdr)), 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_cistatic const struct sctp_paramhdr prsctp_param = { 1368c2ecf20Sopenharmony_ci SCTP_PARAM_FWD_TSN_SUPPORT, 1378c2ecf20Sopenharmony_ci cpu_to_be16(sizeof(struct sctp_paramhdr)), 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* A helper to initialize an op error inside a provided chunk, as most 1418c2ecf20Sopenharmony_ci * cause codes will be embedded inside an abort chunk. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ciint sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, 1448c2ecf20Sopenharmony_ci size_t paylen) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct sctp_errhdr err; 1478c2ecf20Sopenharmony_ci __u16 len; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* Cause code constants are now defined in network order. */ 1508c2ecf20Sopenharmony_ci err.cause = cause_code; 1518c2ecf20Sopenharmony_ci len = sizeof(err) + paylen; 1528c2ecf20Sopenharmony_ci err.length = htons(len); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (skb_tailroom(chunk->skb) < len) 1558c2ecf20Sopenharmony_ci return -ENOSPC; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(err), &err); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 3.3.2 Initiation (INIT) (1) 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * This chunk is used to initiate a SCTP association between two 1658c2ecf20Sopenharmony_ci * endpoints. The format of the INIT chunk is shown below: 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * 0 1 2 3 1688c2ecf20Sopenharmony_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 1698c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1708c2ecf20Sopenharmony_ci * | Type = 1 | Chunk Flags | Chunk Length | 1718c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1728c2ecf20Sopenharmony_ci * | Initiate Tag | 1738c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1748c2ecf20Sopenharmony_ci * | Advertised Receiver Window Credit (a_rwnd) | 1758c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1768c2ecf20Sopenharmony_ci * | Number of Outbound Streams | Number of Inbound Streams | 1778c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1788c2ecf20Sopenharmony_ci * | Initial TSN | 1798c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1808c2ecf20Sopenharmony_ci * \ \ 1818c2ecf20Sopenharmony_ci * / Optional/Variable-Length Parameters / 1828c2ecf20Sopenharmony_ci * \ \ 1838c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * The INIT chunk contains the following parameters. Unless otherwise 1878c2ecf20Sopenharmony_ci * noted, each parameter MUST only be included once in the INIT chunk. 1888c2ecf20Sopenharmony_ci * 1898c2ecf20Sopenharmony_ci * Fixed Parameters Status 1908c2ecf20Sopenharmony_ci * ---------------------------------------------- 1918c2ecf20Sopenharmony_ci * Initiate Tag Mandatory 1928c2ecf20Sopenharmony_ci * Advertised Receiver Window Credit Mandatory 1938c2ecf20Sopenharmony_ci * Number of Outbound Streams Mandatory 1948c2ecf20Sopenharmony_ci * Number of Inbound Streams Mandatory 1958c2ecf20Sopenharmony_ci * Initial TSN Mandatory 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * Variable Parameters Status Type Value 1988c2ecf20Sopenharmony_ci * ------------------------------------------------------------- 1998c2ecf20Sopenharmony_ci * IPv4 Address (Note 1) Optional 5 2008c2ecf20Sopenharmony_ci * IPv6 Address (Note 1) Optional 6 2018c2ecf20Sopenharmony_ci * Cookie Preservative Optional 9 2028c2ecf20Sopenharmony_ci * Reserved for ECN Capable (Note 2) Optional 32768 (0x8000) 2038c2ecf20Sopenharmony_ci * Host Name Address (Note 3) Optional 11 2048c2ecf20Sopenharmony_ci * Supported Address Types (Note 4) Optional 12 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, 2078c2ecf20Sopenharmony_ci const struct sctp_bind_addr *bp, 2088c2ecf20Sopenharmony_ci gfp_t gfp, int vparam_len) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct sctp_supported_ext_param ext_param; 2118c2ecf20Sopenharmony_ci struct sctp_adaptation_ind_param aiparam; 2128c2ecf20Sopenharmony_ci struct sctp_paramhdr *auth_chunks = NULL; 2138c2ecf20Sopenharmony_ci struct sctp_paramhdr *auth_hmacs = NULL; 2148c2ecf20Sopenharmony_ci struct sctp_supported_addrs_param sat; 2158c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = asoc->ep; 2168c2ecf20Sopenharmony_ci struct sctp_chunk *retval = NULL; 2178c2ecf20Sopenharmony_ci int num_types, addrs_len = 0; 2188c2ecf20Sopenharmony_ci struct sctp_inithdr init; 2198c2ecf20Sopenharmony_ci union sctp_params addrs; 2208c2ecf20Sopenharmony_ci struct sctp_sock *sp; 2218c2ecf20Sopenharmony_ci __u8 extensions[5]; 2228c2ecf20Sopenharmony_ci size_t chunksize; 2238c2ecf20Sopenharmony_ci __be16 types[2]; 2248c2ecf20Sopenharmony_ci int num_ext = 0; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* RFC 2960 3.3.2 Initiation (INIT) (1) 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * Note 1: The INIT chunks can contain multiple addresses that 2298c2ecf20Sopenharmony_ci * can be IPv4 and/or IPv6 in any combination. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Convert the provided bind address list to raw format. */ 2338c2ecf20Sopenharmony_ci addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci init.init_tag = htonl(asoc->c.my_vtag); 2368c2ecf20Sopenharmony_ci init.a_rwnd = htonl(asoc->rwnd); 2378c2ecf20Sopenharmony_ci init.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); 2388c2ecf20Sopenharmony_ci init.num_inbound_streams = htons(asoc->c.sinit_max_instreams); 2398c2ecf20Sopenharmony_ci init.initial_tsn = htonl(asoc->c.initial_tsn); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* How many address types are needed? */ 2428c2ecf20Sopenharmony_ci sp = sctp_sk(asoc->base.sk); 2438c2ecf20Sopenharmony_ci num_types = sp->pf->supported_addrs(sp, types); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci chunksize = sizeof(init) + addrs_len; 2468c2ecf20Sopenharmony_ci chunksize += SCTP_PAD4(SCTP_SAT_LEN(num_types)); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (asoc->ep->ecn_enable) 2498c2ecf20Sopenharmony_ci chunksize += sizeof(ecap_param); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (asoc->ep->prsctp_enable) 2528c2ecf20Sopenharmony_ci chunksize += sizeof(prsctp_param); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* ADDIP: Section 4.2.7: 2558c2ecf20Sopenharmony_ci * An implementation supporting this extension [ADDIP] MUST list 2568c2ecf20Sopenharmony_ci * the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and 2578c2ecf20Sopenharmony_ci * INIT-ACK parameters. 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci if (asoc->ep->asconf_enable) { 2608c2ecf20Sopenharmony_ci extensions[num_ext] = SCTP_CID_ASCONF; 2618c2ecf20Sopenharmony_ci extensions[num_ext+1] = SCTP_CID_ASCONF_ACK; 2628c2ecf20Sopenharmony_ci num_ext += 2; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (asoc->ep->reconf_enable) { 2668c2ecf20Sopenharmony_ci extensions[num_ext] = SCTP_CID_RECONF; 2678c2ecf20Sopenharmony_ci num_ext += 1; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (sp->adaptation_ind) 2718c2ecf20Sopenharmony_ci chunksize += sizeof(aiparam); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (asoc->ep->intl_enable) { 2748c2ecf20Sopenharmony_ci extensions[num_ext] = SCTP_CID_I_DATA; 2758c2ecf20Sopenharmony_ci num_ext += 1; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci chunksize += vparam_len; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* Account for AUTH related parameters */ 2818c2ecf20Sopenharmony_ci if (ep->auth_enable) { 2828c2ecf20Sopenharmony_ci /* Add random parameter length*/ 2838c2ecf20Sopenharmony_ci chunksize += sizeof(asoc->c.auth_random); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Add HMACS parameter length if any were defined */ 2868c2ecf20Sopenharmony_ci auth_hmacs = (struct sctp_paramhdr *)asoc->c.auth_hmacs; 2878c2ecf20Sopenharmony_ci if (auth_hmacs->length) 2888c2ecf20Sopenharmony_ci chunksize += SCTP_PAD4(ntohs(auth_hmacs->length)); 2898c2ecf20Sopenharmony_ci else 2908c2ecf20Sopenharmony_ci auth_hmacs = NULL; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Add CHUNKS parameter length */ 2938c2ecf20Sopenharmony_ci auth_chunks = (struct sctp_paramhdr *)asoc->c.auth_chunks; 2948c2ecf20Sopenharmony_ci if (auth_chunks->length) 2958c2ecf20Sopenharmony_ci chunksize += SCTP_PAD4(ntohs(auth_chunks->length)); 2968c2ecf20Sopenharmony_ci else 2978c2ecf20Sopenharmony_ci auth_chunks = NULL; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci extensions[num_ext] = SCTP_CID_AUTH; 3008c2ecf20Sopenharmony_ci num_ext += 1; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* If we have any extensions to report, account for that */ 3048c2ecf20Sopenharmony_ci if (num_ext) 3058c2ecf20Sopenharmony_ci chunksize += SCTP_PAD4(sizeof(ext_param) + num_ext); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* RFC 2960 3.3.2 Initiation (INIT) (1) 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * Note 3: An INIT chunk MUST NOT contain more than one Host 3108c2ecf20Sopenharmony_ci * Name address parameter. Moreover, the sender of the INIT 3118c2ecf20Sopenharmony_ci * MUST NOT combine any other address types with the Host Name 3128c2ecf20Sopenharmony_ci * address in the INIT. The receiver of INIT MUST ignore any 3138c2ecf20Sopenharmony_ci * other address types if the Host Name address parameter is 3148c2ecf20Sopenharmony_ci * present in the received INIT chunk. 3158c2ecf20Sopenharmony_ci * 3168c2ecf20Sopenharmony_ci * PLEASE DO NOT FIXME [This version does not support Host Name.] 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize, gfp); 3208c2ecf20Sopenharmony_ci if (!retval) 3218c2ecf20Sopenharmony_ci goto nodata; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci retval->subh.init_hdr = 3248c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(init), &init); 3258c2ecf20Sopenharmony_ci retval->param_hdr.v = 3268c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, addrs_len, addrs.v); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* RFC 2960 3.3.2 Initiation (INIT) (1) 3298c2ecf20Sopenharmony_ci * 3308c2ecf20Sopenharmony_ci * Note 4: This parameter, when present, specifies all the 3318c2ecf20Sopenharmony_ci * address types the sending endpoint can support. The absence 3328c2ecf20Sopenharmony_ci * of this parameter indicates that the sending endpoint can 3338c2ecf20Sopenharmony_ci * support any address type. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci sat.param_hdr.type = SCTP_PARAM_SUPPORTED_ADDRESS_TYPES; 3368c2ecf20Sopenharmony_ci sat.param_hdr.length = htons(SCTP_SAT_LEN(num_types)); 3378c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(sat), &sat); 3388c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, num_types * sizeof(__u16), &types); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (asoc->ep->ecn_enable) 3418c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Add the supported extensions parameter. Be nice and add this 3448c2ecf20Sopenharmony_ci * fist before addiding the parameters for the extensions themselves 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci if (num_ext) { 3478c2ecf20Sopenharmony_ci ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT; 3488c2ecf20Sopenharmony_ci ext_param.param_hdr.length = htons(sizeof(ext_param) + num_ext); 3498c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(ext_param), &ext_param); 3508c2ecf20Sopenharmony_ci sctp_addto_param(retval, num_ext, extensions); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (asoc->ep->prsctp_enable) 3548c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (sp->adaptation_ind) { 3578c2ecf20Sopenharmony_ci aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND; 3588c2ecf20Sopenharmony_ci aiparam.param_hdr.length = htons(sizeof(aiparam)); 3598c2ecf20Sopenharmony_ci aiparam.adaptation_ind = htonl(sp->adaptation_ind); 3608c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Add SCTP-AUTH chunks to the parameter list */ 3648c2ecf20Sopenharmony_ci if (ep->auth_enable) { 3658c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(asoc->c.auth_random), 3668c2ecf20Sopenharmony_ci asoc->c.auth_random); 3678c2ecf20Sopenharmony_ci if (auth_hmacs) 3688c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, ntohs(auth_hmacs->length), 3698c2ecf20Sopenharmony_ci auth_hmacs); 3708c2ecf20Sopenharmony_ci if (auth_chunks) 3718c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, ntohs(auth_chunks->length), 3728c2ecf20Sopenharmony_ci auth_chunks); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_cinodata: 3758c2ecf20Sopenharmony_ci kfree(addrs.v); 3768c2ecf20Sopenharmony_ci return retval; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, 3808c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk, 3818c2ecf20Sopenharmony_ci gfp_t gfp, int unkparam_len) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct sctp_supported_ext_param ext_param; 3848c2ecf20Sopenharmony_ci struct sctp_adaptation_ind_param aiparam; 3858c2ecf20Sopenharmony_ci struct sctp_paramhdr *auth_chunks = NULL; 3868c2ecf20Sopenharmony_ci struct sctp_paramhdr *auth_random = NULL; 3878c2ecf20Sopenharmony_ci struct sctp_paramhdr *auth_hmacs = NULL; 3888c2ecf20Sopenharmony_ci struct sctp_chunk *retval = NULL; 3898c2ecf20Sopenharmony_ci struct sctp_cookie_param *cookie; 3908c2ecf20Sopenharmony_ci struct sctp_inithdr initack; 3918c2ecf20Sopenharmony_ci union sctp_params addrs; 3928c2ecf20Sopenharmony_ci struct sctp_sock *sp; 3938c2ecf20Sopenharmony_ci __u8 extensions[5]; 3948c2ecf20Sopenharmony_ci size_t chunksize; 3958c2ecf20Sopenharmony_ci int num_ext = 0; 3968c2ecf20Sopenharmony_ci int cookie_len; 3978c2ecf20Sopenharmony_ci int addrs_len; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Note: there may be no addresses to embed. */ 4008c2ecf20Sopenharmony_ci addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci initack.init_tag = htonl(asoc->c.my_vtag); 4038c2ecf20Sopenharmony_ci initack.a_rwnd = htonl(asoc->rwnd); 4048c2ecf20Sopenharmony_ci initack.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); 4058c2ecf20Sopenharmony_ci initack.num_inbound_streams = htons(asoc->c.sinit_max_instreams); 4068c2ecf20Sopenharmony_ci initack.initial_tsn = htonl(asoc->c.initial_tsn); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* FIXME: We really ought to build the cookie right 4098c2ecf20Sopenharmony_ci * into the packet instead of allocating more fresh memory. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci cookie = sctp_pack_cookie(asoc->ep, asoc, chunk, &cookie_len, 4128c2ecf20Sopenharmony_ci addrs.v, addrs_len); 4138c2ecf20Sopenharmony_ci if (!cookie) 4148c2ecf20Sopenharmony_ci goto nomem_cookie; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Calculate the total size of allocation, include the reserved 4178c2ecf20Sopenharmony_ci * space for reporting unknown parameters if it is specified. 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci sp = sctp_sk(asoc->base.sk); 4208c2ecf20Sopenharmony_ci chunksize = sizeof(initack) + addrs_len + cookie_len + unkparam_len; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Tell peer that we'll do ECN only if peer advertised such cap. */ 4238c2ecf20Sopenharmony_ci if (asoc->peer.ecn_capable) 4248c2ecf20Sopenharmony_ci chunksize += sizeof(ecap_param); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (asoc->peer.prsctp_capable) 4278c2ecf20Sopenharmony_ci chunksize += sizeof(prsctp_param); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (asoc->peer.asconf_capable) { 4308c2ecf20Sopenharmony_ci extensions[num_ext] = SCTP_CID_ASCONF; 4318c2ecf20Sopenharmony_ci extensions[num_ext+1] = SCTP_CID_ASCONF_ACK; 4328c2ecf20Sopenharmony_ci num_ext += 2; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (asoc->peer.reconf_capable) { 4368c2ecf20Sopenharmony_ci extensions[num_ext] = SCTP_CID_RECONF; 4378c2ecf20Sopenharmony_ci num_ext += 1; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (sp->adaptation_ind) 4418c2ecf20Sopenharmony_ci chunksize += sizeof(aiparam); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (asoc->peer.intl_capable) { 4448c2ecf20Sopenharmony_ci extensions[num_ext] = SCTP_CID_I_DATA; 4458c2ecf20Sopenharmony_ci num_ext += 1; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (asoc->peer.auth_capable) { 4498c2ecf20Sopenharmony_ci auth_random = (struct sctp_paramhdr *)asoc->c.auth_random; 4508c2ecf20Sopenharmony_ci chunksize += ntohs(auth_random->length); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci auth_hmacs = (struct sctp_paramhdr *)asoc->c.auth_hmacs; 4538c2ecf20Sopenharmony_ci if (auth_hmacs->length) 4548c2ecf20Sopenharmony_ci chunksize += SCTP_PAD4(ntohs(auth_hmacs->length)); 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci auth_hmacs = NULL; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci auth_chunks = (struct sctp_paramhdr *)asoc->c.auth_chunks; 4598c2ecf20Sopenharmony_ci if (auth_chunks->length) 4608c2ecf20Sopenharmony_ci chunksize += SCTP_PAD4(ntohs(auth_chunks->length)); 4618c2ecf20Sopenharmony_ci else 4628c2ecf20Sopenharmony_ci auth_chunks = NULL; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci extensions[num_ext] = SCTP_CID_AUTH; 4658c2ecf20Sopenharmony_ci num_ext += 1; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (num_ext) 4698c2ecf20Sopenharmony_ci chunksize += SCTP_PAD4(sizeof(ext_param) + num_ext); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Now allocate and fill out the chunk. */ 4728c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize, gfp); 4738c2ecf20Sopenharmony_ci if (!retval) 4748c2ecf20Sopenharmony_ci goto nomem_chunk; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 4778c2ecf20Sopenharmony_ci * 4788c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 4798c2ecf20Sopenharmony_ci * HEARTBEAT ACK, * etc.) to the same destination transport 4808c2ecf20Sopenharmony_ci * address from which it received the DATA or control chunk 4818c2ecf20Sopenharmony_ci * to which it is replying. 4828c2ecf20Sopenharmony_ci * 4838c2ecf20Sopenharmony_ci * [INIT ACK back to where the INIT came from.] 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci if (chunk->transport) 4868c2ecf20Sopenharmony_ci retval->transport = 4878c2ecf20Sopenharmony_ci sctp_assoc_lookup_paddr(asoc, 4888c2ecf20Sopenharmony_ci &chunk->transport->ipaddr); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci retval->subh.init_hdr = 4918c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(initack), &initack); 4928c2ecf20Sopenharmony_ci retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v); 4938c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, cookie_len, cookie); 4948c2ecf20Sopenharmony_ci if (asoc->peer.ecn_capable) 4958c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); 4968c2ecf20Sopenharmony_ci if (num_ext) { 4978c2ecf20Sopenharmony_ci ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT; 4988c2ecf20Sopenharmony_ci ext_param.param_hdr.length = htons(sizeof(ext_param) + num_ext); 4998c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(ext_param), &ext_param); 5008c2ecf20Sopenharmony_ci sctp_addto_param(retval, num_ext, extensions); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci if (asoc->peer.prsctp_capable) 5038c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (sp->adaptation_ind) { 5068c2ecf20Sopenharmony_ci aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND; 5078c2ecf20Sopenharmony_ci aiparam.param_hdr.length = htons(sizeof(aiparam)); 5088c2ecf20Sopenharmony_ci aiparam.adaptation_ind = htonl(sp->adaptation_ind); 5098c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (asoc->peer.auth_capable) { 5138c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, ntohs(auth_random->length), 5148c2ecf20Sopenharmony_ci auth_random); 5158c2ecf20Sopenharmony_ci if (auth_hmacs) 5168c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, ntohs(auth_hmacs->length), 5178c2ecf20Sopenharmony_ci auth_hmacs); 5188c2ecf20Sopenharmony_ci if (auth_chunks) 5198c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, ntohs(auth_chunks->length), 5208c2ecf20Sopenharmony_ci auth_chunks); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* We need to remove the const qualifier at this point. */ 5248c2ecf20Sopenharmony_ci retval->asoc = (struct sctp_association *) asoc; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cinomem_chunk: 5278c2ecf20Sopenharmony_ci kfree(cookie); 5288c2ecf20Sopenharmony_cinomem_cookie: 5298c2ecf20Sopenharmony_ci kfree(addrs.v); 5308c2ecf20Sopenharmony_ci return retval; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/* 3.3.11 Cookie Echo (COOKIE ECHO) (10): 5348c2ecf20Sopenharmony_ci * 5358c2ecf20Sopenharmony_ci * This chunk is used only during the initialization of an association. 5368c2ecf20Sopenharmony_ci * It is sent by the initiator of an association to its peer to complete 5378c2ecf20Sopenharmony_ci * the initialization process. This chunk MUST precede any DATA chunk 5388c2ecf20Sopenharmony_ci * sent within the association, but MAY be bundled with one or more DATA 5398c2ecf20Sopenharmony_ci * chunks in the same packet. 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci * 0 1 2 3 5428c2ecf20Sopenharmony_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 5438c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5448c2ecf20Sopenharmony_ci * | Type = 10 |Chunk Flags | Length | 5458c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5468c2ecf20Sopenharmony_ci * / Cookie / 5478c2ecf20Sopenharmony_ci * \ \ 5488c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5498c2ecf20Sopenharmony_ci * 5508c2ecf20Sopenharmony_ci * Chunk Flags: 8 bit 5518c2ecf20Sopenharmony_ci * 5528c2ecf20Sopenharmony_ci * Set to zero on transmit and ignored on receipt. 5538c2ecf20Sopenharmony_ci * 5548c2ecf20Sopenharmony_ci * Length: 16 bits (unsigned integer) 5558c2ecf20Sopenharmony_ci * 5568c2ecf20Sopenharmony_ci * Set to the size of the chunk in bytes, including the 4 bytes of 5578c2ecf20Sopenharmony_ci * the chunk header and the size of the Cookie. 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * Cookie: variable size 5608c2ecf20Sopenharmony_ci * 5618c2ecf20Sopenharmony_ci * This field must contain the exact cookie received in the 5628c2ecf20Sopenharmony_ci * State Cookie parameter from the previous INIT ACK. 5638c2ecf20Sopenharmony_ci * 5648c2ecf20Sopenharmony_ci * An implementation SHOULD make the cookie as small as possible 5658c2ecf20Sopenharmony_ci * to insure interoperability. 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc, 5688c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 5718c2ecf20Sopenharmony_ci int cookie_len; 5728c2ecf20Sopenharmony_ci void *cookie; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci cookie = asoc->peer.cookie; 5758c2ecf20Sopenharmony_ci cookie_len = asoc->peer.cookie_len; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* Build a cookie echo chunk. */ 5788c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0, 5798c2ecf20Sopenharmony_ci cookie_len, GFP_ATOMIC); 5808c2ecf20Sopenharmony_ci if (!retval) 5818c2ecf20Sopenharmony_ci goto nodata; 5828c2ecf20Sopenharmony_ci retval->subh.cookie_hdr = 5838c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, cookie_len, cookie); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 5868c2ecf20Sopenharmony_ci * 5878c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 5888c2ecf20Sopenharmony_ci * HEARTBEAT ACK, * etc.) to the same destination transport 5898c2ecf20Sopenharmony_ci * address from which it * received the DATA or control chunk 5908c2ecf20Sopenharmony_ci * to which it is replying. 5918c2ecf20Sopenharmony_ci * 5928c2ecf20Sopenharmony_ci * [COOKIE ECHO back to where the INIT ACK came from.] 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_ci if (chunk) 5958c2ecf20Sopenharmony_ci retval->transport = chunk->transport; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cinodata: 5988c2ecf20Sopenharmony_ci return retval; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/* 3.3.12 Cookie Acknowledgement (COOKIE ACK) (11): 6028c2ecf20Sopenharmony_ci * 6038c2ecf20Sopenharmony_ci * This chunk is used only during the initialization of an 6048c2ecf20Sopenharmony_ci * association. It is used to acknowledge the receipt of a COOKIE 6058c2ecf20Sopenharmony_ci * ECHO chunk. This chunk MUST precede any DATA or SACK chunk sent 6068c2ecf20Sopenharmony_ci * within the association, but MAY be bundled with one or more DATA 6078c2ecf20Sopenharmony_ci * chunks or SACK chunk in the same SCTP packet. 6088c2ecf20Sopenharmony_ci * 6098c2ecf20Sopenharmony_ci * 0 1 2 3 6108c2ecf20Sopenharmony_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 6118c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6128c2ecf20Sopenharmony_ci * | Type = 11 |Chunk Flags | Length = 4 | 6138c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6148c2ecf20Sopenharmony_ci * 6158c2ecf20Sopenharmony_ci * Chunk Flags: 8 bits 6168c2ecf20Sopenharmony_ci * 6178c2ecf20Sopenharmony_ci * Set to zero on transmit and ignored on receipt. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc, 6208c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0, GFP_ATOMIC); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 6278c2ecf20Sopenharmony_ci * 6288c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 6298c2ecf20Sopenharmony_ci * HEARTBEAT ACK, * etc.) to the same destination transport 6308c2ecf20Sopenharmony_ci * address from which it * received the DATA or control chunk 6318c2ecf20Sopenharmony_ci * to which it is replying. 6328c2ecf20Sopenharmony_ci * 6338c2ecf20Sopenharmony_ci * [COOKIE ACK back to where the COOKIE ECHO came from.] 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci if (retval && chunk && chunk->transport) 6368c2ecf20Sopenharmony_ci retval->transport = 6378c2ecf20Sopenharmony_ci sctp_assoc_lookup_paddr(asoc, 6388c2ecf20Sopenharmony_ci &chunk->transport->ipaddr); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci return retval; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/* 6448c2ecf20Sopenharmony_ci * Appendix A: Explicit Congestion Notification: 6458c2ecf20Sopenharmony_ci * CWR: 6468c2ecf20Sopenharmony_ci * 6478c2ecf20Sopenharmony_ci * RFC 2481 details a specific bit for a sender to send in the header of 6488c2ecf20Sopenharmony_ci * its next outbound TCP segment to indicate to its peer that it has 6498c2ecf20Sopenharmony_ci * reduced its congestion window. This is termed the CWR bit. For 6508c2ecf20Sopenharmony_ci * SCTP the same indication is made by including the CWR chunk. 6518c2ecf20Sopenharmony_ci * This chunk contains one data element, i.e. the TSN number that 6528c2ecf20Sopenharmony_ci * was sent in the ECNE chunk. This element represents the lowest 6538c2ecf20Sopenharmony_ci * TSN number in the datagram that was originally marked with the 6548c2ecf20Sopenharmony_ci * CE bit. 6558c2ecf20Sopenharmony_ci * 6568c2ecf20Sopenharmony_ci * 0 1 2 3 6578c2ecf20Sopenharmony_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 6588c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6598c2ecf20Sopenharmony_ci * | Chunk Type=13 | Flags=00000000| Chunk Length = 8 | 6608c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6618c2ecf20Sopenharmony_ci * | Lowest TSN Number | 6628c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6638c2ecf20Sopenharmony_ci * 6648c2ecf20Sopenharmony_ci * Note: The CWR is considered a Control chunk. 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc, 6678c2ecf20Sopenharmony_ci const __u32 lowest_tsn, 6688c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 6718c2ecf20Sopenharmony_ci struct sctp_cwrhdr cwr; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci cwr.lowest_tsn = htonl(lowest_tsn); 6748c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0, 6758c2ecf20Sopenharmony_ci sizeof(cwr), GFP_ATOMIC); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (!retval) 6788c2ecf20Sopenharmony_ci goto nodata; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci retval->subh.ecn_cwr_hdr = 6818c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(cwr), &cwr); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 6848c2ecf20Sopenharmony_ci * 6858c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 6868c2ecf20Sopenharmony_ci * HEARTBEAT ACK, * etc.) to the same destination transport 6878c2ecf20Sopenharmony_ci * address from which it * received the DATA or control chunk 6888c2ecf20Sopenharmony_ci * to which it is replying. 6898c2ecf20Sopenharmony_ci * 6908c2ecf20Sopenharmony_ci * [Report a reduced congestion window back to where the ECNE 6918c2ecf20Sopenharmony_ci * came from.] 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci if (chunk) 6948c2ecf20Sopenharmony_ci retval->transport = chunk->transport; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cinodata: 6978c2ecf20Sopenharmony_ci return retval; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci/* Make an ECNE chunk. This is a congestion experienced report. */ 7018c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc, 7028c2ecf20Sopenharmony_ci const __u32 lowest_tsn) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 7058c2ecf20Sopenharmony_ci struct sctp_ecnehdr ecne; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci ecne.lowest_tsn = htonl(lowest_tsn); 7088c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0, 7098c2ecf20Sopenharmony_ci sizeof(ecne), GFP_ATOMIC); 7108c2ecf20Sopenharmony_ci if (!retval) 7118c2ecf20Sopenharmony_ci goto nodata; 7128c2ecf20Sopenharmony_ci retval->subh.ecne_hdr = 7138c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(ecne), &ecne); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cinodata: 7168c2ecf20Sopenharmony_ci return retval; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci/* Make a DATA chunk for the given association from the provided 7208c2ecf20Sopenharmony_ci * parameters. However, do not populate the data payload. 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_datafrag_empty(const struct sctp_association *asoc, 7238c2ecf20Sopenharmony_ci const struct sctp_sndrcvinfo *sinfo, 7248c2ecf20Sopenharmony_ci int len, __u8 flags, gfp_t gfp) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 7278c2ecf20Sopenharmony_ci struct sctp_datahdr dp; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* We assign the TSN as LATE as possible, not here when 7308c2ecf20Sopenharmony_ci * creating the chunk. 7318c2ecf20Sopenharmony_ci */ 7328c2ecf20Sopenharmony_ci memset(&dp, 0, sizeof(dp)); 7338c2ecf20Sopenharmony_ci dp.ppid = sinfo->sinfo_ppid; 7348c2ecf20Sopenharmony_ci dp.stream = htons(sinfo->sinfo_stream); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Set the flags for an unordered send. */ 7378c2ecf20Sopenharmony_ci if (sinfo->sinfo_flags & SCTP_UNORDERED) 7388c2ecf20Sopenharmony_ci flags |= SCTP_DATA_UNORDERED; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci retval = sctp_make_data(asoc, flags, sizeof(dp) + len, gfp); 7418c2ecf20Sopenharmony_ci if (!retval) 7428c2ecf20Sopenharmony_ci return NULL; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp); 7458c2ecf20Sopenharmony_ci memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo)); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci return retval; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci/* Create a selective ackowledgement (SACK) for the given 7518c2ecf20Sopenharmony_ci * association. This reports on which TSN's we've seen to date, 7528c2ecf20Sopenharmony_ci * including duplicates and gaps. 7538c2ecf20Sopenharmony_ci */ 7548c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_sack(struct sctp_association *asoc) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; 7578c2ecf20Sopenharmony_ci struct sctp_gap_ack_block gabs[SCTP_MAX_GABS]; 7588c2ecf20Sopenharmony_ci __u16 num_gabs, num_dup_tsns; 7598c2ecf20Sopenharmony_ci struct sctp_transport *trans; 7608c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 7618c2ecf20Sopenharmony_ci struct sctp_sackhdr sack; 7628c2ecf20Sopenharmony_ci __u32 ctsn; 7638c2ecf20Sopenharmony_ci int len; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci memset(gabs, 0, sizeof(gabs)); 7668c2ecf20Sopenharmony_ci ctsn = sctp_tsnmap_get_ctsn(map); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci pr_debug("%s: sackCTSNAck sent:0x%x\n", __func__, ctsn); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* How much room is needed in the chunk? */ 7718c2ecf20Sopenharmony_ci num_gabs = sctp_tsnmap_num_gabs(map, gabs); 7728c2ecf20Sopenharmony_ci num_dup_tsns = sctp_tsnmap_num_dups(map); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Initialize the SACK header. */ 7758c2ecf20Sopenharmony_ci sack.cum_tsn_ack = htonl(ctsn); 7768c2ecf20Sopenharmony_ci sack.a_rwnd = htonl(asoc->a_rwnd); 7778c2ecf20Sopenharmony_ci sack.num_gap_ack_blocks = htons(num_gabs); 7788c2ecf20Sopenharmony_ci sack.num_dup_tsns = htons(num_dup_tsns); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci len = sizeof(sack) 7818c2ecf20Sopenharmony_ci + sizeof(struct sctp_gap_ack_block) * num_gabs 7828c2ecf20Sopenharmony_ci + sizeof(__u32) * num_dup_tsns; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* Create the chunk. */ 7858c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len, GFP_ATOMIC); 7868c2ecf20Sopenharmony_ci if (!retval) 7878c2ecf20Sopenharmony_ci goto nodata; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 7908c2ecf20Sopenharmony_ci * 7918c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 7928c2ecf20Sopenharmony_ci * HEARTBEAT ACK, etc.) to the same destination transport 7938c2ecf20Sopenharmony_ci * address from which it received the DATA or control chunk to 7948c2ecf20Sopenharmony_ci * which it is replying. This rule should also be followed if 7958c2ecf20Sopenharmony_ci * the endpoint is bundling DATA chunks together with the 7968c2ecf20Sopenharmony_ci * reply chunk. 7978c2ecf20Sopenharmony_ci * 7988c2ecf20Sopenharmony_ci * However, when acknowledging multiple DATA chunks received 7998c2ecf20Sopenharmony_ci * in packets from different source addresses in a single 8008c2ecf20Sopenharmony_ci * SACK, the SACK chunk may be transmitted to one of the 8018c2ecf20Sopenharmony_ci * destination transport addresses from which the DATA or 8028c2ecf20Sopenharmony_ci * control chunks being acknowledged were received. 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci * [BUG: We do not implement the following paragraph. 8058c2ecf20Sopenharmony_ci * Perhaps we should remember the last transport we used for a 8068c2ecf20Sopenharmony_ci * SACK and avoid that (if possible) if we have seen any 8078c2ecf20Sopenharmony_ci * duplicates. --piggy] 8088c2ecf20Sopenharmony_ci * 8098c2ecf20Sopenharmony_ci * When a receiver of a duplicate DATA chunk sends a SACK to a 8108c2ecf20Sopenharmony_ci * multi- homed endpoint it MAY be beneficial to vary the 8118c2ecf20Sopenharmony_ci * destination address and not use the source address of the 8128c2ecf20Sopenharmony_ci * DATA chunk. The reason being that receiving a duplicate 8138c2ecf20Sopenharmony_ci * from a multi-homed endpoint might indicate that the return 8148c2ecf20Sopenharmony_ci * path (as specified in the source address of the DATA chunk) 8158c2ecf20Sopenharmony_ci * for the SACK is broken. 8168c2ecf20Sopenharmony_ci * 8178c2ecf20Sopenharmony_ci * [Send to the address from which we last received a DATA chunk.] 8188c2ecf20Sopenharmony_ci */ 8198c2ecf20Sopenharmony_ci retval->transport = asoc->peer.last_data_from; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci retval->subh.sack_hdr = 8228c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(sack), &sack); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* Add the gap ack block information. */ 8258c2ecf20Sopenharmony_ci if (num_gabs) 8268c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(__u32) * num_gabs, 8278c2ecf20Sopenharmony_ci gabs); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* Add the duplicate TSN information. */ 8308c2ecf20Sopenharmony_ci if (num_dup_tsns) { 8318c2ecf20Sopenharmony_ci asoc->stats.idupchunks += num_dup_tsns; 8328c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns, 8338c2ecf20Sopenharmony_ci sctp_tsnmap_get_dups(map)); 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci /* Once we have a sack generated, check to see what our sack 8368c2ecf20Sopenharmony_ci * generation is, if its 0, reset the transports to 0, and reset 8378c2ecf20Sopenharmony_ci * the association generation to 1 8388c2ecf20Sopenharmony_ci * 8398c2ecf20Sopenharmony_ci * The idea is that zero is never used as a valid generation for the 8408c2ecf20Sopenharmony_ci * association so no transport will match after a wrap event like this, 8418c2ecf20Sopenharmony_ci * Until the next sack 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci if (++asoc->peer.sack_generation == 0) { 8448c2ecf20Sopenharmony_ci list_for_each_entry(trans, &asoc->peer.transport_addr_list, 8458c2ecf20Sopenharmony_ci transports) 8468c2ecf20Sopenharmony_ci trans->sack_generation = 0; 8478c2ecf20Sopenharmony_ci asoc->peer.sack_generation = 1; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_cinodata: 8508c2ecf20Sopenharmony_ci return retval; 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci/* Make a SHUTDOWN chunk. */ 8548c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, 8558c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci struct sctp_shutdownhdr shut; 8588c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 8598c2ecf20Sopenharmony_ci __u32 ctsn; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (chunk && chunk->asoc) 8628c2ecf20Sopenharmony_ci ctsn = sctp_tsnmap_get_ctsn(&chunk->asoc->peer.tsn_map); 8638c2ecf20Sopenharmony_ci else 8648c2ecf20Sopenharmony_ci ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci shut.cum_tsn_ack = htonl(ctsn); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0, 8698c2ecf20Sopenharmony_ci sizeof(shut), GFP_ATOMIC); 8708c2ecf20Sopenharmony_ci if (!retval) 8718c2ecf20Sopenharmony_ci goto nodata; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci retval->subh.shutdown_hdr = 8748c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(shut), &shut); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (chunk) 8778c2ecf20Sopenharmony_ci retval->transport = chunk->transport; 8788c2ecf20Sopenharmony_cinodata: 8798c2ecf20Sopenharmony_ci return retval; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, 8838c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0, 8888c2ecf20Sopenharmony_ci GFP_ATOMIC); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 8918c2ecf20Sopenharmony_ci * 8928c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 8938c2ecf20Sopenharmony_ci * HEARTBEAT ACK, * etc.) to the same destination transport 8948c2ecf20Sopenharmony_ci * address from which it * received the DATA or control chunk 8958c2ecf20Sopenharmony_ci * to which it is replying. 8968c2ecf20Sopenharmony_ci * 8978c2ecf20Sopenharmony_ci * [ACK back to where the SHUTDOWN came from.] 8988c2ecf20Sopenharmony_ci */ 8998c2ecf20Sopenharmony_ci if (retval && chunk) 9008c2ecf20Sopenharmony_ci retval->transport = chunk->transport; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return retval; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_shutdown_complete( 9068c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 9078c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 9108c2ecf20Sopenharmony_ci __u8 flags = 0; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Set the T-bit if we have no association (vtag will be 9138c2ecf20Sopenharmony_ci * reflected) 9148c2ecf20Sopenharmony_ci */ 9158c2ecf20Sopenharmony_ci flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 9188c2ecf20Sopenharmony_ci 0, GFP_ATOMIC); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 9218c2ecf20Sopenharmony_ci * 9228c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 9238c2ecf20Sopenharmony_ci * HEARTBEAT ACK, * etc.) to the same destination transport 9248c2ecf20Sopenharmony_ci * address from which it * received the DATA or control chunk 9258c2ecf20Sopenharmony_ci * to which it is replying. 9268c2ecf20Sopenharmony_ci * 9278c2ecf20Sopenharmony_ci * [Report SHUTDOWN COMPLETE back to where the SHUTDOWN ACK 9288c2ecf20Sopenharmony_ci * came from.] 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_ci if (retval && chunk) 9318c2ecf20Sopenharmony_ci retval->transport = chunk->transport; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci return retval; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci/* Create an ABORT. Note that we set the T bit if we have no 9378c2ecf20Sopenharmony_ci * association, except when responding to an INIT (sctpimpguide 2.41). 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc, 9408c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk, 9418c2ecf20Sopenharmony_ci const size_t hint) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 9448c2ecf20Sopenharmony_ci __u8 flags = 0; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci /* Set the T-bit if we have no association and 'chunk' is not 9478c2ecf20Sopenharmony_ci * an INIT (vtag will be reflected). 9488c2ecf20Sopenharmony_ci */ 9498c2ecf20Sopenharmony_ci if (!asoc) { 9508c2ecf20Sopenharmony_ci if (chunk && chunk->chunk_hdr && 9518c2ecf20Sopenharmony_ci chunk->chunk_hdr->type == SCTP_CID_INIT) 9528c2ecf20Sopenharmony_ci flags = 0; 9538c2ecf20Sopenharmony_ci else 9548c2ecf20Sopenharmony_ci flags = SCTP_CHUNK_FLAG_T; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint, 9588c2ecf20Sopenharmony_ci GFP_ATOMIC); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 9638c2ecf20Sopenharmony_ci * HEARTBEAT ACK, * etc.) to the same destination transport 9648c2ecf20Sopenharmony_ci * address from which it * received the DATA or control chunk 9658c2ecf20Sopenharmony_ci * to which it is replying. 9668c2ecf20Sopenharmony_ci * 9678c2ecf20Sopenharmony_ci * [ABORT back to where the offender came from.] 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_ci if (retval && chunk) 9708c2ecf20Sopenharmony_ci retval->transport = chunk->transport; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return retval; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci/* Helper to create ABORT with a NO_USER_DATA error. */ 9768c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_abort_no_data( 9778c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 9788c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk, 9798c2ecf20Sopenharmony_ci __u32 tsn) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 9828c2ecf20Sopenharmony_ci __be32 payload; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci retval = sctp_make_abort(asoc, chunk, 9858c2ecf20Sopenharmony_ci sizeof(struct sctp_errhdr) + sizeof(tsn)); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (!retval) 9888c2ecf20Sopenharmony_ci goto no_mem; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* Put the tsn back into network byte order. */ 9918c2ecf20Sopenharmony_ci payload = htonl(tsn); 9928c2ecf20Sopenharmony_ci sctp_init_cause(retval, SCTP_ERROR_NO_DATA, sizeof(payload)); 9938c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(payload), (const void *)&payload); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 9968c2ecf20Sopenharmony_ci * 9978c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 9988c2ecf20Sopenharmony_ci * HEARTBEAT ACK, * etc.) to the same destination transport 9998c2ecf20Sopenharmony_ci * address from which it * received the DATA or control chunk 10008c2ecf20Sopenharmony_ci * to which it is replying. 10018c2ecf20Sopenharmony_ci * 10028c2ecf20Sopenharmony_ci * [ABORT back to where the offender came from.] 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_ci if (chunk) 10058c2ecf20Sopenharmony_ci retval->transport = chunk->transport; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cino_mem: 10088c2ecf20Sopenharmony_ci return retval; 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci/* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error. */ 10128c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc, 10138c2ecf20Sopenharmony_ci struct msghdr *msg, 10148c2ecf20Sopenharmony_ci size_t paylen) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 10178c2ecf20Sopenharmony_ci void *payload = NULL; 10188c2ecf20Sopenharmony_ci int err; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci retval = sctp_make_abort(asoc, NULL, 10218c2ecf20Sopenharmony_ci sizeof(struct sctp_errhdr) + paylen); 10228c2ecf20Sopenharmony_ci if (!retval) 10238c2ecf20Sopenharmony_ci goto err_chunk; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (paylen) { 10268c2ecf20Sopenharmony_ci /* Put the msg_iov together into payload. */ 10278c2ecf20Sopenharmony_ci payload = kmalloc(paylen, GFP_KERNEL); 10288c2ecf20Sopenharmony_ci if (!payload) 10298c2ecf20Sopenharmony_ci goto err_payload; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci err = memcpy_from_msg(payload, msg, paylen); 10328c2ecf20Sopenharmony_ci if (err < 0) 10338c2ecf20Sopenharmony_ci goto err_copy; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, paylen); 10378c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, paylen, payload); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (paylen) 10408c2ecf20Sopenharmony_ci kfree(payload); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return retval; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cierr_copy: 10458c2ecf20Sopenharmony_ci kfree(payload); 10468c2ecf20Sopenharmony_cierr_payload: 10478c2ecf20Sopenharmony_ci sctp_chunk_free(retval); 10488c2ecf20Sopenharmony_ci retval = NULL; 10498c2ecf20Sopenharmony_cierr_chunk: 10508c2ecf20Sopenharmony_ci return retval; 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci/* Append bytes to the end of a parameter. Will panic if chunk is not big 10548c2ecf20Sopenharmony_ci * enough. 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_cistatic void *sctp_addto_param(struct sctp_chunk *chunk, int len, 10578c2ecf20Sopenharmony_ci const void *data) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci int chunklen = ntohs(chunk->chunk_hdr->length); 10608c2ecf20Sopenharmony_ci void *target; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci target = skb_put(chunk->skb, len); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (data) 10658c2ecf20Sopenharmony_ci memcpy(target, data, len); 10668c2ecf20Sopenharmony_ci else 10678c2ecf20Sopenharmony_ci memset(target, 0, len); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* Adjust the chunk length field. */ 10708c2ecf20Sopenharmony_ci chunk->chunk_hdr->length = htons(chunklen + len); 10718c2ecf20Sopenharmony_ci chunk->chunk_end = skb_tail_pointer(chunk->skb); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci return target; 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci/* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */ 10778c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_abort_violation( 10788c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 10798c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk, 10808c2ecf20Sopenharmony_ci const __u8 *payload, 10818c2ecf20Sopenharmony_ci const size_t paylen) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 10848c2ecf20Sopenharmony_ci struct sctp_paramhdr phdr; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci retval = sctp_make_abort(asoc, chunk, sizeof(struct sctp_errhdr) + 10878c2ecf20Sopenharmony_ci paylen + sizeof(phdr)); 10888c2ecf20Sopenharmony_ci if (!retval) 10898c2ecf20Sopenharmony_ci goto end; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen + 10928c2ecf20Sopenharmony_ci sizeof(phdr)); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci phdr.type = htons(chunk->chunk_hdr->type); 10958c2ecf20Sopenharmony_ci phdr.length = chunk->chunk_hdr->length; 10968c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, paylen, payload); 10978c2ecf20Sopenharmony_ci sctp_addto_param(retval, sizeof(phdr), &phdr); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ciend: 11008c2ecf20Sopenharmony_ci return retval; 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_violation_paramlen( 11048c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 11058c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk, 11068c2ecf20Sopenharmony_ci struct sctp_paramhdr *param) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci static const char error[] = "The following parameter had invalid length:"; 11098c2ecf20Sopenharmony_ci size_t payload_len = sizeof(error) + sizeof(struct sctp_errhdr) + 11108c2ecf20Sopenharmony_ci sizeof(*param); 11118c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci retval = sctp_make_abort(asoc, chunk, payload_len); 11148c2ecf20Sopenharmony_ci if (!retval) 11158c2ecf20Sopenharmony_ci goto nodata; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, 11188c2ecf20Sopenharmony_ci sizeof(error) + sizeof(*param)); 11198c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(error), error); 11208c2ecf20Sopenharmony_ci sctp_addto_param(retval, sizeof(*param), param); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_cinodata: 11238c2ecf20Sopenharmony_ci return retval; 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_violation_max_retrans( 11278c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 11288c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci static const char error[] = "Association exceeded its max_retrans count"; 11318c2ecf20Sopenharmony_ci size_t payload_len = sizeof(error) + sizeof(struct sctp_errhdr); 11328c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci retval = sctp_make_abort(asoc, chunk, payload_len); 11358c2ecf20Sopenharmony_ci if (!retval) 11368c2ecf20Sopenharmony_ci goto nodata; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, sizeof(error)); 11398c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(error), error); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cinodata: 11428c2ecf20Sopenharmony_ci return retval; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci/* Make a HEARTBEAT chunk. */ 11468c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, 11478c2ecf20Sopenharmony_ci const struct sctp_transport *transport) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct sctp_sender_hb_info hbinfo; 11508c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0, 11538c2ecf20Sopenharmony_ci sizeof(hbinfo), GFP_ATOMIC); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (!retval) 11568c2ecf20Sopenharmony_ci goto nodata; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; 11598c2ecf20Sopenharmony_ci hbinfo.param_hdr.length = htons(sizeof(hbinfo)); 11608c2ecf20Sopenharmony_ci hbinfo.daddr = transport->ipaddr; 11618c2ecf20Sopenharmony_ci hbinfo.sent_at = jiffies; 11628c2ecf20Sopenharmony_ci hbinfo.hb_nonce = transport->hb_nonce; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* Cast away the 'const', as this is just telling the chunk 11658c2ecf20Sopenharmony_ci * what transport it belongs to. 11668c2ecf20Sopenharmony_ci */ 11678c2ecf20Sopenharmony_ci retval->transport = (struct sctp_transport *) transport; 11688c2ecf20Sopenharmony_ci retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo), 11698c2ecf20Sopenharmony_ci &hbinfo); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_cinodata: 11728c2ecf20Sopenharmony_ci return retval; 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc, 11768c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk, 11778c2ecf20Sopenharmony_ci const void *payload, 11788c2ecf20Sopenharmony_ci const size_t paylen) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen, 11838c2ecf20Sopenharmony_ci GFP_ATOMIC); 11848c2ecf20Sopenharmony_ci if (!retval) 11858c2ecf20Sopenharmony_ci goto nodata; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 11908c2ecf20Sopenharmony_ci * 11918c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 11928c2ecf20Sopenharmony_ci * HEARTBEAT ACK, * etc.) to the same destination transport 11938c2ecf20Sopenharmony_ci * address from which it * received the DATA or control chunk 11948c2ecf20Sopenharmony_ci * to which it is replying. 11958c2ecf20Sopenharmony_ci * 11968c2ecf20Sopenharmony_ci * [HBACK back to where the HEARTBEAT came from.] 11978c2ecf20Sopenharmony_ci */ 11988c2ecf20Sopenharmony_ci if (chunk) 11998c2ecf20Sopenharmony_ci retval->transport = chunk->transport; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cinodata: 12028c2ecf20Sopenharmony_ci return retval; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci/* Create an Operation Error chunk with the specified space reserved. 12068c2ecf20Sopenharmony_ci * This routine can be used for containing multiple causes in the chunk. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_cistatic struct sctp_chunk *sctp_make_op_error_space( 12098c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 12108c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk, 12118c2ecf20Sopenharmony_ci size_t size) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0, 12168c2ecf20Sopenharmony_ci sizeof(struct sctp_errhdr) + size, 12178c2ecf20Sopenharmony_ci GFP_ATOMIC); 12188c2ecf20Sopenharmony_ci if (!retval) 12198c2ecf20Sopenharmony_ci goto nodata; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-homed SCTP Endpoints 12228c2ecf20Sopenharmony_ci * 12238c2ecf20Sopenharmony_ci * An endpoint SHOULD transmit reply chunks (e.g., SACK, 12248c2ecf20Sopenharmony_ci * HEARTBEAT ACK, etc.) to the same destination transport 12258c2ecf20Sopenharmony_ci * address from which it received the DATA or control chunk 12268c2ecf20Sopenharmony_ci * to which it is replying. 12278c2ecf20Sopenharmony_ci * 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci if (chunk) 12308c2ecf20Sopenharmony_ci retval->transport = chunk->transport; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_cinodata: 12338c2ecf20Sopenharmony_ci return retval; 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci/* Create an Operation Error chunk of a fixed size, specifically, 12378c2ecf20Sopenharmony_ci * min(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT) - overheads. 12388c2ecf20Sopenharmony_ci * This is a helper function to allocate an error chunk for those 12398c2ecf20Sopenharmony_ci * invalid parameter codes in which we may not want to report all the 12408c2ecf20Sopenharmony_ci * errors, if the incoming chunk is large. If it can't fit in a single 12418c2ecf20Sopenharmony_ci * packet, we ignore it. 12428c2ecf20Sopenharmony_ci */ 12438c2ecf20Sopenharmony_cistatic inline struct sctp_chunk *sctp_make_op_error_limited( 12448c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 12458c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci size_t size = SCTP_DEFAULT_MAXSEGMENT; 12488c2ecf20Sopenharmony_ci struct sctp_sock *sp = NULL; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (asoc) { 12518c2ecf20Sopenharmony_ci size = min_t(size_t, size, asoc->pathmtu); 12528c2ecf20Sopenharmony_ci sp = sctp_sk(asoc->base.sk); 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci size = sctp_mtu_payload(sp, size, sizeof(struct sctp_errhdr)); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci return sctp_make_op_error_space(asoc, chunk, size); 12588c2ecf20Sopenharmony_ci} 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci/* Create an Operation Error chunk. */ 12618c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, 12628c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk, 12638c2ecf20Sopenharmony_ci __be16 cause_code, const void *payload, 12648c2ecf20Sopenharmony_ci size_t paylen, size_t reserve_tail) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci retval = sctp_make_op_error_space(asoc, chunk, paylen + reserve_tail); 12698c2ecf20Sopenharmony_ci if (!retval) 12708c2ecf20Sopenharmony_ci goto nodata; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci sctp_init_cause(retval, cause_code, paylen + reserve_tail); 12738c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, paylen, payload); 12748c2ecf20Sopenharmony_ci if (reserve_tail) 12758c2ecf20Sopenharmony_ci sctp_addto_param(retval, reserve_tail, NULL); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cinodata: 12788c2ecf20Sopenharmony_ci return retval; 12798c2ecf20Sopenharmony_ci} 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc, 12828c2ecf20Sopenharmony_ci __u16 key_id) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct sctp_authhdr auth_hdr; 12858c2ecf20Sopenharmony_ci struct sctp_hmac *hmac_desc; 12868c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci /* Get the first hmac that the peer told us to use */ 12898c2ecf20Sopenharmony_ci hmac_desc = sctp_auth_asoc_get_hmac(asoc); 12908c2ecf20Sopenharmony_ci if (unlikely(!hmac_desc)) 12918c2ecf20Sopenharmony_ci return NULL; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0, 12948c2ecf20Sopenharmony_ci hmac_desc->hmac_len + sizeof(auth_hdr), 12958c2ecf20Sopenharmony_ci GFP_ATOMIC); 12968c2ecf20Sopenharmony_ci if (!retval) 12978c2ecf20Sopenharmony_ci return NULL; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci auth_hdr.hmac_id = htons(hmac_desc->hmac_id); 13008c2ecf20Sopenharmony_ci auth_hdr.shkey_id = htons(key_id); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(auth_hdr), 13038c2ecf20Sopenharmony_ci &auth_hdr); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci skb_put_zero(retval->skb, hmac_desc->hmac_len); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci /* Adjust the chunk header to include the empty MAC */ 13088c2ecf20Sopenharmony_ci retval->chunk_hdr->length = 13098c2ecf20Sopenharmony_ci htons(ntohs(retval->chunk_hdr->length) + hmac_desc->hmac_len); 13108c2ecf20Sopenharmony_ci retval->chunk_end = skb_tail_pointer(retval->skb); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci return retval; 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci/******************************************************************** 13178c2ecf20Sopenharmony_ci * 2nd Level Abstractions 13188c2ecf20Sopenharmony_ci ********************************************************************/ 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci/* Turn an skb into a chunk. 13218c2ecf20Sopenharmony_ci * FIXME: Eventually move the structure directly inside the skb->cb[]. 13228c2ecf20Sopenharmony_ci * 13238c2ecf20Sopenharmony_ci * sctpimpguide-05.txt Section 2.8.2 13248c2ecf20Sopenharmony_ci * M1) Each time a new DATA chunk is transmitted 13258c2ecf20Sopenharmony_ci * set the 'TSN.Missing.Report' count for that TSN to 0. The 13268c2ecf20Sopenharmony_ci * 'TSN.Missing.Report' count will be used to determine missing chunks 13278c2ecf20Sopenharmony_ci * and when to fast retransmit. 13288c2ecf20Sopenharmony_ci * 13298c2ecf20Sopenharmony_ci */ 13308c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_chunkify(struct sk_buff *skb, 13318c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 13328c2ecf20Sopenharmony_ci struct sock *sk, gfp_t gfp) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci retval = kmem_cache_zalloc(sctp_chunk_cachep, gfp); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci if (!retval) 13398c2ecf20Sopenharmony_ci goto nodata; 13408c2ecf20Sopenharmony_ci if (!sk) 13418c2ecf20Sopenharmony_ci pr_debug("%s: chunkifying skb:%p w/o an sk\n", __func__, skb); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&retval->list); 13448c2ecf20Sopenharmony_ci retval->skb = skb; 13458c2ecf20Sopenharmony_ci retval->asoc = (struct sctp_association *)asoc; 13468c2ecf20Sopenharmony_ci retval->singleton = 1; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci retval->fast_retransmit = SCTP_CAN_FRTX; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci /* Polish the bead hole. */ 13518c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&retval->transmitted_list); 13528c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&retval->frag_list); 13538c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_INC(chunk); 13548c2ecf20Sopenharmony_ci refcount_set(&retval->refcnt, 1); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_cinodata: 13578c2ecf20Sopenharmony_ci return retval; 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci/* Set chunk->source and dest based on the IP header in chunk->skb. */ 13618c2ecf20Sopenharmony_civoid sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src, 13628c2ecf20Sopenharmony_ci union sctp_addr *dest) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci memcpy(&chunk->source, src, sizeof(union sctp_addr)); 13658c2ecf20Sopenharmony_ci memcpy(&chunk->dest, dest, sizeof(union sctp_addr)); 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci/* Extract the source address from a chunk. */ 13698c2ecf20Sopenharmony_ciconst union sctp_addr *sctp_source(const struct sctp_chunk *chunk) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci /* If we have a known transport, use that. */ 13728c2ecf20Sopenharmony_ci if (chunk->transport) { 13738c2ecf20Sopenharmony_ci return &chunk->transport->ipaddr; 13748c2ecf20Sopenharmony_ci } else { 13758c2ecf20Sopenharmony_ci /* Otherwise, extract it from the IP header. */ 13768c2ecf20Sopenharmony_ci return &chunk->source; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci/* Create a new chunk, setting the type and flags headers from the 13818c2ecf20Sopenharmony_ci * arguments, reserving enough space for a 'paylen' byte payload. 13828c2ecf20Sopenharmony_ci */ 13838c2ecf20Sopenharmony_cistatic struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, 13848c2ecf20Sopenharmony_ci __u8 type, __u8 flags, int paylen, 13858c2ecf20Sopenharmony_ci gfp_t gfp) 13868c2ecf20Sopenharmony_ci{ 13878c2ecf20Sopenharmony_ci struct sctp_chunkhdr *chunk_hdr; 13888c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 13898c2ecf20Sopenharmony_ci struct sk_buff *skb; 13908c2ecf20Sopenharmony_ci struct sock *sk; 13918c2ecf20Sopenharmony_ci int chunklen; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci chunklen = SCTP_PAD4(sizeof(*chunk_hdr) + paylen); 13948c2ecf20Sopenharmony_ci if (chunklen > SCTP_MAX_CHUNK_LEN) 13958c2ecf20Sopenharmony_ci goto nodata; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci /* No need to allocate LL here, as this is only a chunk. */ 13988c2ecf20Sopenharmony_ci skb = alloc_skb(chunklen, gfp); 13998c2ecf20Sopenharmony_ci if (!skb) 14008c2ecf20Sopenharmony_ci goto nodata; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci /* Make room for the chunk header. */ 14038c2ecf20Sopenharmony_ci chunk_hdr = (struct sctp_chunkhdr *)skb_put(skb, sizeof(*chunk_hdr)); 14048c2ecf20Sopenharmony_ci chunk_hdr->type = type; 14058c2ecf20Sopenharmony_ci chunk_hdr->flags = flags; 14068c2ecf20Sopenharmony_ci chunk_hdr->length = htons(sizeof(*chunk_hdr)); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci sk = asoc ? asoc->base.sk : NULL; 14098c2ecf20Sopenharmony_ci retval = sctp_chunkify(skb, asoc, sk, gfp); 14108c2ecf20Sopenharmony_ci if (!retval) { 14118c2ecf20Sopenharmony_ci kfree_skb(skb); 14128c2ecf20Sopenharmony_ci goto nodata; 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci retval->chunk_hdr = chunk_hdr; 14168c2ecf20Sopenharmony_ci retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(*chunk_hdr); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci /* Determine if the chunk needs to be authenticated */ 14198c2ecf20Sopenharmony_ci if (sctp_auth_send_cid(type, asoc)) 14208c2ecf20Sopenharmony_ci retval->auth = 1; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci return retval; 14238c2ecf20Sopenharmony_cinodata: 14248c2ecf20Sopenharmony_ci return NULL; 14258c2ecf20Sopenharmony_ci} 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_cistatic struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, 14288c2ecf20Sopenharmony_ci __u8 flags, int paylen, gfp_t gfp) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen, gfp); 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_idata(const struct sctp_association *asoc, 14348c2ecf20Sopenharmony_ci __u8 flags, int paylen, gfp_t gfp) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci return _sctp_make_chunk(asoc, SCTP_CID_I_DATA, flags, paylen, gfp); 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, 14408c2ecf20Sopenharmony_ci __u8 type, __u8 flags, int paylen, 14418c2ecf20Sopenharmony_ci gfp_t gfp) 14428c2ecf20Sopenharmony_ci{ 14438c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci chunk = _sctp_make_chunk(asoc, type, flags, paylen, gfp); 14468c2ecf20Sopenharmony_ci if (chunk) 14478c2ecf20Sopenharmony_ci sctp_control_set_owner_w(chunk); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci return chunk; 14508c2ecf20Sopenharmony_ci} 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci/* Release the memory occupied by a chunk. */ 14538c2ecf20Sopenharmony_cistatic void sctp_chunk_destroy(struct sctp_chunk *chunk) 14548c2ecf20Sopenharmony_ci{ 14558c2ecf20Sopenharmony_ci BUG_ON(!list_empty(&chunk->list)); 14568c2ecf20Sopenharmony_ci list_del_init(&chunk->transmitted_list); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci consume_skb(chunk->skb); 14598c2ecf20Sopenharmony_ci consume_skb(chunk->auth_chunk); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_DEC(chunk); 14628c2ecf20Sopenharmony_ci kmem_cache_free(sctp_chunk_cachep, chunk); 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci/* Possibly, free the chunk. */ 14668c2ecf20Sopenharmony_civoid sctp_chunk_free(struct sctp_chunk *chunk) 14678c2ecf20Sopenharmony_ci{ 14688c2ecf20Sopenharmony_ci /* Release our reference on the message tracker. */ 14698c2ecf20Sopenharmony_ci if (chunk->msg) 14708c2ecf20Sopenharmony_ci sctp_datamsg_put(chunk->msg); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci sctp_chunk_put(chunk); 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci/* Grab a reference to the chunk. */ 14768c2ecf20Sopenharmony_civoid sctp_chunk_hold(struct sctp_chunk *ch) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci refcount_inc(&ch->refcnt); 14798c2ecf20Sopenharmony_ci} 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci/* Release a reference to the chunk. */ 14828c2ecf20Sopenharmony_civoid sctp_chunk_put(struct sctp_chunk *ch) 14838c2ecf20Sopenharmony_ci{ 14848c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&ch->refcnt)) 14858c2ecf20Sopenharmony_ci sctp_chunk_destroy(ch); 14868c2ecf20Sopenharmony_ci} 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci/* Append bytes to the end of a chunk. Will panic if chunk is not big 14898c2ecf20Sopenharmony_ci * enough. 14908c2ecf20Sopenharmony_ci */ 14918c2ecf20Sopenharmony_civoid *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci int chunklen = ntohs(chunk->chunk_hdr->length); 14948c2ecf20Sopenharmony_ci int padlen = SCTP_PAD4(chunklen) - chunklen; 14958c2ecf20Sopenharmony_ci void *target; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci skb_put_zero(chunk->skb, padlen); 14988c2ecf20Sopenharmony_ci target = skb_put_data(chunk->skb, data, len); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci /* Adjust the chunk length field. */ 15018c2ecf20Sopenharmony_ci chunk->chunk_hdr->length = htons(chunklen + padlen + len); 15028c2ecf20Sopenharmony_ci chunk->chunk_end = skb_tail_pointer(chunk->skb); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return target; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci/* Append bytes from user space to the end of a chunk. Will panic if 15088c2ecf20Sopenharmony_ci * chunk is not big enough. 15098c2ecf20Sopenharmony_ci * Returns a kernel err value. 15108c2ecf20Sopenharmony_ci */ 15118c2ecf20Sopenharmony_ciint sctp_user_addto_chunk(struct sctp_chunk *chunk, int len, 15128c2ecf20Sopenharmony_ci struct iov_iter *from) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci void *target; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* Make room in chunk for data. */ 15178c2ecf20Sopenharmony_ci target = skb_put(chunk->skb, len); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* Copy data (whole iovec) into chunk */ 15208c2ecf20Sopenharmony_ci if (!copy_from_iter_full(target, len, from)) 15218c2ecf20Sopenharmony_ci return -EFAULT; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci /* Adjust the chunk length field. */ 15248c2ecf20Sopenharmony_ci chunk->chunk_hdr->length = 15258c2ecf20Sopenharmony_ci htons(ntohs(chunk->chunk_hdr->length) + len); 15268c2ecf20Sopenharmony_ci chunk->chunk_end = skb_tail_pointer(chunk->skb); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci return 0; 15298c2ecf20Sopenharmony_ci} 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci/* Helper function to assign a TSN if needed. This assumes that both 15328c2ecf20Sopenharmony_ci * the data_hdr and association have already been assigned. 15338c2ecf20Sopenharmony_ci */ 15348c2ecf20Sopenharmony_civoid sctp_chunk_assign_ssn(struct sctp_chunk *chunk) 15358c2ecf20Sopenharmony_ci{ 15368c2ecf20Sopenharmony_ci struct sctp_stream *stream; 15378c2ecf20Sopenharmony_ci struct sctp_chunk *lchunk; 15388c2ecf20Sopenharmony_ci struct sctp_datamsg *msg; 15398c2ecf20Sopenharmony_ci __u16 ssn, sid; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (chunk->has_ssn) 15428c2ecf20Sopenharmony_ci return; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci /* All fragments will be on the same stream */ 15458c2ecf20Sopenharmony_ci sid = ntohs(chunk->subh.data_hdr->stream); 15468c2ecf20Sopenharmony_ci stream = &chunk->asoc->stream; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci /* Now assign the sequence number to the entire message. 15498c2ecf20Sopenharmony_ci * All fragments must have the same stream sequence number. 15508c2ecf20Sopenharmony_ci */ 15518c2ecf20Sopenharmony_ci msg = chunk->msg; 15528c2ecf20Sopenharmony_ci list_for_each_entry(lchunk, &msg->chunks, frag_list) { 15538c2ecf20Sopenharmony_ci if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { 15548c2ecf20Sopenharmony_ci ssn = 0; 15558c2ecf20Sopenharmony_ci } else { 15568c2ecf20Sopenharmony_ci if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG) 15578c2ecf20Sopenharmony_ci ssn = sctp_ssn_next(stream, out, sid); 15588c2ecf20Sopenharmony_ci else 15598c2ecf20Sopenharmony_ci ssn = sctp_ssn_peek(stream, out, sid); 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci lchunk->subh.data_hdr->ssn = htons(ssn); 15638c2ecf20Sopenharmony_ci lchunk->has_ssn = 1; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci/* Helper function to assign a TSN if needed. This assumes that both 15688c2ecf20Sopenharmony_ci * the data_hdr and association have already been assigned. 15698c2ecf20Sopenharmony_ci */ 15708c2ecf20Sopenharmony_civoid sctp_chunk_assign_tsn(struct sctp_chunk *chunk) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci if (!chunk->has_tsn) { 15738c2ecf20Sopenharmony_ci /* This is the last possible instant to 15748c2ecf20Sopenharmony_ci * assign a TSN. 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_ci chunk->subh.data_hdr->tsn = 15778c2ecf20Sopenharmony_ci htonl(sctp_association_get_next_tsn(chunk->asoc)); 15788c2ecf20Sopenharmony_ci chunk->has_tsn = 1; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci} 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci/* Create a CLOSED association to use with an incoming packet. */ 15838c2ecf20Sopenharmony_cistruct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep, 15848c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 15858c2ecf20Sopenharmony_ci gfp_t gfp) 15868c2ecf20Sopenharmony_ci{ 15878c2ecf20Sopenharmony_ci struct sctp_association *asoc; 15888c2ecf20Sopenharmony_ci enum sctp_scope scope; 15898c2ecf20Sopenharmony_ci struct sk_buff *skb; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci /* Create the bare association. */ 15928c2ecf20Sopenharmony_ci scope = sctp_scope(sctp_source(chunk)); 15938c2ecf20Sopenharmony_ci asoc = sctp_association_new(ep, ep->base.sk, scope, gfp); 15948c2ecf20Sopenharmony_ci if (!asoc) 15958c2ecf20Sopenharmony_ci goto nodata; 15968c2ecf20Sopenharmony_ci asoc->temp = 1; 15978c2ecf20Sopenharmony_ci skb = chunk->skb; 15988c2ecf20Sopenharmony_ci /* Create an entry for the source address of the packet. */ 15998c2ecf20Sopenharmony_ci SCTP_INPUT_CB(skb)->af->from_skb(&asoc->c.peer_addr, skb, 1); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_cinodata: 16028c2ecf20Sopenharmony_ci return asoc; 16038c2ecf20Sopenharmony_ci} 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci/* Build a cookie representing asoc. 16068c2ecf20Sopenharmony_ci * This INCLUDES the param header needed to put the cookie in the INIT ACK. 16078c2ecf20Sopenharmony_ci */ 16088c2ecf20Sopenharmony_cistatic struct sctp_cookie_param *sctp_pack_cookie( 16098c2ecf20Sopenharmony_ci const struct sctp_endpoint *ep, 16108c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 16118c2ecf20Sopenharmony_ci const struct sctp_chunk *init_chunk, 16128c2ecf20Sopenharmony_ci int *cookie_len, const __u8 *raw_addrs, 16138c2ecf20Sopenharmony_ci int addrs_len) 16148c2ecf20Sopenharmony_ci{ 16158c2ecf20Sopenharmony_ci struct sctp_signed_cookie *cookie; 16168c2ecf20Sopenharmony_ci struct sctp_cookie_param *retval; 16178c2ecf20Sopenharmony_ci int headersize, bodysize; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* Header size is static data prior to the actual cookie, including 16208c2ecf20Sopenharmony_ci * any padding. 16218c2ecf20Sopenharmony_ci */ 16228c2ecf20Sopenharmony_ci headersize = sizeof(struct sctp_paramhdr) + 16238c2ecf20Sopenharmony_ci (sizeof(struct sctp_signed_cookie) - 16248c2ecf20Sopenharmony_ci sizeof(struct sctp_cookie)); 16258c2ecf20Sopenharmony_ci bodysize = sizeof(struct sctp_cookie) 16268c2ecf20Sopenharmony_ci + ntohs(init_chunk->chunk_hdr->length) + addrs_len; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci /* Pad out the cookie to a multiple to make the signature 16298c2ecf20Sopenharmony_ci * functions simpler to write. 16308c2ecf20Sopenharmony_ci */ 16318c2ecf20Sopenharmony_ci if (bodysize % SCTP_COOKIE_MULTIPLE) 16328c2ecf20Sopenharmony_ci bodysize += SCTP_COOKIE_MULTIPLE 16338c2ecf20Sopenharmony_ci - (bodysize % SCTP_COOKIE_MULTIPLE); 16348c2ecf20Sopenharmony_ci *cookie_len = headersize + bodysize; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci /* Clear this memory since we are sending this data structure 16378c2ecf20Sopenharmony_ci * out on the network. 16388c2ecf20Sopenharmony_ci */ 16398c2ecf20Sopenharmony_ci retval = kzalloc(*cookie_len, GFP_ATOMIC); 16408c2ecf20Sopenharmony_ci if (!retval) 16418c2ecf20Sopenharmony_ci goto nodata; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci cookie = (struct sctp_signed_cookie *) retval->body; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci /* Set up the parameter header. */ 16468c2ecf20Sopenharmony_ci retval->p.type = SCTP_PARAM_STATE_COOKIE; 16478c2ecf20Sopenharmony_ci retval->p.length = htons(*cookie_len); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* Copy the cookie part of the association itself. */ 16508c2ecf20Sopenharmony_ci cookie->c = asoc->c; 16518c2ecf20Sopenharmony_ci /* Save the raw address list length in the cookie. */ 16528c2ecf20Sopenharmony_ci cookie->c.raw_addr_list_len = addrs_len; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci /* Remember PR-SCTP capability. */ 16558c2ecf20Sopenharmony_ci cookie->c.prsctp_capable = asoc->peer.prsctp_capable; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci /* Save adaptation indication in the cookie. */ 16588c2ecf20Sopenharmony_ci cookie->c.adaptation_ind = asoc->peer.adaptation_ind; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci /* Set an expiration time for the cookie. */ 16618c2ecf20Sopenharmony_ci cookie->c.expiration = ktime_add(asoc->cookie_life, 16628c2ecf20Sopenharmony_ci ktime_get_real()); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci /* Copy the peer's init packet. */ 16658c2ecf20Sopenharmony_ci memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr, 16668c2ecf20Sopenharmony_ci ntohs(init_chunk->chunk_hdr->length)); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci /* Copy the raw local address list of the association. */ 16698c2ecf20Sopenharmony_ci memcpy((__u8 *)&cookie->c.peer_init[0] + 16708c2ecf20Sopenharmony_ci ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (sctp_sk(ep->base.sk)->hmac) { 16738c2ecf20Sopenharmony_ci struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac; 16748c2ecf20Sopenharmony_ci int err; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci /* Sign the message. */ 16778c2ecf20Sopenharmony_ci err = crypto_shash_setkey(tfm, ep->secret_key, 16788c2ecf20Sopenharmony_ci sizeof(ep->secret_key)) ?: 16798c2ecf20Sopenharmony_ci crypto_shash_tfm_digest(tfm, (u8 *)&cookie->c, bodysize, 16808c2ecf20Sopenharmony_ci cookie->signature); 16818c2ecf20Sopenharmony_ci if (err) 16828c2ecf20Sopenharmony_ci goto free_cookie; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci return retval; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_cifree_cookie: 16888c2ecf20Sopenharmony_ci kfree(retval); 16898c2ecf20Sopenharmony_cinodata: 16908c2ecf20Sopenharmony_ci *cookie_len = 0; 16918c2ecf20Sopenharmony_ci return NULL; 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci/* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */ 16958c2ecf20Sopenharmony_cistruct sctp_association *sctp_unpack_cookie( 16968c2ecf20Sopenharmony_ci const struct sctp_endpoint *ep, 16978c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 16988c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, gfp_t gfp, 16998c2ecf20Sopenharmony_ci int *error, struct sctp_chunk **errp) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci struct sctp_association *retval = NULL; 17028c2ecf20Sopenharmony_ci int headersize, bodysize, fixed_size; 17038c2ecf20Sopenharmony_ci struct sctp_signed_cookie *cookie; 17048c2ecf20Sopenharmony_ci struct sk_buff *skb = chunk->skb; 17058c2ecf20Sopenharmony_ci struct sctp_cookie *bear_cookie; 17068c2ecf20Sopenharmony_ci __u8 *digest = ep->digest; 17078c2ecf20Sopenharmony_ci enum sctp_scope scope; 17088c2ecf20Sopenharmony_ci unsigned int len; 17098c2ecf20Sopenharmony_ci ktime_t kt; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci /* Header size is static data prior to the actual cookie, including 17128c2ecf20Sopenharmony_ci * any padding. 17138c2ecf20Sopenharmony_ci */ 17148c2ecf20Sopenharmony_ci headersize = sizeof(struct sctp_chunkhdr) + 17158c2ecf20Sopenharmony_ci (sizeof(struct sctp_signed_cookie) - 17168c2ecf20Sopenharmony_ci sizeof(struct sctp_cookie)); 17178c2ecf20Sopenharmony_ci bodysize = ntohs(chunk->chunk_hdr->length) - headersize; 17188c2ecf20Sopenharmony_ci fixed_size = headersize + sizeof(struct sctp_cookie); 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* Verify that the chunk looks like it even has a cookie. 17218c2ecf20Sopenharmony_ci * There must be enough room for our cookie and our peer's 17228c2ecf20Sopenharmony_ci * INIT chunk. 17238c2ecf20Sopenharmony_ci */ 17248c2ecf20Sopenharmony_ci len = ntohs(chunk->chunk_hdr->length); 17258c2ecf20Sopenharmony_ci if (len < fixed_size + sizeof(struct sctp_chunkhdr)) 17268c2ecf20Sopenharmony_ci goto malformed; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci /* Verify that the cookie has been padded out. */ 17298c2ecf20Sopenharmony_ci if (bodysize % SCTP_COOKIE_MULTIPLE) 17308c2ecf20Sopenharmony_ci goto malformed; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci /* Process the cookie. */ 17338c2ecf20Sopenharmony_ci cookie = chunk->subh.cookie_hdr; 17348c2ecf20Sopenharmony_ci bear_cookie = &cookie->c; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci if (!sctp_sk(ep->base.sk)->hmac) 17378c2ecf20Sopenharmony_ci goto no_hmac; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci /* Check the signature. */ 17408c2ecf20Sopenharmony_ci { 17418c2ecf20Sopenharmony_ci struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac; 17428c2ecf20Sopenharmony_ci int err; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci err = crypto_shash_setkey(tfm, ep->secret_key, 17458c2ecf20Sopenharmony_ci sizeof(ep->secret_key)) ?: 17468c2ecf20Sopenharmony_ci crypto_shash_tfm_digest(tfm, (u8 *)bear_cookie, bodysize, 17478c2ecf20Sopenharmony_ci digest); 17488c2ecf20Sopenharmony_ci if (err) { 17498c2ecf20Sopenharmony_ci *error = -SCTP_IERROR_NOMEM; 17508c2ecf20Sopenharmony_ci goto fail; 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { 17558c2ecf20Sopenharmony_ci *error = -SCTP_IERROR_BAD_SIG; 17568c2ecf20Sopenharmony_ci goto fail; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_cino_hmac: 17608c2ecf20Sopenharmony_ci /* IG Section 2.35.2: 17618c2ecf20Sopenharmony_ci * 3) Compare the port numbers and the verification tag contained 17628c2ecf20Sopenharmony_ci * within the COOKIE ECHO chunk to the actual port numbers and the 17638c2ecf20Sopenharmony_ci * verification tag within the SCTP common header of the received 17648c2ecf20Sopenharmony_ci * packet. If these values do not match the packet MUST be silently 17658c2ecf20Sopenharmony_ci * discarded, 17668c2ecf20Sopenharmony_ci */ 17678c2ecf20Sopenharmony_ci if (ntohl(chunk->sctp_hdr->vtag) != bear_cookie->my_vtag) { 17688c2ecf20Sopenharmony_ci *error = -SCTP_IERROR_BAD_TAG; 17698c2ecf20Sopenharmony_ci goto fail; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci if (chunk->sctp_hdr->source != bear_cookie->peer_addr.v4.sin_port || 17738c2ecf20Sopenharmony_ci ntohs(chunk->sctp_hdr->dest) != bear_cookie->my_port) { 17748c2ecf20Sopenharmony_ci *error = -SCTP_IERROR_BAD_PORTS; 17758c2ecf20Sopenharmony_ci goto fail; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci /* Check to see if the cookie is stale. If there is already 17798c2ecf20Sopenharmony_ci * an association, there is no need to check cookie's expiration 17808c2ecf20Sopenharmony_ci * for init collision case of lost COOKIE ACK. 17818c2ecf20Sopenharmony_ci * If skb has been timestamped, then use the stamp, otherwise 17828c2ecf20Sopenharmony_ci * use current time. This introduces a small possibility that 17838c2ecf20Sopenharmony_ci * a cookie may be considered expired, but this would only slow 17848c2ecf20Sopenharmony_ci * down the new association establishment instead of every packet. 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_ci if (sock_flag(ep->base.sk, SOCK_TIMESTAMP)) 17878c2ecf20Sopenharmony_ci kt = skb_get_ktime(skb); 17888c2ecf20Sopenharmony_ci else 17898c2ecf20Sopenharmony_ci kt = ktime_get_real(); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci if (!asoc && ktime_before(bear_cookie->expiration, kt)) { 17928c2ecf20Sopenharmony_ci suseconds_t usecs = ktime_to_us(ktime_sub(kt, bear_cookie->expiration)); 17938c2ecf20Sopenharmony_ci __be32 n = htonl(usecs); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci /* 17968c2ecf20Sopenharmony_ci * Section 3.3.10.3 Stale Cookie Error (3) 17978c2ecf20Sopenharmony_ci * 17988c2ecf20Sopenharmony_ci * Cause of error 17998c2ecf20Sopenharmony_ci * --------------- 18008c2ecf20Sopenharmony_ci * Stale Cookie Error: Indicates the receipt of a valid State 18018c2ecf20Sopenharmony_ci * Cookie that has expired. 18028c2ecf20Sopenharmony_ci */ 18038c2ecf20Sopenharmony_ci *errp = sctp_make_op_error(asoc, chunk, 18048c2ecf20Sopenharmony_ci SCTP_ERROR_STALE_COOKIE, &n, 18058c2ecf20Sopenharmony_ci sizeof(n), 0); 18068c2ecf20Sopenharmony_ci if (*errp) 18078c2ecf20Sopenharmony_ci *error = -SCTP_IERROR_STALE_COOKIE; 18088c2ecf20Sopenharmony_ci else 18098c2ecf20Sopenharmony_ci *error = -SCTP_IERROR_NOMEM; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci goto fail; 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci /* Make a new base association. */ 18158c2ecf20Sopenharmony_ci scope = sctp_scope(sctp_source(chunk)); 18168c2ecf20Sopenharmony_ci retval = sctp_association_new(ep, ep->base.sk, scope, gfp); 18178c2ecf20Sopenharmony_ci if (!retval) { 18188c2ecf20Sopenharmony_ci *error = -SCTP_IERROR_NOMEM; 18198c2ecf20Sopenharmony_ci goto fail; 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci /* Set up our peer's port number. */ 18238c2ecf20Sopenharmony_ci retval->peer.port = ntohs(chunk->sctp_hdr->source); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci /* Populate the association from the cookie. */ 18268c2ecf20Sopenharmony_ci memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie)); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci if (sctp_assoc_set_bind_addr_from_cookie(retval, bear_cookie, 18298c2ecf20Sopenharmony_ci GFP_ATOMIC) < 0) { 18308c2ecf20Sopenharmony_ci *error = -SCTP_IERROR_NOMEM; 18318c2ecf20Sopenharmony_ci goto fail; 18328c2ecf20Sopenharmony_ci } 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci /* Also, add the destination address. */ 18358c2ecf20Sopenharmony_ci if (list_empty(&retval->base.bind_addr.address_list)) { 18368c2ecf20Sopenharmony_ci sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, 18378c2ecf20Sopenharmony_ci sizeof(chunk->dest), SCTP_ADDR_SRC, 18388c2ecf20Sopenharmony_ci GFP_ATOMIC); 18398c2ecf20Sopenharmony_ci } 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci retval->next_tsn = retval->c.initial_tsn; 18428c2ecf20Sopenharmony_ci retval->ctsn_ack_point = retval->next_tsn - 1; 18438c2ecf20Sopenharmony_ci retval->addip_serial = retval->c.initial_tsn; 18448c2ecf20Sopenharmony_ci retval->strreset_outseq = retval->c.initial_tsn; 18458c2ecf20Sopenharmony_ci retval->adv_peer_ack_point = retval->ctsn_ack_point; 18468c2ecf20Sopenharmony_ci retval->peer.prsctp_capable = retval->c.prsctp_capable; 18478c2ecf20Sopenharmony_ci retval->peer.adaptation_ind = retval->c.adaptation_ind; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci /* The INIT stuff will be done by the side effects. */ 18508c2ecf20Sopenharmony_ci return retval; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_cifail: 18538c2ecf20Sopenharmony_ci if (retval) 18548c2ecf20Sopenharmony_ci sctp_association_free(retval); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci return NULL; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_cimalformed: 18598c2ecf20Sopenharmony_ci /* Yikes! The packet is either corrupt or deliberately 18608c2ecf20Sopenharmony_ci * malformed. 18618c2ecf20Sopenharmony_ci */ 18628c2ecf20Sopenharmony_ci *error = -SCTP_IERROR_MALFORMED; 18638c2ecf20Sopenharmony_ci goto fail; 18648c2ecf20Sopenharmony_ci} 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci/******************************************************************** 18678c2ecf20Sopenharmony_ci * 3rd Level Abstractions 18688c2ecf20Sopenharmony_ci ********************************************************************/ 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistruct __sctp_missing { 18718c2ecf20Sopenharmony_ci __be32 num_missing; 18728c2ecf20Sopenharmony_ci __be16 type; 18738c2ecf20Sopenharmony_ci} __packed; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci/* 18768c2ecf20Sopenharmony_ci * Report a missing mandatory parameter. 18778c2ecf20Sopenharmony_ci */ 18788c2ecf20Sopenharmony_cistatic int sctp_process_missing_param(const struct sctp_association *asoc, 18798c2ecf20Sopenharmony_ci enum sctp_param paramtype, 18808c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 18818c2ecf20Sopenharmony_ci struct sctp_chunk **errp) 18828c2ecf20Sopenharmony_ci{ 18838c2ecf20Sopenharmony_ci struct __sctp_missing report; 18848c2ecf20Sopenharmony_ci __u16 len; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci len = SCTP_PAD4(sizeof(report)); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci /* Make an ERROR chunk, preparing enough room for 18898c2ecf20Sopenharmony_ci * returning multiple unknown parameters. 18908c2ecf20Sopenharmony_ci */ 18918c2ecf20Sopenharmony_ci if (!*errp) 18928c2ecf20Sopenharmony_ci *errp = sctp_make_op_error_space(asoc, chunk, len); 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (*errp) { 18958c2ecf20Sopenharmony_ci report.num_missing = htonl(1); 18968c2ecf20Sopenharmony_ci report.type = paramtype; 18978c2ecf20Sopenharmony_ci sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM, 18988c2ecf20Sopenharmony_ci sizeof(report)); 18998c2ecf20Sopenharmony_ci sctp_addto_chunk(*errp, sizeof(report), &report); 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci /* Stop processing this chunk. */ 19038c2ecf20Sopenharmony_ci return 0; 19048c2ecf20Sopenharmony_ci} 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci/* Report an Invalid Mandatory Parameter. */ 19078c2ecf20Sopenharmony_cistatic int sctp_process_inv_mandatory(const struct sctp_association *asoc, 19088c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 19098c2ecf20Sopenharmony_ci struct sctp_chunk **errp) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci /* Invalid Mandatory Parameter Error has no payload. */ 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci if (!*errp) 19148c2ecf20Sopenharmony_ci *errp = sctp_make_op_error_space(asoc, chunk, 0); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci if (*errp) 19178c2ecf20Sopenharmony_ci sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, 0); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci /* Stop processing this chunk. */ 19208c2ecf20Sopenharmony_ci return 0; 19218c2ecf20Sopenharmony_ci} 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_cistatic int sctp_process_inv_paramlength(const struct sctp_association *asoc, 19248c2ecf20Sopenharmony_ci struct sctp_paramhdr *param, 19258c2ecf20Sopenharmony_ci const struct sctp_chunk *chunk, 19268c2ecf20Sopenharmony_ci struct sctp_chunk **errp) 19278c2ecf20Sopenharmony_ci{ 19288c2ecf20Sopenharmony_ci /* This is a fatal error. Any accumulated non-fatal errors are 19298c2ecf20Sopenharmony_ci * not reported. 19308c2ecf20Sopenharmony_ci */ 19318c2ecf20Sopenharmony_ci if (*errp) 19328c2ecf20Sopenharmony_ci sctp_chunk_free(*errp); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci /* Create an error chunk and fill it in with our payload. */ 19358c2ecf20Sopenharmony_ci *errp = sctp_make_violation_paramlen(asoc, chunk, param); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci return 0; 19388c2ecf20Sopenharmony_ci} 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci/* Do not attempt to handle the HOST_NAME parm. However, do 19428c2ecf20Sopenharmony_ci * send back an indicator to the peer. 19438c2ecf20Sopenharmony_ci */ 19448c2ecf20Sopenharmony_cistatic int sctp_process_hn_param(const struct sctp_association *asoc, 19458c2ecf20Sopenharmony_ci union sctp_params param, 19468c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 19478c2ecf20Sopenharmony_ci struct sctp_chunk **errp) 19488c2ecf20Sopenharmony_ci{ 19498c2ecf20Sopenharmony_ci __u16 len = ntohs(param.p->length); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci /* Processing of the HOST_NAME parameter will generate an 19528c2ecf20Sopenharmony_ci * ABORT. If we've accumulated any non-fatal errors, they 19538c2ecf20Sopenharmony_ci * would be unrecognized parameters and we should not include 19548c2ecf20Sopenharmony_ci * them in the ABORT. 19558c2ecf20Sopenharmony_ci */ 19568c2ecf20Sopenharmony_ci if (*errp) 19578c2ecf20Sopenharmony_ci sctp_chunk_free(*errp); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci *errp = sctp_make_op_error(asoc, chunk, SCTP_ERROR_DNS_FAILED, 19608c2ecf20Sopenharmony_ci param.v, len, 0); 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci /* Stop processing this chunk. */ 19638c2ecf20Sopenharmony_ci return 0; 19648c2ecf20Sopenharmony_ci} 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_cistatic int sctp_verify_ext_param(struct net *net, 19678c2ecf20Sopenharmony_ci const struct sctp_endpoint *ep, 19688c2ecf20Sopenharmony_ci union sctp_params param) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci __u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); 19718c2ecf20Sopenharmony_ci int have_asconf = 0; 19728c2ecf20Sopenharmony_ci int have_auth = 0; 19738c2ecf20Sopenharmony_ci int i; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci for (i = 0; i < num_ext; i++) { 19768c2ecf20Sopenharmony_ci switch (param.ext->chunks[i]) { 19778c2ecf20Sopenharmony_ci case SCTP_CID_AUTH: 19788c2ecf20Sopenharmony_ci have_auth = 1; 19798c2ecf20Sopenharmony_ci break; 19808c2ecf20Sopenharmony_ci case SCTP_CID_ASCONF: 19818c2ecf20Sopenharmony_ci case SCTP_CID_ASCONF_ACK: 19828c2ecf20Sopenharmony_ci have_asconf = 1; 19838c2ecf20Sopenharmony_ci break; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci /* ADD-IP Security: The draft requires us to ABORT or ignore the 19888c2ecf20Sopenharmony_ci * INIT/INIT-ACK if ADD-IP is listed, but AUTH is not. Do this 19898c2ecf20Sopenharmony_ci * only if ADD-IP is turned on and we are not backward-compatible 19908c2ecf20Sopenharmony_ci * mode. 19918c2ecf20Sopenharmony_ci */ 19928c2ecf20Sopenharmony_ci if (net->sctp.addip_noauth) 19938c2ecf20Sopenharmony_ci return 1; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (ep->asconf_enable && !have_auth && have_asconf) 19968c2ecf20Sopenharmony_ci return 0; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci return 1; 19998c2ecf20Sopenharmony_ci} 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_cistatic void sctp_process_ext_param(struct sctp_association *asoc, 20028c2ecf20Sopenharmony_ci union sctp_params param) 20038c2ecf20Sopenharmony_ci{ 20048c2ecf20Sopenharmony_ci __u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); 20058c2ecf20Sopenharmony_ci int i; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci for (i = 0; i < num_ext; i++) { 20088c2ecf20Sopenharmony_ci switch (param.ext->chunks[i]) { 20098c2ecf20Sopenharmony_ci case SCTP_CID_RECONF: 20108c2ecf20Sopenharmony_ci if (asoc->ep->reconf_enable) 20118c2ecf20Sopenharmony_ci asoc->peer.reconf_capable = 1; 20128c2ecf20Sopenharmony_ci break; 20138c2ecf20Sopenharmony_ci case SCTP_CID_FWD_TSN: 20148c2ecf20Sopenharmony_ci if (asoc->ep->prsctp_enable) 20158c2ecf20Sopenharmony_ci asoc->peer.prsctp_capable = 1; 20168c2ecf20Sopenharmony_ci break; 20178c2ecf20Sopenharmony_ci case SCTP_CID_AUTH: 20188c2ecf20Sopenharmony_ci /* if the peer reports AUTH, assume that he 20198c2ecf20Sopenharmony_ci * supports AUTH. 20208c2ecf20Sopenharmony_ci */ 20218c2ecf20Sopenharmony_ci if (asoc->ep->auth_enable) 20228c2ecf20Sopenharmony_ci asoc->peer.auth_capable = 1; 20238c2ecf20Sopenharmony_ci break; 20248c2ecf20Sopenharmony_ci case SCTP_CID_ASCONF: 20258c2ecf20Sopenharmony_ci case SCTP_CID_ASCONF_ACK: 20268c2ecf20Sopenharmony_ci if (asoc->ep->asconf_enable) 20278c2ecf20Sopenharmony_ci asoc->peer.asconf_capable = 1; 20288c2ecf20Sopenharmony_ci break; 20298c2ecf20Sopenharmony_ci case SCTP_CID_I_DATA: 20308c2ecf20Sopenharmony_ci if (asoc->ep->intl_enable) 20318c2ecf20Sopenharmony_ci asoc->peer.intl_capable = 1; 20328c2ecf20Sopenharmony_ci break; 20338c2ecf20Sopenharmony_ci default: 20348c2ecf20Sopenharmony_ci break; 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci} 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci/* RFC 3.2.1 & the Implementers Guide 2.2. 20408c2ecf20Sopenharmony_ci * 20418c2ecf20Sopenharmony_ci * The Parameter Types are encoded such that the 20428c2ecf20Sopenharmony_ci * highest-order two bits specify the action that must be 20438c2ecf20Sopenharmony_ci * taken if the processing endpoint does not recognize the 20448c2ecf20Sopenharmony_ci * Parameter Type. 20458c2ecf20Sopenharmony_ci * 20468c2ecf20Sopenharmony_ci * 00 - Stop processing this parameter; do not process any further 20478c2ecf20Sopenharmony_ci * parameters within this chunk 20488c2ecf20Sopenharmony_ci * 20498c2ecf20Sopenharmony_ci * 01 - Stop processing this parameter, do not process any further 20508c2ecf20Sopenharmony_ci * parameters within this chunk, and report the unrecognized 20518c2ecf20Sopenharmony_ci * parameter in an 'Unrecognized Parameter' ERROR chunk. 20528c2ecf20Sopenharmony_ci * 20538c2ecf20Sopenharmony_ci * 10 - Skip this parameter and continue processing. 20548c2ecf20Sopenharmony_ci * 20558c2ecf20Sopenharmony_ci * 11 - Skip this parameter and continue processing but 20568c2ecf20Sopenharmony_ci * report the unrecognized parameter in an 20578c2ecf20Sopenharmony_ci * 'Unrecognized Parameter' ERROR chunk. 20588c2ecf20Sopenharmony_ci * 20598c2ecf20Sopenharmony_ci * Return value: 20608c2ecf20Sopenharmony_ci * SCTP_IERROR_NO_ERROR - continue with the chunk 20618c2ecf20Sopenharmony_ci * SCTP_IERROR_ERROR - stop and report an error. 20628c2ecf20Sopenharmony_ci * SCTP_IERROR_NOMEME - out of memory. 20638c2ecf20Sopenharmony_ci */ 20648c2ecf20Sopenharmony_cistatic enum sctp_ierror sctp_process_unk_param( 20658c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 20668c2ecf20Sopenharmony_ci union sctp_params param, 20678c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 20688c2ecf20Sopenharmony_ci struct sctp_chunk **errp) 20698c2ecf20Sopenharmony_ci{ 20708c2ecf20Sopenharmony_ci int retval = SCTP_IERROR_NO_ERROR; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci switch (param.p->type & SCTP_PARAM_ACTION_MASK) { 20738c2ecf20Sopenharmony_ci case SCTP_PARAM_ACTION_DISCARD: 20748c2ecf20Sopenharmony_ci retval = SCTP_IERROR_ERROR; 20758c2ecf20Sopenharmony_ci break; 20768c2ecf20Sopenharmony_ci case SCTP_PARAM_ACTION_SKIP: 20778c2ecf20Sopenharmony_ci break; 20788c2ecf20Sopenharmony_ci case SCTP_PARAM_ACTION_DISCARD_ERR: 20798c2ecf20Sopenharmony_ci retval = SCTP_IERROR_ERROR; 20808c2ecf20Sopenharmony_ci fallthrough; 20818c2ecf20Sopenharmony_ci case SCTP_PARAM_ACTION_SKIP_ERR: 20828c2ecf20Sopenharmony_ci /* Make an ERROR chunk, preparing enough room for 20838c2ecf20Sopenharmony_ci * returning multiple unknown parameters. 20848c2ecf20Sopenharmony_ci */ 20858c2ecf20Sopenharmony_ci if (!*errp) { 20868c2ecf20Sopenharmony_ci *errp = sctp_make_op_error_limited(asoc, chunk); 20878c2ecf20Sopenharmony_ci if (!*errp) { 20888c2ecf20Sopenharmony_ci /* If there is no memory for generating the 20898c2ecf20Sopenharmony_ci * ERROR report as specified, an ABORT will be 20908c2ecf20Sopenharmony_ci * triggered to the peer and the association 20918c2ecf20Sopenharmony_ci * won't be established. 20928c2ecf20Sopenharmony_ci */ 20938c2ecf20Sopenharmony_ci retval = SCTP_IERROR_NOMEM; 20948c2ecf20Sopenharmony_ci break; 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci if (!sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, 20998c2ecf20Sopenharmony_ci ntohs(param.p->length))) 21008c2ecf20Sopenharmony_ci sctp_addto_chunk(*errp, ntohs(param.p->length), 21018c2ecf20Sopenharmony_ci param.v); 21028c2ecf20Sopenharmony_ci break; 21038c2ecf20Sopenharmony_ci default: 21048c2ecf20Sopenharmony_ci break; 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci return retval; 21088c2ecf20Sopenharmony_ci} 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci/* Verify variable length parameters 21118c2ecf20Sopenharmony_ci * Return values: 21128c2ecf20Sopenharmony_ci * SCTP_IERROR_ABORT - trigger an ABORT 21138c2ecf20Sopenharmony_ci * SCTP_IERROR_NOMEM - out of memory (abort) 21148c2ecf20Sopenharmony_ci * SCTP_IERROR_ERROR - stop processing, trigger an ERROR 21158c2ecf20Sopenharmony_ci * SCTP_IERROR_NO_ERROR - continue with the chunk 21168c2ecf20Sopenharmony_ci */ 21178c2ecf20Sopenharmony_cistatic enum sctp_ierror sctp_verify_param(struct net *net, 21188c2ecf20Sopenharmony_ci const struct sctp_endpoint *ep, 21198c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 21208c2ecf20Sopenharmony_ci union sctp_params param, 21218c2ecf20Sopenharmony_ci enum sctp_cid cid, 21228c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 21238c2ecf20Sopenharmony_ci struct sctp_chunk **err_chunk) 21248c2ecf20Sopenharmony_ci{ 21258c2ecf20Sopenharmony_ci struct sctp_hmac_algo_param *hmacs; 21268c2ecf20Sopenharmony_ci int retval = SCTP_IERROR_NO_ERROR; 21278c2ecf20Sopenharmony_ci __u16 n_elt, id = 0; 21288c2ecf20Sopenharmony_ci int i; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci /* FIXME - This routine is not looking at each parameter per the 21318c2ecf20Sopenharmony_ci * chunk type, i.e., unrecognized parameters should be further 21328c2ecf20Sopenharmony_ci * identified based on the chunk id. 21338c2ecf20Sopenharmony_ci */ 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci switch (param.p->type) { 21368c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV4_ADDRESS: 21378c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV6_ADDRESS: 21388c2ecf20Sopenharmony_ci case SCTP_PARAM_COOKIE_PRESERVATIVE: 21398c2ecf20Sopenharmony_ci case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: 21408c2ecf20Sopenharmony_ci case SCTP_PARAM_STATE_COOKIE: 21418c2ecf20Sopenharmony_ci case SCTP_PARAM_HEARTBEAT_INFO: 21428c2ecf20Sopenharmony_ci case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: 21438c2ecf20Sopenharmony_ci case SCTP_PARAM_ECN_CAPABLE: 21448c2ecf20Sopenharmony_ci case SCTP_PARAM_ADAPTATION_LAYER_IND: 21458c2ecf20Sopenharmony_ci break; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci case SCTP_PARAM_SUPPORTED_EXT: 21488c2ecf20Sopenharmony_ci if (!sctp_verify_ext_param(net, ep, param)) 21498c2ecf20Sopenharmony_ci return SCTP_IERROR_ABORT; 21508c2ecf20Sopenharmony_ci break; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci case SCTP_PARAM_SET_PRIMARY: 21538c2ecf20Sopenharmony_ci if (!ep->asconf_enable) 21548c2ecf20Sopenharmony_ci goto unhandled; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci if (ntohs(param.p->length) < sizeof(struct sctp_addip_param) + 21578c2ecf20Sopenharmony_ci sizeof(struct sctp_paramhdr)) { 21588c2ecf20Sopenharmony_ci sctp_process_inv_paramlength(asoc, param.p, 21598c2ecf20Sopenharmony_ci chunk, err_chunk); 21608c2ecf20Sopenharmony_ci retval = SCTP_IERROR_ABORT; 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci break; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci case SCTP_PARAM_HOST_NAME_ADDRESS: 21658c2ecf20Sopenharmony_ci /* Tell the peer, we won't support this param. */ 21668c2ecf20Sopenharmony_ci sctp_process_hn_param(asoc, param, chunk, err_chunk); 21678c2ecf20Sopenharmony_ci retval = SCTP_IERROR_ABORT; 21688c2ecf20Sopenharmony_ci break; 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci case SCTP_PARAM_FWD_TSN_SUPPORT: 21718c2ecf20Sopenharmony_ci if (ep->prsctp_enable) 21728c2ecf20Sopenharmony_ci break; 21738c2ecf20Sopenharmony_ci goto unhandled; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci case SCTP_PARAM_RANDOM: 21768c2ecf20Sopenharmony_ci if (!ep->auth_enable) 21778c2ecf20Sopenharmony_ci goto unhandled; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci /* SCTP-AUTH: Secion 6.1 21808c2ecf20Sopenharmony_ci * If the random number is not 32 byte long the association 21818c2ecf20Sopenharmony_ci * MUST be aborted. The ABORT chunk SHOULD contain the error 21828c2ecf20Sopenharmony_ci * cause 'Protocol Violation'. 21838c2ecf20Sopenharmony_ci */ 21848c2ecf20Sopenharmony_ci if (SCTP_AUTH_RANDOM_LENGTH != ntohs(param.p->length) - 21858c2ecf20Sopenharmony_ci sizeof(struct sctp_paramhdr)) { 21868c2ecf20Sopenharmony_ci sctp_process_inv_paramlength(asoc, param.p, 21878c2ecf20Sopenharmony_ci chunk, err_chunk); 21888c2ecf20Sopenharmony_ci retval = SCTP_IERROR_ABORT; 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_ci break; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci case SCTP_PARAM_CHUNKS: 21938c2ecf20Sopenharmony_ci if (!ep->auth_enable) 21948c2ecf20Sopenharmony_ci goto unhandled; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci /* SCTP-AUTH: Section 3.2 21978c2ecf20Sopenharmony_ci * The CHUNKS parameter MUST be included once in the INIT or 21988c2ecf20Sopenharmony_ci * INIT-ACK chunk if the sender wants to receive authenticated 21998c2ecf20Sopenharmony_ci * chunks. Its maximum length is 260 bytes. 22008c2ecf20Sopenharmony_ci */ 22018c2ecf20Sopenharmony_ci if (260 < ntohs(param.p->length)) { 22028c2ecf20Sopenharmony_ci sctp_process_inv_paramlength(asoc, param.p, 22038c2ecf20Sopenharmony_ci chunk, err_chunk); 22048c2ecf20Sopenharmony_ci retval = SCTP_IERROR_ABORT; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci break; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci case SCTP_PARAM_HMAC_ALGO: 22098c2ecf20Sopenharmony_ci if (!ep->auth_enable) 22108c2ecf20Sopenharmony_ci goto unhandled; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci hmacs = (struct sctp_hmac_algo_param *)param.p; 22138c2ecf20Sopenharmony_ci n_elt = (ntohs(param.p->length) - 22148c2ecf20Sopenharmony_ci sizeof(struct sctp_paramhdr)) >> 1; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci /* SCTP-AUTH: Section 6.1 22178c2ecf20Sopenharmony_ci * The HMAC algorithm based on SHA-1 MUST be supported and 22188c2ecf20Sopenharmony_ci * included in the HMAC-ALGO parameter. 22198c2ecf20Sopenharmony_ci */ 22208c2ecf20Sopenharmony_ci for (i = 0; i < n_elt; i++) { 22218c2ecf20Sopenharmony_ci id = ntohs(hmacs->hmac_ids[i]); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci if (id == SCTP_AUTH_HMAC_ID_SHA1) 22248c2ecf20Sopenharmony_ci break; 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci if (id != SCTP_AUTH_HMAC_ID_SHA1) { 22288c2ecf20Sopenharmony_ci sctp_process_inv_paramlength(asoc, param.p, chunk, 22298c2ecf20Sopenharmony_ci err_chunk); 22308c2ecf20Sopenharmony_ci retval = SCTP_IERROR_ABORT; 22318c2ecf20Sopenharmony_ci } 22328c2ecf20Sopenharmony_ci break; 22338c2ecf20Sopenharmony_ciunhandled: 22348c2ecf20Sopenharmony_ci default: 22358c2ecf20Sopenharmony_ci pr_debug("%s: unrecognized param:%d for chunk:%d\n", 22368c2ecf20Sopenharmony_ci __func__, ntohs(param.p->type), cid); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci retval = sctp_process_unk_param(asoc, param, chunk, err_chunk); 22398c2ecf20Sopenharmony_ci break; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci return retval; 22428c2ecf20Sopenharmony_ci} 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci/* Verify the INIT packet before we process it. */ 22458c2ecf20Sopenharmony_ciint sctp_verify_init(struct net *net, const struct sctp_endpoint *ep, 22468c2ecf20Sopenharmony_ci const struct sctp_association *asoc, enum sctp_cid cid, 22478c2ecf20Sopenharmony_ci struct sctp_init_chunk *peer_init, 22488c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, struct sctp_chunk **errp) 22498c2ecf20Sopenharmony_ci{ 22508c2ecf20Sopenharmony_ci union sctp_params param; 22518c2ecf20Sopenharmony_ci bool has_cookie = false; 22528c2ecf20Sopenharmony_ci int result; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci /* Check for missing mandatory parameters. Note: Initial TSN is 22558c2ecf20Sopenharmony_ci * also mandatory, but is not checked here since the valid range 22568c2ecf20Sopenharmony_ci * is 0..2**32-1. RFC4960, section 3.3.3. 22578c2ecf20Sopenharmony_ci */ 22588c2ecf20Sopenharmony_ci if (peer_init->init_hdr.num_outbound_streams == 0 || 22598c2ecf20Sopenharmony_ci peer_init->init_hdr.num_inbound_streams == 0 || 22608c2ecf20Sopenharmony_ci peer_init->init_hdr.init_tag == 0 || 22618c2ecf20Sopenharmony_ci ntohl(peer_init->init_hdr.a_rwnd) < SCTP_DEFAULT_MINWINDOW) 22628c2ecf20Sopenharmony_ci return sctp_process_inv_mandatory(asoc, chunk, errp); 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci sctp_walk_params(param, peer_init, init_hdr.params) { 22658c2ecf20Sopenharmony_ci if (param.p->type == SCTP_PARAM_STATE_COOKIE) 22668c2ecf20Sopenharmony_ci has_cookie = true; 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci /* There is a possibility that a parameter length was bad and 22708c2ecf20Sopenharmony_ci * in that case we would have stoped walking the parameters. 22718c2ecf20Sopenharmony_ci * The current param.p would point at the bad one. 22728c2ecf20Sopenharmony_ci * Current consensus on the mailing list is to generate a PROTOCOL 22738c2ecf20Sopenharmony_ci * VIOLATION error. We build the ERROR chunk here and let the normal 22748c2ecf20Sopenharmony_ci * error handling code build and send the packet. 22758c2ecf20Sopenharmony_ci */ 22768c2ecf20Sopenharmony_ci if (param.v != (void *)chunk->chunk_end) 22778c2ecf20Sopenharmony_ci return sctp_process_inv_paramlength(asoc, param.p, chunk, errp); 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci /* The only missing mandatory param possible today is 22808c2ecf20Sopenharmony_ci * the state cookie for an INIT-ACK chunk. 22818c2ecf20Sopenharmony_ci */ 22828c2ecf20Sopenharmony_ci if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) 22838c2ecf20Sopenharmony_ci return sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, 22848c2ecf20Sopenharmony_ci chunk, errp); 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci /* Verify all the variable length parameters */ 22878c2ecf20Sopenharmony_ci sctp_walk_params(param, peer_init, init_hdr.params) { 22888c2ecf20Sopenharmony_ci result = sctp_verify_param(net, ep, asoc, param, cid, 22898c2ecf20Sopenharmony_ci chunk, errp); 22908c2ecf20Sopenharmony_ci switch (result) { 22918c2ecf20Sopenharmony_ci case SCTP_IERROR_ABORT: 22928c2ecf20Sopenharmony_ci case SCTP_IERROR_NOMEM: 22938c2ecf20Sopenharmony_ci return 0; 22948c2ecf20Sopenharmony_ci case SCTP_IERROR_ERROR: 22958c2ecf20Sopenharmony_ci return 1; 22968c2ecf20Sopenharmony_ci case SCTP_IERROR_NO_ERROR: 22978c2ecf20Sopenharmony_ci default: 22988c2ecf20Sopenharmony_ci break; 22998c2ecf20Sopenharmony_ci } 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci } /* for (loop through all parameters) */ 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci return 1; 23048c2ecf20Sopenharmony_ci} 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci/* Unpack the parameters in an INIT packet into an association. 23078c2ecf20Sopenharmony_ci * Returns 0 on failure, else success. 23088c2ecf20Sopenharmony_ci * FIXME: This is an association method. 23098c2ecf20Sopenharmony_ci */ 23108c2ecf20Sopenharmony_ciint sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, 23118c2ecf20Sopenharmony_ci const union sctp_addr *peer_addr, 23128c2ecf20Sopenharmony_ci struct sctp_init_chunk *peer_init, gfp_t gfp) 23138c2ecf20Sopenharmony_ci{ 23148c2ecf20Sopenharmony_ci struct sctp_transport *transport; 23158c2ecf20Sopenharmony_ci struct list_head *pos, *temp; 23168c2ecf20Sopenharmony_ci union sctp_params param; 23178c2ecf20Sopenharmony_ci union sctp_addr addr; 23188c2ecf20Sopenharmony_ci struct sctp_af *af; 23198c2ecf20Sopenharmony_ci int src_match = 0; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci /* We must include the address that the INIT packet came from. 23228c2ecf20Sopenharmony_ci * This is the only address that matters for an INIT packet. 23238c2ecf20Sopenharmony_ci * When processing a COOKIE ECHO, we retrieve the from address 23248c2ecf20Sopenharmony_ci * of the INIT from the cookie. 23258c2ecf20Sopenharmony_ci */ 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci /* This implementation defaults to making the first transport 23288c2ecf20Sopenharmony_ci * added as the primary transport. The source address seems to 23298c2ecf20Sopenharmony_ci * be a better choice than any of the embedded addresses. 23308c2ecf20Sopenharmony_ci */ 23318c2ecf20Sopenharmony_ci if (!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) 23328c2ecf20Sopenharmony_ci goto nomem; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr)) 23358c2ecf20Sopenharmony_ci src_match = 1; 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci /* Process the initialization parameters. */ 23388c2ecf20Sopenharmony_ci sctp_walk_params(param, peer_init, init_hdr.params) { 23398c2ecf20Sopenharmony_ci if (!src_match && 23408c2ecf20Sopenharmony_ci (param.p->type == SCTP_PARAM_IPV4_ADDRESS || 23418c2ecf20Sopenharmony_ci param.p->type == SCTP_PARAM_IPV6_ADDRESS)) { 23428c2ecf20Sopenharmony_ci af = sctp_get_af_specific(param_type2af(param.p->type)); 23438c2ecf20Sopenharmony_ci if (!af->from_addr_param(&addr, param.addr, 23448c2ecf20Sopenharmony_ci chunk->sctp_hdr->source, 0)) 23458c2ecf20Sopenharmony_ci continue; 23468c2ecf20Sopenharmony_ci if (sctp_cmp_addr_exact(sctp_source(chunk), &addr)) 23478c2ecf20Sopenharmony_ci src_match = 1; 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if (!sctp_process_param(asoc, param, peer_addr, gfp)) 23518c2ecf20Sopenharmony_ci goto clean_up; 23528c2ecf20Sopenharmony_ci } 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci /* source address of chunk may not match any valid address */ 23558c2ecf20Sopenharmony_ci if (!src_match) 23568c2ecf20Sopenharmony_ci goto clean_up; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci /* AUTH: After processing the parameters, make sure that we 23598c2ecf20Sopenharmony_ci * have all the required info to potentially do authentications. 23608c2ecf20Sopenharmony_ci */ 23618c2ecf20Sopenharmony_ci if (asoc->peer.auth_capable && (!asoc->peer.peer_random || 23628c2ecf20Sopenharmony_ci !asoc->peer.peer_hmacs)) 23638c2ecf20Sopenharmony_ci asoc->peer.auth_capable = 0; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci /* In a non-backward compatible mode, if the peer claims 23668c2ecf20Sopenharmony_ci * support for ADD-IP but not AUTH, the ADD-IP spec states 23678c2ecf20Sopenharmony_ci * that we MUST ABORT the association. Section 6. The section 23688c2ecf20Sopenharmony_ci * also give us an option to silently ignore the packet, which 23698c2ecf20Sopenharmony_ci * is what we'll do here. 23708c2ecf20Sopenharmony_ci */ 23718c2ecf20Sopenharmony_ci if (!asoc->base.net->sctp.addip_noauth && 23728c2ecf20Sopenharmony_ci (asoc->peer.asconf_capable && !asoc->peer.auth_capable)) { 23738c2ecf20Sopenharmony_ci asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP | 23748c2ecf20Sopenharmony_ci SCTP_PARAM_DEL_IP | 23758c2ecf20Sopenharmony_ci SCTP_PARAM_SET_PRIMARY); 23768c2ecf20Sopenharmony_ci asoc->peer.asconf_capable = 0; 23778c2ecf20Sopenharmony_ci goto clean_up; 23788c2ecf20Sopenharmony_ci } 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci /* Walk list of transports, removing transports in the UNKNOWN state. */ 23818c2ecf20Sopenharmony_ci list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { 23828c2ecf20Sopenharmony_ci transport = list_entry(pos, struct sctp_transport, transports); 23838c2ecf20Sopenharmony_ci if (transport->state == SCTP_UNKNOWN) { 23848c2ecf20Sopenharmony_ci sctp_assoc_rm_peer(asoc, transport); 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci } 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci /* The fixed INIT headers are always in network byte 23898c2ecf20Sopenharmony_ci * order. 23908c2ecf20Sopenharmony_ci */ 23918c2ecf20Sopenharmony_ci asoc->peer.i.init_tag = 23928c2ecf20Sopenharmony_ci ntohl(peer_init->init_hdr.init_tag); 23938c2ecf20Sopenharmony_ci asoc->peer.i.a_rwnd = 23948c2ecf20Sopenharmony_ci ntohl(peer_init->init_hdr.a_rwnd); 23958c2ecf20Sopenharmony_ci asoc->peer.i.num_outbound_streams = 23968c2ecf20Sopenharmony_ci ntohs(peer_init->init_hdr.num_outbound_streams); 23978c2ecf20Sopenharmony_ci asoc->peer.i.num_inbound_streams = 23988c2ecf20Sopenharmony_ci ntohs(peer_init->init_hdr.num_inbound_streams); 23998c2ecf20Sopenharmony_ci asoc->peer.i.initial_tsn = 24008c2ecf20Sopenharmony_ci ntohl(peer_init->init_hdr.initial_tsn); 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci asoc->strreset_inseq = asoc->peer.i.initial_tsn; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci /* Apply the upper bounds for output streams based on peer's 24058c2ecf20Sopenharmony_ci * number of inbound streams. 24068c2ecf20Sopenharmony_ci */ 24078c2ecf20Sopenharmony_ci if (asoc->c.sinit_num_ostreams > 24088c2ecf20Sopenharmony_ci ntohs(peer_init->init_hdr.num_inbound_streams)) { 24098c2ecf20Sopenharmony_ci asoc->c.sinit_num_ostreams = 24108c2ecf20Sopenharmony_ci ntohs(peer_init->init_hdr.num_inbound_streams); 24118c2ecf20Sopenharmony_ci } 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci if (asoc->c.sinit_max_instreams > 24148c2ecf20Sopenharmony_ci ntohs(peer_init->init_hdr.num_outbound_streams)) { 24158c2ecf20Sopenharmony_ci asoc->c.sinit_max_instreams = 24168c2ecf20Sopenharmony_ci ntohs(peer_init->init_hdr.num_outbound_streams); 24178c2ecf20Sopenharmony_ci } 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci /* Copy Initiation tag from INIT to VT_peer in cookie. */ 24208c2ecf20Sopenharmony_ci asoc->c.peer_vtag = asoc->peer.i.init_tag; 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci /* Peer Rwnd : Current calculated value of the peer's rwnd. */ 24238c2ecf20Sopenharmony_ci asoc->peer.rwnd = asoc->peer.i.a_rwnd; 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci /* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily 24268c2ecf20Sopenharmony_ci * high (for example, implementations MAY use the size of the receiver 24278c2ecf20Sopenharmony_ci * advertised window). 24288c2ecf20Sopenharmony_ci */ 24298c2ecf20Sopenharmony_ci list_for_each_entry(transport, &asoc->peer.transport_addr_list, 24308c2ecf20Sopenharmony_ci transports) { 24318c2ecf20Sopenharmony_ci transport->ssthresh = asoc->peer.i.a_rwnd; 24328c2ecf20Sopenharmony_ci } 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci /* Set up the TSN tracking pieces. */ 24358c2ecf20Sopenharmony_ci if (!sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL, 24368c2ecf20Sopenharmony_ci asoc->peer.i.initial_tsn, gfp)) 24378c2ecf20Sopenharmony_ci goto clean_up; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number 24408c2ecf20Sopenharmony_ci * 24418c2ecf20Sopenharmony_ci * The stream sequence number in all the streams shall start 24428c2ecf20Sopenharmony_ci * from 0 when the association is established. Also, when the 24438c2ecf20Sopenharmony_ci * stream sequence number reaches the value 65535 the next 24448c2ecf20Sopenharmony_ci * stream sequence number shall be set to 0. 24458c2ecf20Sopenharmony_ci */ 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams, 24488c2ecf20Sopenharmony_ci asoc->c.sinit_max_instreams, gfp)) 24498c2ecf20Sopenharmony_ci goto clean_up; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci /* Update frag_point when stream_interleave may get changed. */ 24528c2ecf20Sopenharmony_ci sctp_assoc_update_frag_point(asoc); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci if (!asoc->temp && sctp_assoc_set_id(asoc, gfp)) 24558c2ecf20Sopenharmony_ci goto clean_up; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci /* ADDIP Section 4.1 ASCONF Chunk Procedures 24588c2ecf20Sopenharmony_ci * 24598c2ecf20Sopenharmony_ci * When an endpoint has an ASCONF signaled change to be sent to the 24608c2ecf20Sopenharmony_ci * remote endpoint it should do the following: 24618c2ecf20Sopenharmony_ci * ... 24628c2ecf20Sopenharmony_ci * A2) A serial number should be assigned to the Chunk. The serial 24638c2ecf20Sopenharmony_ci * number should be a monotonically increasing number. All serial 24648c2ecf20Sopenharmony_ci * numbers are defined to be initialized at the start of the 24658c2ecf20Sopenharmony_ci * association to the same value as the Initial TSN. 24668c2ecf20Sopenharmony_ci */ 24678c2ecf20Sopenharmony_ci asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1; 24688c2ecf20Sopenharmony_ci return 1; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ciclean_up: 24718c2ecf20Sopenharmony_ci /* Release the transport structures. */ 24728c2ecf20Sopenharmony_ci list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { 24738c2ecf20Sopenharmony_ci transport = list_entry(pos, struct sctp_transport, transports); 24748c2ecf20Sopenharmony_ci if (transport->state != SCTP_ACTIVE) 24758c2ecf20Sopenharmony_ci sctp_assoc_rm_peer(asoc, transport); 24768c2ecf20Sopenharmony_ci } 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_cinomem: 24798c2ecf20Sopenharmony_ci return 0; 24808c2ecf20Sopenharmony_ci} 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci/* Update asoc with the option described in param. 24848c2ecf20Sopenharmony_ci * 24858c2ecf20Sopenharmony_ci * RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT 24868c2ecf20Sopenharmony_ci * 24878c2ecf20Sopenharmony_ci * asoc is the association to update. 24888c2ecf20Sopenharmony_ci * param is the variable length parameter to use for update. 24898c2ecf20Sopenharmony_ci * cid tells us if this is an INIT, INIT ACK or COOKIE ECHO. 24908c2ecf20Sopenharmony_ci * If the current packet is an INIT we want to minimize the amount of 24918c2ecf20Sopenharmony_ci * work we do. In particular, we should not build transport 24928c2ecf20Sopenharmony_ci * structures for the addresses. 24938c2ecf20Sopenharmony_ci */ 24948c2ecf20Sopenharmony_cistatic int sctp_process_param(struct sctp_association *asoc, 24958c2ecf20Sopenharmony_ci union sctp_params param, 24968c2ecf20Sopenharmony_ci const union sctp_addr *peer_addr, 24978c2ecf20Sopenharmony_ci gfp_t gfp) 24988c2ecf20Sopenharmony_ci{ 24998c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = asoc->ep; 25008c2ecf20Sopenharmony_ci union sctp_addr_param *addr_param; 25018c2ecf20Sopenharmony_ci struct net *net = asoc->base.net; 25028c2ecf20Sopenharmony_ci struct sctp_transport *t; 25038c2ecf20Sopenharmony_ci enum sctp_scope scope; 25048c2ecf20Sopenharmony_ci union sctp_addr addr; 25058c2ecf20Sopenharmony_ci struct sctp_af *af; 25068c2ecf20Sopenharmony_ci int retval = 1, i; 25078c2ecf20Sopenharmony_ci u32 stale; 25088c2ecf20Sopenharmony_ci __u16 sat; 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci /* We maintain all INIT parameters in network byte order all the 25118c2ecf20Sopenharmony_ci * time. This allows us to not worry about whether the parameters 25128c2ecf20Sopenharmony_ci * came from a fresh INIT, and INIT ACK, or were stored in a cookie. 25138c2ecf20Sopenharmony_ci */ 25148c2ecf20Sopenharmony_ci switch (param.p->type) { 25158c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV6_ADDRESS: 25168c2ecf20Sopenharmony_ci if (PF_INET6 != asoc->base.sk->sk_family) 25178c2ecf20Sopenharmony_ci break; 25188c2ecf20Sopenharmony_ci goto do_addr_param; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV4_ADDRESS: 25218c2ecf20Sopenharmony_ci /* v4 addresses are not allowed on v6-only socket */ 25228c2ecf20Sopenharmony_ci if (ipv6_only_sock(asoc->base.sk)) 25238c2ecf20Sopenharmony_ci break; 25248c2ecf20Sopenharmony_cido_addr_param: 25258c2ecf20Sopenharmony_ci af = sctp_get_af_specific(param_type2af(param.p->type)); 25268c2ecf20Sopenharmony_ci if (!af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0)) 25278c2ecf20Sopenharmony_ci break; 25288c2ecf20Sopenharmony_ci scope = sctp_scope(peer_addr); 25298c2ecf20Sopenharmony_ci if (sctp_in_scope(net, &addr, scope)) 25308c2ecf20Sopenharmony_ci if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED)) 25318c2ecf20Sopenharmony_ci return 0; 25328c2ecf20Sopenharmony_ci break; 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci case SCTP_PARAM_COOKIE_PRESERVATIVE: 25358c2ecf20Sopenharmony_ci if (!net->sctp.cookie_preserve_enable) 25368c2ecf20Sopenharmony_ci break; 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci stale = ntohl(param.life->lifespan_increment); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci /* Suggested Cookie Life span increment's unit is msec, 25418c2ecf20Sopenharmony_ci * (1/1000sec). 25428c2ecf20Sopenharmony_ci */ 25438c2ecf20Sopenharmony_ci asoc->cookie_life = ktime_add_ms(asoc->cookie_life, stale); 25448c2ecf20Sopenharmony_ci break; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci case SCTP_PARAM_HOST_NAME_ADDRESS: 25478c2ecf20Sopenharmony_ci pr_debug("%s: unimplemented SCTP_HOST_NAME_ADDRESS\n", __func__); 25488c2ecf20Sopenharmony_ci break; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: 25518c2ecf20Sopenharmony_ci /* Turn off the default values first so we'll know which 25528c2ecf20Sopenharmony_ci * ones are really set by the peer. 25538c2ecf20Sopenharmony_ci */ 25548c2ecf20Sopenharmony_ci asoc->peer.ipv4_address = 0; 25558c2ecf20Sopenharmony_ci asoc->peer.ipv6_address = 0; 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci /* Assume that peer supports the address family 25588c2ecf20Sopenharmony_ci * by which it sends a packet. 25598c2ecf20Sopenharmony_ci */ 25608c2ecf20Sopenharmony_ci if (peer_addr->sa.sa_family == AF_INET6) 25618c2ecf20Sopenharmony_ci asoc->peer.ipv6_address = 1; 25628c2ecf20Sopenharmony_ci else if (peer_addr->sa.sa_family == AF_INET) 25638c2ecf20Sopenharmony_ci asoc->peer.ipv4_address = 1; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci /* Cycle through address types; avoid divide by 0. */ 25668c2ecf20Sopenharmony_ci sat = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); 25678c2ecf20Sopenharmony_ci if (sat) 25688c2ecf20Sopenharmony_ci sat /= sizeof(__u16); 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci for (i = 0; i < sat; ++i) { 25718c2ecf20Sopenharmony_ci switch (param.sat->types[i]) { 25728c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV4_ADDRESS: 25738c2ecf20Sopenharmony_ci asoc->peer.ipv4_address = 1; 25748c2ecf20Sopenharmony_ci break; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV6_ADDRESS: 25778c2ecf20Sopenharmony_ci if (PF_INET6 == asoc->base.sk->sk_family) 25788c2ecf20Sopenharmony_ci asoc->peer.ipv6_address = 1; 25798c2ecf20Sopenharmony_ci break; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci case SCTP_PARAM_HOST_NAME_ADDRESS: 25828c2ecf20Sopenharmony_ci asoc->peer.hostname_address = 1; 25838c2ecf20Sopenharmony_ci break; 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci default: /* Just ignore anything else. */ 25868c2ecf20Sopenharmony_ci break; 25878c2ecf20Sopenharmony_ci } 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci break; 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci case SCTP_PARAM_STATE_COOKIE: 25928c2ecf20Sopenharmony_ci asoc->peer.cookie_len = 25938c2ecf20Sopenharmony_ci ntohs(param.p->length) - sizeof(struct sctp_paramhdr); 25948c2ecf20Sopenharmony_ci kfree(asoc->peer.cookie); 25958c2ecf20Sopenharmony_ci asoc->peer.cookie = kmemdup(param.cookie->body, asoc->peer.cookie_len, gfp); 25968c2ecf20Sopenharmony_ci if (!asoc->peer.cookie) 25978c2ecf20Sopenharmony_ci retval = 0; 25988c2ecf20Sopenharmony_ci break; 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci case SCTP_PARAM_HEARTBEAT_INFO: 26018c2ecf20Sopenharmony_ci /* Would be odd to receive, but it causes no problems. */ 26028c2ecf20Sopenharmony_ci break; 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: 26058c2ecf20Sopenharmony_ci /* Rejected during verify stage. */ 26068c2ecf20Sopenharmony_ci break; 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci case SCTP_PARAM_ECN_CAPABLE: 26098c2ecf20Sopenharmony_ci if (asoc->ep->ecn_enable) { 26108c2ecf20Sopenharmony_ci asoc->peer.ecn_capable = 1; 26118c2ecf20Sopenharmony_ci break; 26128c2ecf20Sopenharmony_ci } 26138c2ecf20Sopenharmony_ci /* Fall Through */ 26148c2ecf20Sopenharmony_ci goto fall_through; 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci case SCTP_PARAM_ADAPTATION_LAYER_IND: 26188c2ecf20Sopenharmony_ci asoc->peer.adaptation_ind = ntohl(param.aind->adaptation_ind); 26198c2ecf20Sopenharmony_ci break; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci case SCTP_PARAM_SET_PRIMARY: 26228c2ecf20Sopenharmony_ci if (!ep->asconf_enable) 26238c2ecf20Sopenharmony_ci goto fall_through; 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci addr_param = param.v + sizeof(struct sctp_addip_param); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci af = sctp_get_af_specific(param_type2af(addr_param->p.type)); 26288c2ecf20Sopenharmony_ci if (!af) 26298c2ecf20Sopenharmony_ci break; 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci if (!af->from_addr_param(&addr, addr_param, 26328c2ecf20Sopenharmony_ci htons(asoc->peer.port), 0)) 26338c2ecf20Sopenharmony_ci break; 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci if (!af->addr_valid(&addr, NULL, NULL)) 26368c2ecf20Sopenharmony_ci break; 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci t = sctp_assoc_lookup_paddr(asoc, &addr); 26398c2ecf20Sopenharmony_ci if (!t) 26408c2ecf20Sopenharmony_ci break; 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci sctp_assoc_set_primary(asoc, t); 26438c2ecf20Sopenharmony_ci break; 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci case SCTP_PARAM_SUPPORTED_EXT: 26468c2ecf20Sopenharmony_ci sctp_process_ext_param(asoc, param); 26478c2ecf20Sopenharmony_ci break; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci case SCTP_PARAM_FWD_TSN_SUPPORT: 26508c2ecf20Sopenharmony_ci if (asoc->ep->prsctp_enable) { 26518c2ecf20Sopenharmony_ci asoc->peer.prsctp_capable = 1; 26528c2ecf20Sopenharmony_ci break; 26538c2ecf20Sopenharmony_ci } 26548c2ecf20Sopenharmony_ci /* Fall Through */ 26558c2ecf20Sopenharmony_ci goto fall_through; 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci case SCTP_PARAM_RANDOM: 26588c2ecf20Sopenharmony_ci if (!ep->auth_enable) 26598c2ecf20Sopenharmony_ci goto fall_through; 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci /* Save peer's random parameter */ 26628c2ecf20Sopenharmony_ci kfree(asoc->peer.peer_random); 26638c2ecf20Sopenharmony_ci asoc->peer.peer_random = kmemdup(param.p, 26648c2ecf20Sopenharmony_ci ntohs(param.p->length), gfp); 26658c2ecf20Sopenharmony_ci if (!asoc->peer.peer_random) { 26668c2ecf20Sopenharmony_ci retval = 0; 26678c2ecf20Sopenharmony_ci break; 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci break; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci case SCTP_PARAM_HMAC_ALGO: 26728c2ecf20Sopenharmony_ci if (!ep->auth_enable) 26738c2ecf20Sopenharmony_ci goto fall_through; 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci /* Save peer's HMAC list */ 26768c2ecf20Sopenharmony_ci kfree(asoc->peer.peer_hmacs); 26778c2ecf20Sopenharmony_ci asoc->peer.peer_hmacs = kmemdup(param.p, 26788c2ecf20Sopenharmony_ci ntohs(param.p->length), gfp); 26798c2ecf20Sopenharmony_ci if (!asoc->peer.peer_hmacs) { 26808c2ecf20Sopenharmony_ci retval = 0; 26818c2ecf20Sopenharmony_ci break; 26828c2ecf20Sopenharmony_ci } 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci /* Set the default HMAC the peer requested*/ 26858c2ecf20Sopenharmony_ci sctp_auth_asoc_set_default_hmac(asoc, param.hmac_algo); 26868c2ecf20Sopenharmony_ci break; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci case SCTP_PARAM_CHUNKS: 26898c2ecf20Sopenharmony_ci if (!ep->auth_enable) 26908c2ecf20Sopenharmony_ci goto fall_through; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci kfree(asoc->peer.peer_chunks); 26938c2ecf20Sopenharmony_ci asoc->peer.peer_chunks = kmemdup(param.p, 26948c2ecf20Sopenharmony_ci ntohs(param.p->length), gfp); 26958c2ecf20Sopenharmony_ci if (!asoc->peer.peer_chunks) 26968c2ecf20Sopenharmony_ci retval = 0; 26978c2ecf20Sopenharmony_ci break; 26988c2ecf20Sopenharmony_cifall_through: 26998c2ecf20Sopenharmony_ci default: 27008c2ecf20Sopenharmony_ci /* Any unrecognized parameters should have been caught 27018c2ecf20Sopenharmony_ci * and handled by sctp_verify_param() which should be 27028c2ecf20Sopenharmony_ci * called prior to this routine. Simply log the error 27038c2ecf20Sopenharmony_ci * here. 27048c2ecf20Sopenharmony_ci */ 27058c2ecf20Sopenharmony_ci pr_debug("%s: ignoring param:%d for association:%p.\n", 27068c2ecf20Sopenharmony_ci __func__, ntohs(param.p->type), asoc); 27078c2ecf20Sopenharmony_ci break; 27088c2ecf20Sopenharmony_ci } 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci return retval; 27118c2ecf20Sopenharmony_ci} 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci/* Select a new verification tag. */ 27148c2ecf20Sopenharmony_ci__u32 sctp_generate_tag(const struct sctp_endpoint *ep) 27158c2ecf20Sopenharmony_ci{ 27168c2ecf20Sopenharmony_ci /* I believe that this random number generator complies with RFC1750. 27178c2ecf20Sopenharmony_ci * A tag of 0 is reserved for special cases (e.g. INIT). 27188c2ecf20Sopenharmony_ci */ 27198c2ecf20Sopenharmony_ci __u32 x; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci do { 27228c2ecf20Sopenharmony_ci get_random_bytes(&x, sizeof(__u32)); 27238c2ecf20Sopenharmony_ci } while (x == 0); 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci return x; 27268c2ecf20Sopenharmony_ci} 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci/* Select an initial TSN to send during startup. */ 27298c2ecf20Sopenharmony_ci__u32 sctp_generate_tsn(const struct sctp_endpoint *ep) 27308c2ecf20Sopenharmony_ci{ 27318c2ecf20Sopenharmony_ci __u32 retval; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci get_random_bytes(&retval, sizeof(__u32)); 27348c2ecf20Sopenharmony_ci return retval; 27358c2ecf20Sopenharmony_ci} 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci/* 27388c2ecf20Sopenharmony_ci * ADDIP 3.1.1 Address Configuration Change Chunk (ASCONF) 27398c2ecf20Sopenharmony_ci * 0 1 2 3 27408c2ecf20Sopenharmony_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 27418c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27428c2ecf20Sopenharmony_ci * | Type = 0xC1 | Chunk Flags | Chunk Length | 27438c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27448c2ecf20Sopenharmony_ci * | Serial Number | 27458c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27468c2ecf20Sopenharmony_ci * | Address Parameter | 27478c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27488c2ecf20Sopenharmony_ci * | ASCONF Parameter #1 | 27498c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27508c2ecf20Sopenharmony_ci * \ \ 27518c2ecf20Sopenharmony_ci * / .... / 27528c2ecf20Sopenharmony_ci * \ \ 27538c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27548c2ecf20Sopenharmony_ci * | ASCONF Parameter #N | 27558c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27568c2ecf20Sopenharmony_ci * 27578c2ecf20Sopenharmony_ci * Address Parameter and other parameter will not be wrapped in this function 27588c2ecf20Sopenharmony_ci */ 27598c2ecf20Sopenharmony_cistatic struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, 27608c2ecf20Sopenharmony_ci union sctp_addr *addr, 27618c2ecf20Sopenharmony_ci int vparam_len) 27628c2ecf20Sopenharmony_ci{ 27638c2ecf20Sopenharmony_ci struct sctp_addiphdr asconf; 27648c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 27658c2ecf20Sopenharmony_ci int length = sizeof(asconf) + vparam_len; 27668c2ecf20Sopenharmony_ci union sctp_addr_param addrparam; 27678c2ecf20Sopenharmony_ci int addrlen; 27688c2ecf20Sopenharmony_ci struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family); 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci addrlen = af->to_addr_param(addr, &addrparam); 27718c2ecf20Sopenharmony_ci if (!addrlen) 27728c2ecf20Sopenharmony_ci return NULL; 27738c2ecf20Sopenharmony_ci length += addrlen; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci /* Create the chunk. */ 27768c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length, 27778c2ecf20Sopenharmony_ci GFP_ATOMIC); 27788c2ecf20Sopenharmony_ci if (!retval) 27798c2ecf20Sopenharmony_ci return NULL; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci asconf.serial = htonl(asoc->addip_serial++); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci retval->subh.addip_hdr = 27848c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(asconf), &asconf); 27858c2ecf20Sopenharmony_ci retval->param_hdr.v = 27868c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, addrlen, &addrparam); 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci return retval; 27898c2ecf20Sopenharmony_ci} 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci/* ADDIP 27928c2ecf20Sopenharmony_ci * 3.2.1 Add IP Address 27938c2ecf20Sopenharmony_ci * 0 1 2 3 27948c2ecf20Sopenharmony_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 27958c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27968c2ecf20Sopenharmony_ci * | Type = 0xC001 | Length = Variable | 27978c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27988c2ecf20Sopenharmony_ci * | ASCONF-Request Correlation ID | 27998c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28008c2ecf20Sopenharmony_ci * | Address Parameter | 28018c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28028c2ecf20Sopenharmony_ci * 28038c2ecf20Sopenharmony_ci * 3.2.2 Delete IP Address 28048c2ecf20Sopenharmony_ci * 0 1 2 3 28058c2ecf20Sopenharmony_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 28068c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28078c2ecf20Sopenharmony_ci * | Type = 0xC002 | Length = Variable | 28088c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28098c2ecf20Sopenharmony_ci * | ASCONF-Request Correlation ID | 28108c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28118c2ecf20Sopenharmony_ci * | Address Parameter | 28128c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28138c2ecf20Sopenharmony_ci * 28148c2ecf20Sopenharmony_ci */ 28158c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc, 28168c2ecf20Sopenharmony_ci union sctp_addr *laddr, 28178c2ecf20Sopenharmony_ci struct sockaddr *addrs, 28188c2ecf20Sopenharmony_ci int addrcnt, __be16 flags) 28198c2ecf20Sopenharmony_ci{ 28208c2ecf20Sopenharmony_ci union sctp_addr_param addr_param; 28218c2ecf20Sopenharmony_ci struct sctp_addip_param param; 28228c2ecf20Sopenharmony_ci int paramlen = sizeof(param); 28238c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 28248c2ecf20Sopenharmony_ci int addr_param_len = 0; 28258c2ecf20Sopenharmony_ci union sctp_addr *addr; 28268c2ecf20Sopenharmony_ci int totallen = 0, i; 28278c2ecf20Sopenharmony_ci int del_pickup = 0; 28288c2ecf20Sopenharmony_ci struct sctp_af *af; 28298c2ecf20Sopenharmony_ci void *addr_buf; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci /* Get total length of all the address parameters. */ 28328c2ecf20Sopenharmony_ci addr_buf = addrs; 28338c2ecf20Sopenharmony_ci for (i = 0; i < addrcnt; i++) { 28348c2ecf20Sopenharmony_ci addr = addr_buf; 28358c2ecf20Sopenharmony_ci af = sctp_get_af_specific(addr->v4.sin_family); 28368c2ecf20Sopenharmony_ci addr_param_len = af->to_addr_param(addr, &addr_param); 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci totallen += paramlen; 28398c2ecf20Sopenharmony_ci totallen += addr_param_len; 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 28428c2ecf20Sopenharmony_ci if (asoc->asconf_addr_del_pending && !del_pickup) { 28438c2ecf20Sopenharmony_ci /* reuse the parameter length from the same scope one */ 28448c2ecf20Sopenharmony_ci totallen += paramlen; 28458c2ecf20Sopenharmony_ci totallen += addr_param_len; 28468c2ecf20Sopenharmony_ci del_pickup = 1; 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci pr_debug("%s: picked same-scope del_pending addr, " 28498c2ecf20Sopenharmony_ci "totallen for all addresses is %d\n", 28508c2ecf20Sopenharmony_ci __func__, totallen); 28518c2ecf20Sopenharmony_ci } 28528c2ecf20Sopenharmony_ci } 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci /* Create an asconf chunk with the required length. */ 28558c2ecf20Sopenharmony_ci retval = sctp_make_asconf(asoc, laddr, totallen); 28568c2ecf20Sopenharmony_ci if (!retval) 28578c2ecf20Sopenharmony_ci return NULL; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci /* Add the address parameters to the asconf chunk. */ 28608c2ecf20Sopenharmony_ci addr_buf = addrs; 28618c2ecf20Sopenharmony_ci for (i = 0; i < addrcnt; i++) { 28628c2ecf20Sopenharmony_ci addr = addr_buf; 28638c2ecf20Sopenharmony_ci af = sctp_get_af_specific(addr->v4.sin_family); 28648c2ecf20Sopenharmony_ci addr_param_len = af->to_addr_param(addr, &addr_param); 28658c2ecf20Sopenharmony_ci param.param_hdr.type = flags; 28668c2ecf20Sopenharmony_ci param.param_hdr.length = htons(paramlen + addr_param_len); 28678c2ecf20Sopenharmony_ci param.crr_id = htonl(i); 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, paramlen, ¶m); 28708c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, addr_param_len, &addr_param); 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 28738c2ecf20Sopenharmony_ci } 28748c2ecf20Sopenharmony_ci if (flags == SCTP_PARAM_ADD_IP && del_pickup) { 28758c2ecf20Sopenharmony_ci addr = asoc->asconf_addr_del_pending; 28768c2ecf20Sopenharmony_ci af = sctp_get_af_specific(addr->v4.sin_family); 28778c2ecf20Sopenharmony_ci addr_param_len = af->to_addr_param(addr, &addr_param); 28788c2ecf20Sopenharmony_ci param.param_hdr.type = SCTP_PARAM_DEL_IP; 28798c2ecf20Sopenharmony_ci param.param_hdr.length = htons(paramlen + addr_param_len); 28808c2ecf20Sopenharmony_ci param.crr_id = htonl(i); 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, paramlen, ¶m); 28838c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, addr_param_len, &addr_param); 28848c2ecf20Sopenharmony_ci } 28858c2ecf20Sopenharmony_ci return retval; 28868c2ecf20Sopenharmony_ci} 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci/* ADDIP 28898c2ecf20Sopenharmony_ci * 3.2.4 Set Primary IP Address 28908c2ecf20Sopenharmony_ci * 0 1 2 3 28918c2ecf20Sopenharmony_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 28928c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28938c2ecf20Sopenharmony_ci * | Type =0xC004 | Length = Variable | 28948c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28958c2ecf20Sopenharmony_ci * | ASCONF-Request Correlation ID | 28968c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28978c2ecf20Sopenharmony_ci * | Address Parameter | 28988c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28998c2ecf20Sopenharmony_ci * 29008c2ecf20Sopenharmony_ci * Create an ASCONF chunk with Set Primary IP address parameter. 29018c2ecf20Sopenharmony_ci */ 29028c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, 29038c2ecf20Sopenharmony_ci union sctp_addr *addr) 29048c2ecf20Sopenharmony_ci{ 29058c2ecf20Sopenharmony_ci struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family); 29068c2ecf20Sopenharmony_ci union sctp_addr_param addrparam; 29078c2ecf20Sopenharmony_ci struct sctp_addip_param param; 29088c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 29098c2ecf20Sopenharmony_ci int len = sizeof(param); 29108c2ecf20Sopenharmony_ci int addrlen; 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci addrlen = af->to_addr_param(addr, &addrparam); 29138c2ecf20Sopenharmony_ci if (!addrlen) 29148c2ecf20Sopenharmony_ci return NULL; 29158c2ecf20Sopenharmony_ci len += addrlen; 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci /* Create the chunk and make asconf header. */ 29188c2ecf20Sopenharmony_ci retval = sctp_make_asconf(asoc, addr, len); 29198c2ecf20Sopenharmony_ci if (!retval) 29208c2ecf20Sopenharmony_ci return NULL; 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci param.param_hdr.type = SCTP_PARAM_SET_PRIMARY; 29238c2ecf20Sopenharmony_ci param.param_hdr.length = htons(len); 29248c2ecf20Sopenharmony_ci param.crr_id = 0; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(param), ¶m); 29278c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, addrlen, &addrparam); 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci return retval; 29308c2ecf20Sopenharmony_ci} 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci/* ADDIP 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK) 29338c2ecf20Sopenharmony_ci * 0 1 2 3 29348c2ecf20Sopenharmony_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 29358c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 29368c2ecf20Sopenharmony_ci * | Type = 0x80 | Chunk Flags | Chunk Length | 29378c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 29388c2ecf20Sopenharmony_ci * | Serial Number | 29398c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 29408c2ecf20Sopenharmony_ci * | ASCONF Parameter Response#1 | 29418c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 29428c2ecf20Sopenharmony_ci * \ \ 29438c2ecf20Sopenharmony_ci * / .... / 29448c2ecf20Sopenharmony_ci * \ \ 29458c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 29468c2ecf20Sopenharmony_ci * | ASCONF Parameter Response#N | 29478c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 29488c2ecf20Sopenharmony_ci * 29498c2ecf20Sopenharmony_ci * Create an ASCONF_ACK chunk with enough space for the parameter responses. 29508c2ecf20Sopenharmony_ci */ 29518c2ecf20Sopenharmony_cistatic struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc, 29528c2ecf20Sopenharmony_ci __u32 serial, int vparam_len) 29538c2ecf20Sopenharmony_ci{ 29548c2ecf20Sopenharmony_ci struct sctp_addiphdr asconf; 29558c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 29568c2ecf20Sopenharmony_ci int length = sizeof(asconf) + vparam_len; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci /* Create the chunk. */ 29598c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length, 29608c2ecf20Sopenharmony_ci GFP_ATOMIC); 29618c2ecf20Sopenharmony_ci if (!retval) 29628c2ecf20Sopenharmony_ci return NULL; 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci asconf.serial = htonl(serial); 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci retval->subh.addip_hdr = 29678c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(asconf), &asconf); 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci return retval; 29708c2ecf20Sopenharmony_ci} 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci/* Add response parameters to an ASCONF_ACK chunk. */ 29738c2ecf20Sopenharmony_cistatic void sctp_add_asconf_response(struct sctp_chunk *chunk, __be32 crr_id, 29748c2ecf20Sopenharmony_ci __be16 err_code, 29758c2ecf20Sopenharmony_ci struct sctp_addip_param *asconf_param) 29768c2ecf20Sopenharmony_ci{ 29778c2ecf20Sopenharmony_ci struct sctp_addip_param ack_param; 29788c2ecf20Sopenharmony_ci struct sctp_errhdr err_param; 29798c2ecf20Sopenharmony_ci int asconf_param_len = 0; 29808c2ecf20Sopenharmony_ci int err_param_len = 0; 29818c2ecf20Sopenharmony_ci __be16 response_type; 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci if (SCTP_ERROR_NO_ERROR == err_code) { 29848c2ecf20Sopenharmony_ci response_type = SCTP_PARAM_SUCCESS_REPORT; 29858c2ecf20Sopenharmony_ci } else { 29868c2ecf20Sopenharmony_ci response_type = SCTP_PARAM_ERR_CAUSE; 29878c2ecf20Sopenharmony_ci err_param_len = sizeof(err_param); 29888c2ecf20Sopenharmony_ci if (asconf_param) 29898c2ecf20Sopenharmony_ci asconf_param_len = 29908c2ecf20Sopenharmony_ci ntohs(asconf_param->param_hdr.length); 29918c2ecf20Sopenharmony_ci } 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci /* Add Success Indication or Error Cause Indication parameter. */ 29948c2ecf20Sopenharmony_ci ack_param.param_hdr.type = response_type; 29958c2ecf20Sopenharmony_ci ack_param.param_hdr.length = htons(sizeof(ack_param) + 29968c2ecf20Sopenharmony_ci err_param_len + 29978c2ecf20Sopenharmony_ci asconf_param_len); 29988c2ecf20Sopenharmony_ci ack_param.crr_id = crr_id; 29998c2ecf20Sopenharmony_ci sctp_addto_chunk(chunk, sizeof(ack_param), &ack_param); 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci if (SCTP_ERROR_NO_ERROR == err_code) 30028c2ecf20Sopenharmony_ci return; 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci /* Add Error Cause parameter. */ 30058c2ecf20Sopenharmony_ci err_param.cause = err_code; 30068c2ecf20Sopenharmony_ci err_param.length = htons(err_param_len + asconf_param_len); 30078c2ecf20Sopenharmony_ci sctp_addto_chunk(chunk, err_param_len, &err_param); 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci /* Add the failed TLV copied from ASCONF chunk. */ 30108c2ecf20Sopenharmony_ci if (asconf_param) 30118c2ecf20Sopenharmony_ci sctp_addto_chunk(chunk, asconf_param_len, asconf_param); 30128c2ecf20Sopenharmony_ci} 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci/* Process a asconf parameter. */ 30158c2ecf20Sopenharmony_cistatic __be16 sctp_process_asconf_param(struct sctp_association *asoc, 30168c2ecf20Sopenharmony_ci struct sctp_chunk *asconf, 30178c2ecf20Sopenharmony_ci struct sctp_addip_param *asconf_param) 30188c2ecf20Sopenharmony_ci{ 30198c2ecf20Sopenharmony_ci union sctp_addr_param *addr_param; 30208c2ecf20Sopenharmony_ci struct sctp_transport *peer; 30218c2ecf20Sopenharmony_ci union sctp_addr addr; 30228c2ecf20Sopenharmony_ci struct sctp_af *af; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci addr_param = (void *)asconf_param + sizeof(*asconf_param); 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP && 30278c2ecf20Sopenharmony_ci asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP && 30288c2ecf20Sopenharmony_ci asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY) 30298c2ecf20Sopenharmony_ci return SCTP_ERROR_UNKNOWN_PARAM; 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci switch (addr_param->p.type) { 30328c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV6_ADDRESS: 30338c2ecf20Sopenharmony_ci if (!asoc->peer.ipv6_address) 30348c2ecf20Sopenharmony_ci return SCTP_ERROR_DNS_FAILED; 30358c2ecf20Sopenharmony_ci break; 30368c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV4_ADDRESS: 30378c2ecf20Sopenharmony_ci if (!asoc->peer.ipv4_address) 30388c2ecf20Sopenharmony_ci return SCTP_ERROR_DNS_FAILED; 30398c2ecf20Sopenharmony_ci break; 30408c2ecf20Sopenharmony_ci default: 30418c2ecf20Sopenharmony_ci return SCTP_ERROR_DNS_FAILED; 30428c2ecf20Sopenharmony_ci } 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci af = sctp_get_af_specific(param_type2af(addr_param->p.type)); 30458c2ecf20Sopenharmony_ci if (unlikely(!af)) 30468c2ecf20Sopenharmony_ci return SCTP_ERROR_DNS_FAILED; 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci if (!af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0)) 30498c2ecf20Sopenharmony_ci return SCTP_ERROR_DNS_FAILED; 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci /* ADDIP 4.2.1 This parameter MUST NOT contain a broadcast 30528c2ecf20Sopenharmony_ci * or multicast address. 30538c2ecf20Sopenharmony_ci * (note: wildcard is permitted and requires special handling so 30548c2ecf20Sopenharmony_ci * make sure we check for that) 30558c2ecf20Sopenharmony_ci */ 30568c2ecf20Sopenharmony_ci if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb)) 30578c2ecf20Sopenharmony_ci return SCTP_ERROR_DNS_FAILED; 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci switch (asconf_param->param_hdr.type) { 30608c2ecf20Sopenharmony_ci case SCTP_PARAM_ADD_IP: 30618c2ecf20Sopenharmony_ci /* Section 4.2.1: 30628c2ecf20Sopenharmony_ci * If the address 0.0.0.0 or ::0 is provided, the source 30638c2ecf20Sopenharmony_ci * address of the packet MUST be added. 30648c2ecf20Sopenharmony_ci */ 30658c2ecf20Sopenharmony_ci if (af->is_any(&addr)) 30668c2ecf20Sopenharmony_ci memcpy(&addr, &asconf->source, sizeof(addr)); 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci if (security_sctp_bind_connect(asoc->ep->base.sk, 30698c2ecf20Sopenharmony_ci SCTP_PARAM_ADD_IP, 30708c2ecf20Sopenharmony_ci (struct sockaddr *)&addr, 30718c2ecf20Sopenharmony_ci af->sockaddr_len)) 30728c2ecf20Sopenharmony_ci return SCTP_ERROR_REQ_REFUSED; 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci /* ADDIP 4.3 D9) If an endpoint receives an ADD IP address 30758c2ecf20Sopenharmony_ci * request and does not have the local resources to add this 30768c2ecf20Sopenharmony_ci * new address to the association, it MUST return an Error 30778c2ecf20Sopenharmony_ci * Cause TLV set to the new error code 'Operation Refused 30788c2ecf20Sopenharmony_ci * Due to Resource Shortage'. 30798c2ecf20Sopenharmony_ci */ 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_UNCONFIRMED); 30828c2ecf20Sopenharmony_ci if (!peer) 30838c2ecf20Sopenharmony_ci return SCTP_ERROR_RSRC_LOW; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci /* Start the heartbeat timer. */ 30868c2ecf20Sopenharmony_ci sctp_transport_reset_hb_timer(peer); 30878c2ecf20Sopenharmony_ci asoc->new_transport = peer; 30888c2ecf20Sopenharmony_ci break; 30898c2ecf20Sopenharmony_ci case SCTP_PARAM_DEL_IP: 30908c2ecf20Sopenharmony_ci /* ADDIP 4.3 D7) If a request is received to delete the 30918c2ecf20Sopenharmony_ci * last remaining IP address of a peer endpoint, the receiver 30928c2ecf20Sopenharmony_ci * MUST send an Error Cause TLV with the error cause set to the 30938c2ecf20Sopenharmony_ci * new error code 'Request to Delete Last Remaining IP Address'. 30948c2ecf20Sopenharmony_ci */ 30958c2ecf20Sopenharmony_ci if (asoc->peer.transport_count == 1) 30968c2ecf20Sopenharmony_ci return SCTP_ERROR_DEL_LAST_IP; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci /* ADDIP 4.3 D8) If a request is received to delete an IP 30998c2ecf20Sopenharmony_ci * address which is also the source address of the IP packet 31008c2ecf20Sopenharmony_ci * which contained the ASCONF chunk, the receiver MUST reject 31018c2ecf20Sopenharmony_ci * this request. To reject the request the receiver MUST send 31028c2ecf20Sopenharmony_ci * an Error Cause TLV set to the new error code 'Request to 31038c2ecf20Sopenharmony_ci * Delete Source IP Address' 31048c2ecf20Sopenharmony_ci */ 31058c2ecf20Sopenharmony_ci if (sctp_cmp_addr_exact(&asconf->source, &addr)) 31068c2ecf20Sopenharmony_ci return SCTP_ERROR_DEL_SRC_IP; 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci /* Section 4.2.2 31098c2ecf20Sopenharmony_ci * If the address 0.0.0.0 or ::0 is provided, all 31108c2ecf20Sopenharmony_ci * addresses of the peer except the source address of the 31118c2ecf20Sopenharmony_ci * packet MUST be deleted. 31128c2ecf20Sopenharmony_ci */ 31138c2ecf20Sopenharmony_ci if (af->is_any(&addr)) { 31148c2ecf20Sopenharmony_ci sctp_assoc_set_primary(asoc, asconf->transport); 31158c2ecf20Sopenharmony_ci sctp_assoc_del_nonprimary_peers(asoc, 31168c2ecf20Sopenharmony_ci asconf->transport); 31178c2ecf20Sopenharmony_ci return SCTP_ERROR_NO_ERROR; 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci /* If the address is not part of the association, the 31218c2ecf20Sopenharmony_ci * ASCONF-ACK with Error Cause Indication Parameter 31228c2ecf20Sopenharmony_ci * which including cause of Unresolvable Address should 31238c2ecf20Sopenharmony_ci * be sent. 31248c2ecf20Sopenharmony_ci */ 31258c2ecf20Sopenharmony_ci peer = sctp_assoc_lookup_paddr(asoc, &addr); 31268c2ecf20Sopenharmony_ci if (!peer) 31278c2ecf20Sopenharmony_ci return SCTP_ERROR_DNS_FAILED; 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci sctp_assoc_rm_peer(asoc, peer); 31308c2ecf20Sopenharmony_ci break; 31318c2ecf20Sopenharmony_ci case SCTP_PARAM_SET_PRIMARY: 31328c2ecf20Sopenharmony_ci /* ADDIP Section 4.2.4 31338c2ecf20Sopenharmony_ci * If the address 0.0.0.0 or ::0 is provided, the receiver 31348c2ecf20Sopenharmony_ci * MAY mark the source address of the packet as its 31358c2ecf20Sopenharmony_ci * primary. 31368c2ecf20Sopenharmony_ci */ 31378c2ecf20Sopenharmony_ci if (af->is_any(&addr)) 31388c2ecf20Sopenharmony_ci memcpy(&addr, sctp_source(asconf), sizeof(addr)); 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci if (security_sctp_bind_connect(asoc->ep->base.sk, 31418c2ecf20Sopenharmony_ci SCTP_PARAM_SET_PRIMARY, 31428c2ecf20Sopenharmony_ci (struct sockaddr *)&addr, 31438c2ecf20Sopenharmony_ci af->sockaddr_len)) 31448c2ecf20Sopenharmony_ci return SCTP_ERROR_REQ_REFUSED; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci peer = sctp_assoc_lookup_paddr(asoc, &addr); 31478c2ecf20Sopenharmony_ci if (!peer) 31488c2ecf20Sopenharmony_ci return SCTP_ERROR_DNS_FAILED; 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci sctp_assoc_set_primary(asoc, peer); 31518c2ecf20Sopenharmony_ci break; 31528c2ecf20Sopenharmony_ci } 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci return SCTP_ERROR_NO_ERROR; 31558c2ecf20Sopenharmony_ci} 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci/* Verify the ASCONF packet before we process it. */ 31588c2ecf20Sopenharmony_cibool sctp_verify_asconf(const struct sctp_association *asoc, 31598c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, bool addr_param_needed, 31608c2ecf20Sopenharmony_ci struct sctp_paramhdr **errp) 31618c2ecf20Sopenharmony_ci{ 31628c2ecf20Sopenharmony_ci struct sctp_addip_chunk *addip; 31638c2ecf20Sopenharmony_ci bool addr_param_seen = false; 31648c2ecf20Sopenharmony_ci union sctp_params param; 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci addip = (struct sctp_addip_chunk *)chunk->chunk_hdr; 31678c2ecf20Sopenharmony_ci sctp_walk_params(param, addip, addip_hdr.params) { 31688c2ecf20Sopenharmony_ci size_t length = ntohs(param.p->length); 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci *errp = param.p; 31718c2ecf20Sopenharmony_ci switch (param.p->type) { 31728c2ecf20Sopenharmony_ci case SCTP_PARAM_ERR_CAUSE: 31738c2ecf20Sopenharmony_ci break; 31748c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV4_ADDRESS: 31758c2ecf20Sopenharmony_ci if (length != sizeof(struct sctp_ipv4addr_param)) 31768c2ecf20Sopenharmony_ci return false; 31778c2ecf20Sopenharmony_ci /* ensure there is only one addr param and it's in the 31788c2ecf20Sopenharmony_ci * beginning of addip_hdr params, or we reject it. 31798c2ecf20Sopenharmony_ci */ 31808c2ecf20Sopenharmony_ci if (param.v != addip->addip_hdr.params) 31818c2ecf20Sopenharmony_ci return false; 31828c2ecf20Sopenharmony_ci addr_param_seen = true; 31838c2ecf20Sopenharmony_ci break; 31848c2ecf20Sopenharmony_ci case SCTP_PARAM_IPV6_ADDRESS: 31858c2ecf20Sopenharmony_ci if (length != sizeof(struct sctp_ipv6addr_param)) 31868c2ecf20Sopenharmony_ci return false; 31878c2ecf20Sopenharmony_ci if (param.v != addip->addip_hdr.params) 31888c2ecf20Sopenharmony_ci return false; 31898c2ecf20Sopenharmony_ci addr_param_seen = true; 31908c2ecf20Sopenharmony_ci break; 31918c2ecf20Sopenharmony_ci case SCTP_PARAM_ADD_IP: 31928c2ecf20Sopenharmony_ci case SCTP_PARAM_DEL_IP: 31938c2ecf20Sopenharmony_ci case SCTP_PARAM_SET_PRIMARY: 31948c2ecf20Sopenharmony_ci /* In ASCONF chunks, these need to be first. */ 31958c2ecf20Sopenharmony_ci if (addr_param_needed && !addr_param_seen) 31968c2ecf20Sopenharmony_ci return false; 31978c2ecf20Sopenharmony_ci length = ntohs(param.addip->param_hdr.length); 31988c2ecf20Sopenharmony_ci if (length < sizeof(struct sctp_addip_param) + 31998c2ecf20Sopenharmony_ci sizeof(**errp)) 32008c2ecf20Sopenharmony_ci return false; 32018c2ecf20Sopenharmony_ci break; 32028c2ecf20Sopenharmony_ci case SCTP_PARAM_SUCCESS_REPORT: 32038c2ecf20Sopenharmony_ci case SCTP_PARAM_ADAPTATION_LAYER_IND: 32048c2ecf20Sopenharmony_ci if (length != sizeof(struct sctp_addip_param)) 32058c2ecf20Sopenharmony_ci return false; 32068c2ecf20Sopenharmony_ci break; 32078c2ecf20Sopenharmony_ci default: 32088c2ecf20Sopenharmony_ci /* This is unkown to us, reject! */ 32098c2ecf20Sopenharmony_ci return false; 32108c2ecf20Sopenharmony_ci } 32118c2ecf20Sopenharmony_ci } 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci /* Remaining sanity checks. */ 32148c2ecf20Sopenharmony_ci if (addr_param_needed && !addr_param_seen) 32158c2ecf20Sopenharmony_ci return false; 32168c2ecf20Sopenharmony_ci if (!addr_param_needed && addr_param_seen) 32178c2ecf20Sopenharmony_ci return false; 32188c2ecf20Sopenharmony_ci if (param.v != chunk->chunk_end) 32198c2ecf20Sopenharmony_ci return false; 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci return true; 32228c2ecf20Sopenharmony_ci} 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci/* Process an incoming ASCONF chunk with the next expected serial no. and 32258c2ecf20Sopenharmony_ci * return an ASCONF_ACK chunk to be sent in response. 32268c2ecf20Sopenharmony_ci */ 32278c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, 32288c2ecf20Sopenharmony_ci struct sctp_chunk *asconf) 32298c2ecf20Sopenharmony_ci{ 32308c2ecf20Sopenharmony_ci union sctp_addr_param *addr_param; 32318c2ecf20Sopenharmony_ci struct sctp_addip_chunk *addip; 32328c2ecf20Sopenharmony_ci struct sctp_chunk *asconf_ack; 32338c2ecf20Sopenharmony_ci bool all_param_pass = true; 32348c2ecf20Sopenharmony_ci struct sctp_addiphdr *hdr; 32358c2ecf20Sopenharmony_ci int length = 0, chunk_len; 32368c2ecf20Sopenharmony_ci union sctp_params param; 32378c2ecf20Sopenharmony_ci __be16 err_code; 32388c2ecf20Sopenharmony_ci __u32 serial; 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci addip = (struct sctp_addip_chunk *)asconf->chunk_hdr; 32418c2ecf20Sopenharmony_ci chunk_len = ntohs(asconf->chunk_hdr->length) - 32428c2ecf20Sopenharmony_ci sizeof(struct sctp_chunkhdr); 32438c2ecf20Sopenharmony_ci hdr = (struct sctp_addiphdr *)asconf->skb->data; 32448c2ecf20Sopenharmony_ci serial = ntohl(hdr->serial); 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci /* Skip the addiphdr and store a pointer to address parameter. */ 32478c2ecf20Sopenharmony_ci length = sizeof(*hdr); 32488c2ecf20Sopenharmony_ci addr_param = (union sctp_addr_param *)(asconf->skb->data + length); 32498c2ecf20Sopenharmony_ci chunk_len -= length; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci /* Skip the address parameter and store a pointer to the first 32528c2ecf20Sopenharmony_ci * asconf parameter. 32538c2ecf20Sopenharmony_ci */ 32548c2ecf20Sopenharmony_ci length = ntohs(addr_param->p.length); 32558c2ecf20Sopenharmony_ci chunk_len -= length; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci /* create an ASCONF_ACK chunk. 32588c2ecf20Sopenharmony_ci * Based on the definitions of parameters, we know that the size of 32598c2ecf20Sopenharmony_ci * ASCONF_ACK parameters are less than or equal to the fourfold of ASCONF 32608c2ecf20Sopenharmony_ci * parameters. 32618c2ecf20Sopenharmony_ci */ 32628c2ecf20Sopenharmony_ci asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 4); 32638c2ecf20Sopenharmony_ci if (!asconf_ack) 32648c2ecf20Sopenharmony_ci goto done; 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci /* Process the TLVs contained within the ASCONF chunk. */ 32678c2ecf20Sopenharmony_ci sctp_walk_params(param, addip, addip_hdr.params) { 32688c2ecf20Sopenharmony_ci /* Skip preceeding address parameters. */ 32698c2ecf20Sopenharmony_ci if (param.p->type == SCTP_PARAM_IPV4_ADDRESS || 32708c2ecf20Sopenharmony_ci param.p->type == SCTP_PARAM_IPV6_ADDRESS) 32718c2ecf20Sopenharmony_ci continue; 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci err_code = sctp_process_asconf_param(asoc, asconf, 32748c2ecf20Sopenharmony_ci param.addip); 32758c2ecf20Sopenharmony_ci /* ADDIP 4.1 A7) 32768c2ecf20Sopenharmony_ci * If an error response is received for a TLV parameter, 32778c2ecf20Sopenharmony_ci * all TLVs with no response before the failed TLV are 32788c2ecf20Sopenharmony_ci * considered successful if not reported. All TLVs after 32798c2ecf20Sopenharmony_ci * the failed response are considered unsuccessful unless 32808c2ecf20Sopenharmony_ci * a specific success indication is present for the parameter. 32818c2ecf20Sopenharmony_ci */ 32828c2ecf20Sopenharmony_ci if (err_code != SCTP_ERROR_NO_ERROR) 32838c2ecf20Sopenharmony_ci all_param_pass = false; 32848c2ecf20Sopenharmony_ci if (!all_param_pass) 32858c2ecf20Sopenharmony_ci sctp_add_asconf_response(asconf_ack, param.addip->crr_id, 32868c2ecf20Sopenharmony_ci err_code, param.addip); 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci /* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add 32898c2ecf20Sopenharmony_ci * an IP address sends an 'Out of Resource' in its response, it 32908c2ecf20Sopenharmony_ci * MUST also fail any subsequent add or delete requests bundled 32918c2ecf20Sopenharmony_ci * in the ASCONF. 32928c2ecf20Sopenharmony_ci */ 32938c2ecf20Sopenharmony_ci if (err_code == SCTP_ERROR_RSRC_LOW) 32948c2ecf20Sopenharmony_ci goto done; 32958c2ecf20Sopenharmony_ci } 32968c2ecf20Sopenharmony_cidone: 32978c2ecf20Sopenharmony_ci asoc->peer.addip_serial++; 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci /* If we are sending a new ASCONF_ACK hold a reference to it in assoc 33008c2ecf20Sopenharmony_ci * after freeing the reference to old asconf ack if any. 33018c2ecf20Sopenharmony_ci */ 33028c2ecf20Sopenharmony_ci if (asconf_ack) { 33038c2ecf20Sopenharmony_ci sctp_chunk_hold(asconf_ack); 33048c2ecf20Sopenharmony_ci list_add_tail(&asconf_ack->transmitted_list, 33058c2ecf20Sopenharmony_ci &asoc->asconf_ack_list); 33068c2ecf20Sopenharmony_ci } 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci return asconf_ack; 33098c2ecf20Sopenharmony_ci} 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci/* Process a asconf parameter that is successfully acked. */ 33128c2ecf20Sopenharmony_cistatic void sctp_asconf_param_success(struct sctp_association *asoc, 33138c2ecf20Sopenharmony_ci struct sctp_addip_param *asconf_param) 33148c2ecf20Sopenharmony_ci{ 33158c2ecf20Sopenharmony_ci struct sctp_bind_addr *bp = &asoc->base.bind_addr; 33168c2ecf20Sopenharmony_ci union sctp_addr_param *addr_param; 33178c2ecf20Sopenharmony_ci struct sctp_sockaddr_entry *saddr; 33188c2ecf20Sopenharmony_ci struct sctp_transport *transport; 33198c2ecf20Sopenharmony_ci union sctp_addr addr; 33208c2ecf20Sopenharmony_ci struct sctp_af *af; 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci addr_param = (void *)asconf_param + sizeof(*asconf_param); 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ci /* We have checked the packet before, so we do not check again. */ 33258c2ecf20Sopenharmony_ci af = sctp_get_af_specific(param_type2af(addr_param->p.type)); 33268c2ecf20Sopenharmony_ci if (!af->from_addr_param(&addr, addr_param, htons(bp->port), 0)) 33278c2ecf20Sopenharmony_ci return; 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci switch (asconf_param->param_hdr.type) { 33308c2ecf20Sopenharmony_ci case SCTP_PARAM_ADD_IP: 33318c2ecf20Sopenharmony_ci /* This is always done in BH context with a socket lock 33328c2ecf20Sopenharmony_ci * held, so the list can not change. 33338c2ecf20Sopenharmony_ci */ 33348c2ecf20Sopenharmony_ci local_bh_disable(); 33358c2ecf20Sopenharmony_ci list_for_each_entry(saddr, &bp->address_list, list) { 33368c2ecf20Sopenharmony_ci if (sctp_cmp_addr_exact(&saddr->a, &addr)) 33378c2ecf20Sopenharmony_ci saddr->state = SCTP_ADDR_SRC; 33388c2ecf20Sopenharmony_ci } 33398c2ecf20Sopenharmony_ci local_bh_enable(); 33408c2ecf20Sopenharmony_ci list_for_each_entry(transport, &asoc->peer.transport_addr_list, 33418c2ecf20Sopenharmony_ci transports) { 33428c2ecf20Sopenharmony_ci sctp_transport_dst_release(transport); 33438c2ecf20Sopenharmony_ci } 33448c2ecf20Sopenharmony_ci break; 33458c2ecf20Sopenharmony_ci case SCTP_PARAM_DEL_IP: 33468c2ecf20Sopenharmony_ci local_bh_disable(); 33478c2ecf20Sopenharmony_ci sctp_del_bind_addr(bp, &addr); 33488c2ecf20Sopenharmony_ci if (asoc->asconf_addr_del_pending != NULL && 33498c2ecf20Sopenharmony_ci sctp_cmp_addr_exact(asoc->asconf_addr_del_pending, &addr)) { 33508c2ecf20Sopenharmony_ci kfree(asoc->asconf_addr_del_pending); 33518c2ecf20Sopenharmony_ci asoc->asconf_addr_del_pending = NULL; 33528c2ecf20Sopenharmony_ci } 33538c2ecf20Sopenharmony_ci local_bh_enable(); 33548c2ecf20Sopenharmony_ci list_for_each_entry(transport, &asoc->peer.transport_addr_list, 33558c2ecf20Sopenharmony_ci transports) { 33568c2ecf20Sopenharmony_ci sctp_transport_dst_release(transport); 33578c2ecf20Sopenharmony_ci } 33588c2ecf20Sopenharmony_ci break; 33598c2ecf20Sopenharmony_ci default: 33608c2ecf20Sopenharmony_ci break; 33618c2ecf20Sopenharmony_ci } 33628c2ecf20Sopenharmony_ci} 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci/* Get the corresponding ASCONF response error code from the ASCONF_ACK chunk 33658c2ecf20Sopenharmony_ci * for the given asconf parameter. If there is no response for this parameter, 33668c2ecf20Sopenharmony_ci * return the error code based on the third argument 'no_err'. 33678c2ecf20Sopenharmony_ci * ADDIP 4.1 33688c2ecf20Sopenharmony_ci * A7) If an error response is received for a TLV parameter, all TLVs with no 33698c2ecf20Sopenharmony_ci * response before the failed TLV are considered successful if not reported. 33708c2ecf20Sopenharmony_ci * All TLVs after the failed response are considered unsuccessful unless a 33718c2ecf20Sopenharmony_ci * specific success indication is present for the parameter. 33728c2ecf20Sopenharmony_ci */ 33738c2ecf20Sopenharmony_cistatic __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack, 33748c2ecf20Sopenharmony_ci struct sctp_addip_param *asconf_param, 33758c2ecf20Sopenharmony_ci int no_err) 33768c2ecf20Sopenharmony_ci{ 33778c2ecf20Sopenharmony_ci struct sctp_addip_param *asconf_ack_param; 33788c2ecf20Sopenharmony_ci struct sctp_errhdr *err_param; 33798c2ecf20Sopenharmony_ci int asconf_ack_len; 33808c2ecf20Sopenharmony_ci __be16 err_code; 33818c2ecf20Sopenharmony_ci int length; 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci if (no_err) 33848c2ecf20Sopenharmony_ci err_code = SCTP_ERROR_NO_ERROR; 33858c2ecf20Sopenharmony_ci else 33868c2ecf20Sopenharmony_ci err_code = SCTP_ERROR_REQ_REFUSED; 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci asconf_ack_len = ntohs(asconf_ack->chunk_hdr->length) - 33898c2ecf20Sopenharmony_ci sizeof(struct sctp_chunkhdr); 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci /* Skip the addiphdr from the asconf_ack chunk and store a pointer to 33928c2ecf20Sopenharmony_ci * the first asconf_ack parameter. 33938c2ecf20Sopenharmony_ci */ 33948c2ecf20Sopenharmony_ci length = sizeof(struct sctp_addiphdr); 33958c2ecf20Sopenharmony_ci asconf_ack_param = (struct sctp_addip_param *)(asconf_ack->skb->data + 33968c2ecf20Sopenharmony_ci length); 33978c2ecf20Sopenharmony_ci asconf_ack_len -= length; 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci while (asconf_ack_len > 0) { 34008c2ecf20Sopenharmony_ci if (asconf_ack_param->crr_id == asconf_param->crr_id) { 34018c2ecf20Sopenharmony_ci switch (asconf_ack_param->param_hdr.type) { 34028c2ecf20Sopenharmony_ci case SCTP_PARAM_SUCCESS_REPORT: 34038c2ecf20Sopenharmony_ci return SCTP_ERROR_NO_ERROR; 34048c2ecf20Sopenharmony_ci case SCTP_PARAM_ERR_CAUSE: 34058c2ecf20Sopenharmony_ci length = sizeof(*asconf_ack_param); 34068c2ecf20Sopenharmony_ci err_param = (void *)asconf_ack_param + length; 34078c2ecf20Sopenharmony_ci asconf_ack_len -= length; 34088c2ecf20Sopenharmony_ci if (asconf_ack_len > 0) 34098c2ecf20Sopenharmony_ci return err_param->cause; 34108c2ecf20Sopenharmony_ci else 34118c2ecf20Sopenharmony_ci return SCTP_ERROR_INV_PARAM; 34128c2ecf20Sopenharmony_ci break; 34138c2ecf20Sopenharmony_ci default: 34148c2ecf20Sopenharmony_ci return SCTP_ERROR_INV_PARAM; 34158c2ecf20Sopenharmony_ci } 34168c2ecf20Sopenharmony_ci } 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci length = ntohs(asconf_ack_param->param_hdr.length); 34198c2ecf20Sopenharmony_ci asconf_ack_param = (void *)asconf_ack_param + length; 34208c2ecf20Sopenharmony_ci asconf_ack_len -= length; 34218c2ecf20Sopenharmony_ci } 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci return err_code; 34248c2ecf20Sopenharmony_ci} 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci/* Process an incoming ASCONF_ACK chunk against the cached last ASCONF chunk. */ 34278c2ecf20Sopenharmony_ciint sctp_process_asconf_ack(struct sctp_association *asoc, 34288c2ecf20Sopenharmony_ci struct sctp_chunk *asconf_ack) 34298c2ecf20Sopenharmony_ci{ 34308c2ecf20Sopenharmony_ci struct sctp_chunk *asconf = asoc->addip_last_asconf; 34318c2ecf20Sopenharmony_ci struct sctp_addip_param *asconf_param; 34328c2ecf20Sopenharmony_ci __be16 err_code = SCTP_ERROR_NO_ERROR; 34338c2ecf20Sopenharmony_ci union sctp_addr_param *addr_param; 34348c2ecf20Sopenharmony_ci int asconf_len = asconf->skb->len; 34358c2ecf20Sopenharmony_ci int all_param_pass = 0; 34368c2ecf20Sopenharmony_ci int length = 0; 34378c2ecf20Sopenharmony_ci int no_err = 1; 34388c2ecf20Sopenharmony_ci int retval = 0; 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci /* Skip the chunkhdr and addiphdr from the last asconf sent and store 34418c2ecf20Sopenharmony_ci * a pointer to address parameter. 34428c2ecf20Sopenharmony_ci */ 34438c2ecf20Sopenharmony_ci length = sizeof(struct sctp_addip_chunk); 34448c2ecf20Sopenharmony_ci addr_param = (union sctp_addr_param *)(asconf->skb->data + length); 34458c2ecf20Sopenharmony_ci asconf_len -= length; 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci /* Skip the address parameter in the last asconf sent and store a 34488c2ecf20Sopenharmony_ci * pointer to the first asconf parameter. 34498c2ecf20Sopenharmony_ci */ 34508c2ecf20Sopenharmony_ci length = ntohs(addr_param->p.length); 34518c2ecf20Sopenharmony_ci asconf_param = (void *)addr_param + length; 34528c2ecf20Sopenharmony_ci asconf_len -= length; 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci /* ADDIP 4.1 34558c2ecf20Sopenharmony_ci * A8) If there is no response(s) to specific TLV parameter(s), and no 34568c2ecf20Sopenharmony_ci * failures are indicated, then all request(s) are considered 34578c2ecf20Sopenharmony_ci * successful. 34588c2ecf20Sopenharmony_ci */ 34598c2ecf20Sopenharmony_ci if (asconf_ack->skb->len == sizeof(struct sctp_addiphdr)) 34608c2ecf20Sopenharmony_ci all_param_pass = 1; 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci /* Process the TLVs contained in the last sent ASCONF chunk. */ 34638c2ecf20Sopenharmony_ci while (asconf_len > 0) { 34648c2ecf20Sopenharmony_ci if (all_param_pass) 34658c2ecf20Sopenharmony_ci err_code = SCTP_ERROR_NO_ERROR; 34668c2ecf20Sopenharmony_ci else { 34678c2ecf20Sopenharmony_ci err_code = sctp_get_asconf_response(asconf_ack, 34688c2ecf20Sopenharmony_ci asconf_param, 34698c2ecf20Sopenharmony_ci no_err); 34708c2ecf20Sopenharmony_ci if (no_err && (SCTP_ERROR_NO_ERROR != err_code)) 34718c2ecf20Sopenharmony_ci no_err = 0; 34728c2ecf20Sopenharmony_ci } 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci switch (err_code) { 34758c2ecf20Sopenharmony_ci case SCTP_ERROR_NO_ERROR: 34768c2ecf20Sopenharmony_ci sctp_asconf_param_success(asoc, asconf_param); 34778c2ecf20Sopenharmony_ci break; 34788c2ecf20Sopenharmony_ci 34798c2ecf20Sopenharmony_ci case SCTP_ERROR_RSRC_LOW: 34808c2ecf20Sopenharmony_ci retval = 1; 34818c2ecf20Sopenharmony_ci break; 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci case SCTP_ERROR_UNKNOWN_PARAM: 34848c2ecf20Sopenharmony_ci /* Disable sending this type of asconf parameter in 34858c2ecf20Sopenharmony_ci * future. 34868c2ecf20Sopenharmony_ci */ 34878c2ecf20Sopenharmony_ci asoc->peer.addip_disabled_mask |= 34888c2ecf20Sopenharmony_ci asconf_param->param_hdr.type; 34898c2ecf20Sopenharmony_ci break; 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci case SCTP_ERROR_REQ_REFUSED: 34928c2ecf20Sopenharmony_ci case SCTP_ERROR_DEL_LAST_IP: 34938c2ecf20Sopenharmony_ci case SCTP_ERROR_DEL_SRC_IP: 34948c2ecf20Sopenharmony_ci default: 34958c2ecf20Sopenharmony_ci break; 34968c2ecf20Sopenharmony_ci } 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci /* Skip the processed asconf parameter and move to the next 34998c2ecf20Sopenharmony_ci * one. 35008c2ecf20Sopenharmony_ci */ 35018c2ecf20Sopenharmony_ci length = ntohs(asconf_param->param_hdr.length); 35028c2ecf20Sopenharmony_ci asconf_param = (void *)asconf_param + length; 35038c2ecf20Sopenharmony_ci asconf_len -= length; 35048c2ecf20Sopenharmony_ci } 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_ci if (no_err && asoc->src_out_of_asoc_ok) { 35078c2ecf20Sopenharmony_ci asoc->src_out_of_asoc_ok = 0; 35088c2ecf20Sopenharmony_ci sctp_transport_immediate_rtx(asoc->peer.primary_path); 35098c2ecf20Sopenharmony_ci } 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_ci /* Free the cached last sent asconf chunk. */ 35128c2ecf20Sopenharmony_ci list_del_init(&asconf->transmitted_list); 35138c2ecf20Sopenharmony_ci sctp_chunk_free(asconf); 35148c2ecf20Sopenharmony_ci asoc->addip_last_asconf = NULL; 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci return retval; 35178c2ecf20Sopenharmony_ci} 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci/* Make a FWD TSN chunk. */ 35208c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, 35218c2ecf20Sopenharmony_ci __u32 new_cum_tsn, size_t nstreams, 35228c2ecf20Sopenharmony_ci struct sctp_fwdtsn_skip *skiplist) 35238c2ecf20Sopenharmony_ci{ 35248c2ecf20Sopenharmony_ci struct sctp_chunk *retval = NULL; 35258c2ecf20Sopenharmony_ci struct sctp_fwdtsn_hdr ftsn_hdr; 35268c2ecf20Sopenharmony_ci struct sctp_fwdtsn_skip skip; 35278c2ecf20Sopenharmony_ci size_t hint; 35288c2ecf20Sopenharmony_ci int i; 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci hint = (nstreams + 1) * sizeof(__u32); 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint, GFP_ATOMIC); 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci if (!retval) 35358c2ecf20Sopenharmony_ci return NULL; 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci ftsn_hdr.new_cum_tsn = htonl(new_cum_tsn); 35388c2ecf20Sopenharmony_ci retval->subh.fwdtsn_hdr = 35398c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(ftsn_hdr), &ftsn_hdr); 35408c2ecf20Sopenharmony_ci 35418c2ecf20Sopenharmony_ci for (i = 0; i < nstreams; i++) { 35428c2ecf20Sopenharmony_ci skip.stream = skiplist[i].stream; 35438c2ecf20Sopenharmony_ci skip.ssn = skiplist[i].ssn; 35448c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(skip), &skip); 35458c2ecf20Sopenharmony_ci } 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci return retval; 35488c2ecf20Sopenharmony_ci} 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_ifwdtsn(const struct sctp_association *asoc, 35518c2ecf20Sopenharmony_ci __u32 new_cum_tsn, size_t nstreams, 35528c2ecf20Sopenharmony_ci struct sctp_ifwdtsn_skip *skiplist) 35538c2ecf20Sopenharmony_ci{ 35548c2ecf20Sopenharmony_ci struct sctp_chunk *retval = NULL; 35558c2ecf20Sopenharmony_ci struct sctp_ifwdtsn_hdr ftsn_hdr; 35568c2ecf20Sopenharmony_ci size_t hint; 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci hint = (nstreams + 1) * sizeof(__u32); 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_I_FWD_TSN, 0, hint, 35618c2ecf20Sopenharmony_ci GFP_ATOMIC); 35628c2ecf20Sopenharmony_ci if (!retval) 35638c2ecf20Sopenharmony_ci return NULL; 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_ci ftsn_hdr.new_cum_tsn = htonl(new_cum_tsn); 35668c2ecf20Sopenharmony_ci retval->subh.ifwdtsn_hdr = 35678c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(ftsn_hdr), &ftsn_hdr); 35688c2ecf20Sopenharmony_ci 35698c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, nstreams * sizeof(skiplist[0]), skiplist); 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci return retval; 35728c2ecf20Sopenharmony_ci} 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci/* RE-CONFIG 3.1 (RE-CONFIG chunk) 35758c2ecf20Sopenharmony_ci * 0 1 2 3 35768c2ecf20Sopenharmony_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 35778c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 35788c2ecf20Sopenharmony_ci * | Type = 130 | Chunk Flags | Chunk Length | 35798c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 35808c2ecf20Sopenharmony_ci * \ \ 35818c2ecf20Sopenharmony_ci * / Re-configuration Parameter / 35828c2ecf20Sopenharmony_ci * \ \ 35838c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 35848c2ecf20Sopenharmony_ci * \ \ 35858c2ecf20Sopenharmony_ci * / Re-configuration Parameter (optional) / 35868c2ecf20Sopenharmony_ci * \ \ 35878c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 35888c2ecf20Sopenharmony_ci */ 35898c2ecf20Sopenharmony_cistatic struct sctp_chunk *sctp_make_reconf(const struct sctp_association *asoc, 35908c2ecf20Sopenharmony_ci int length) 35918c2ecf20Sopenharmony_ci{ 35928c2ecf20Sopenharmony_ci struct sctp_reconf_chunk *reconf; 35938c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci retval = sctp_make_control(asoc, SCTP_CID_RECONF, 0, length, 35968c2ecf20Sopenharmony_ci GFP_ATOMIC); 35978c2ecf20Sopenharmony_ci if (!retval) 35988c2ecf20Sopenharmony_ci return NULL; 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_ci reconf = (struct sctp_reconf_chunk *)retval->chunk_hdr; 36018c2ecf20Sopenharmony_ci retval->param_hdr.v = reconf->params; 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci return retval; 36048c2ecf20Sopenharmony_ci} 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci/* RE-CONFIG 4.1 (STREAM OUT RESET) 36078c2ecf20Sopenharmony_ci * 0 1 2 3 36088c2ecf20Sopenharmony_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 36098c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36108c2ecf20Sopenharmony_ci * | Parameter Type = 13 | Parameter Length = 16 + 2 * N | 36118c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36128c2ecf20Sopenharmony_ci * | Re-configuration Request Sequence Number | 36138c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36148c2ecf20Sopenharmony_ci * | Re-configuration Response Sequence Number | 36158c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36168c2ecf20Sopenharmony_ci * | Sender's Last Assigned TSN | 36178c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36188c2ecf20Sopenharmony_ci * | Stream Number 1 (optional) | Stream Number 2 (optional) | 36198c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36208c2ecf20Sopenharmony_ci * / ...... / 36218c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36228c2ecf20Sopenharmony_ci * | Stream Number N-1 (optional) | Stream Number N (optional) | 36238c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36248c2ecf20Sopenharmony_ci * 36258c2ecf20Sopenharmony_ci * RE-CONFIG 4.2 (STREAM IN RESET) 36268c2ecf20Sopenharmony_ci * 0 1 2 3 36278c2ecf20Sopenharmony_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 36288c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36298c2ecf20Sopenharmony_ci * | Parameter Type = 14 | Parameter Length = 8 + 2 * N | 36308c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36318c2ecf20Sopenharmony_ci * | Re-configuration Request Sequence Number | 36328c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36338c2ecf20Sopenharmony_ci * | Stream Number 1 (optional) | Stream Number 2 (optional) | 36348c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36358c2ecf20Sopenharmony_ci * / ...... / 36368c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36378c2ecf20Sopenharmony_ci * | Stream Number N-1 (optional) | Stream Number N (optional) | 36388c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36398c2ecf20Sopenharmony_ci */ 36408c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_req( 36418c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 36428c2ecf20Sopenharmony_ci __u16 stream_num, __be16 *stream_list, 36438c2ecf20Sopenharmony_ci bool out, bool in) 36448c2ecf20Sopenharmony_ci{ 36458c2ecf20Sopenharmony_ci __u16 stream_len = stream_num * sizeof(__u16); 36468c2ecf20Sopenharmony_ci struct sctp_strreset_outreq outreq; 36478c2ecf20Sopenharmony_ci struct sctp_strreset_inreq inreq; 36488c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 36498c2ecf20Sopenharmony_ci __u16 outlen, inlen; 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci outlen = (sizeof(outreq) + stream_len) * out; 36528c2ecf20Sopenharmony_ci inlen = (sizeof(inreq) + stream_len) * in; 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ci retval = sctp_make_reconf(asoc, SCTP_PAD4(outlen) + SCTP_PAD4(inlen)); 36558c2ecf20Sopenharmony_ci if (!retval) 36568c2ecf20Sopenharmony_ci return NULL; 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci if (outlen) { 36598c2ecf20Sopenharmony_ci outreq.param_hdr.type = SCTP_PARAM_RESET_OUT_REQUEST; 36608c2ecf20Sopenharmony_ci outreq.param_hdr.length = htons(outlen); 36618c2ecf20Sopenharmony_ci outreq.request_seq = htonl(asoc->strreset_outseq); 36628c2ecf20Sopenharmony_ci outreq.response_seq = htonl(asoc->strreset_inseq - 1); 36638c2ecf20Sopenharmony_ci outreq.send_reset_at_tsn = htonl(asoc->next_tsn - 1); 36648c2ecf20Sopenharmony_ci 36658c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(outreq), &outreq); 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci if (stream_len) 36688c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, stream_len, stream_list); 36698c2ecf20Sopenharmony_ci } 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci if (inlen) { 36728c2ecf20Sopenharmony_ci inreq.param_hdr.type = SCTP_PARAM_RESET_IN_REQUEST; 36738c2ecf20Sopenharmony_ci inreq.param_hdr.length = htons(inlen); 36748c2ecf20Sopenharmony_ci inreq.request_seq = htonl(asoc->strreset_outseq + out); 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(inreq), &inreq); 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci if (stream_len) 36798c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, stream_len, stream_list); 36808c2ecf20Sopenharmony_ci } 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci return retval; 36838c2ecf20Sopenharmony_ci} 36848c2ecf20Sopenharmony_ci 36858c2ecf20Sopenharmony_ci/* RE-CONFIG 4.3 (SSN/TSN RESET ALL) 36868c2ecf20Sopenharmony_ci * 0 1 2 3 36878c2ecf20Sopenharmony_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 36888c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36898c2ecf20Sopenharmony_ci * | Parameter Type = 15 | Parameter Length = 8 | 36908c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36918c2ecf20Sopenharmony_ci * | Re-configuration Request Sequence Number | 36928c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36938c2ecf20Sopenharmony_ci */ 36948c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_tsnreq( 36958c2ecf20Sopenharmony_ci const struct sctp_association *asoc) 36968c2ecf20Sopenharmony_ci{ 36978c2ecf20Sopenharmony_ci struct sctp_strreset_tsnreq tsnreq; 36988c2ecf20Sopenharmony_ci __u16 length = sizeof(tsnreq); 36998c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci retval = sctp_make_reconf(asoc, length); 37028c2ecf20Sopenharmony_ci if (!retval) 37038c2ecf20Sopenharmony_ci return NULL; 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_ci tsnreq.param_hdr.type = SCTP_PARAM_RESET_TSN_REQUEST; 37068c2ecf20Sopenharmony_ci tsnreq.param_hdr.length = htons(length); 37078c2ecf20Sopenharmony_ci tsnreq.request_seq = htonl(asoc->strreset_outseq); 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(tsnreq), &tsnreq); 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci return retval; 37128c2ecf20Sopenharmony_ci} 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci/* RE-CONFIG 4.5/4.6 (ADD STREAM) 37158c2ecf20Sopenharmony_ci * 0 1 2 3 37168c2ecf20Sopenharmony_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 37178c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37188c2ecf20Sopenharmony_ci * | Parameter Type = 17 | Parameter Length = 12 | 37198c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37208c2ecf20Sopenharmony_ci * | Re-configuration Request Sequence Number | 37218c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37228c2ecf20Sopenharmony_ci * | Number of new streams | Reserved | 37238c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37248c2ecf20Sopenharmony_ci */ 37258c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_addstrm( 37268c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 37278c2ecf20Sopenharmony_ci __u16 out, __u16 in) 37288c2ecf20Sopenharmony_ci{ 37298c2ecf20Sopenharmony_ci struct sctp_strreset_addstrm addstrm; 37308c2ecf20Sopenharmony_ci __u16 size = sizeof(addstrm); 37318c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_ci retval = sctp_make_reconf(asoc, (!!out + !!in) * size); 37348c2ecf20Sopenharmony_ci if (!retval) 37358c2ecf20Sopenharmony_ci return NULL; 37368c2ecf20Sopenharmony_ci 37378c2ecf20Sopenharmony_ci if (out) { 37388c2ecf20Sopenharmony_ci addstrm.param_hdr.type = SCTP_PARAM_RESET_ADD_OUT_STREAMS; 37398c2ecf20Sopenharmony_ci addstrm.param_hdr.length = htons(size); 37408c2ecf20Sopenharmony_ci addstrm.number_of_streams = htons(out); 37418c2ecf20Sopenharmony_ci addstrm.request_seq = htonl(asoc->strreset_outseq); 37428c2ecf20Sopenharmony_ci addstrm.reserved = 0; 37438c2ecf20Sopenharmony_ci 37448c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, size, &addstrm); 37458c2ecf20Sopenharmony_ci } 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci if (in) { 37488c2ecf20Sopenharmony_ci addstrm.param_hdr.type = SCTP_PARAM_RESET_ADD_IN_STREAMS; 37498c2ecf20Sopenharmony_ci addstrm.param_hdr.length = htons(size); 37508c2ecf20Sopenharmony_ci addstrm.number_of_streams = htons(in); 37518c2ecf20Sopenharmony_ci addstrm.request_seq = htonl(asoc->strreset_outseq + !!out); 37528c2ecf20Sopenharmony_ci addstrm.reserved = 0; 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, size, &addstrm); 37558c2ecf20Sopenharmony_ci } 37568c2ecf20Sopenharmony_ci 37578c2ecf20Sopenharmony_ci return retval; 37588c2ecf20Sopenharmony_ci} 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci/* RE-CONFIG 4.4 (RESP) 37618c2ecf20Sopenharmony_ci * 0 1 2 3 37628c2ecf20Sopenharmony_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 37638c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37648c2ecf20Sopenharmony_ci * | Parameter Type = 16 | Parameter Length | 37658c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37668c2ecf20Sopenharmony_ci * | Re-configuration Response Sequence Number | 37678c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37688c2ecf20Sopenharmony_ci * | Result | 37698c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37708c2ecf20Sopenharmony_ci */ 37718c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_resp(const struct sctp_association *asoc, 37728c2ecf20Sopenharmony_ci __u32 result, __u32 sn) 37738c2ecf20Sopenharmony_ci{ 37748c2ecf20Sopenharmony_ci struct sctp_strreset_resp resp; 37758c2ecf20Sopenharmony_ci __u16 length = sizeof(resp); 37768c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 37778c2ecf20Sopenharmony_ci 37788c2ecf20Sopenharmony_ci retval = sctp_make_reconf(asoc, length); 37798c2ecf20Sopenharmony_ci if (!retval) 37808c2ecf20Sopenharmony_ci return NULL; 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci resp.param_hdr.type = SCTP_PARAM_RESET_RESPONSE; 37838c2ecf20Sopenharmony_ci resp.param_hdr.length = htons(length); 37848c2ecf20Sopenharmony_ci resp.response_seq = htonl(sn); 37858c2ecf20Sopenharmony_ci resp.result = htonl(result); 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(resp), &resp); 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci return retval; 37908c2ecf20Sopenharmony_ci} 37918c2ecf20Sopenharmony_ci 37928c2ecf20Sopenharmony_ci/* RE-CONFIG 4.4 OPTIONAL (TSNRESP) 37938c2ecf20Sopenharmony_ci * 0 1 2 3 37948c2ecf20Sopenharmony_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 37958c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37968c2ecf20Sopenharmony_ci * | Parameter Type = 16 | Parameter Length | 37978c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37988c2ecf20Sopenharmony_ci * | Re-configuration Response Sequence Number | 37998c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 38008c2ecf20Sopenharmony_ci * | Result | 38018c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 38028c2ecf20Sopenharmony_ci * | Sender's Next TSN (optional) | 38038c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 38048c2ecf20Sopenharmony_ci * | Receiver's Next TSN (optional) | 38058c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 38068c2ecf20Sopenharmony_ci */ 38078c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_make_strreset_tsnresp(struct sctp_association *asoc, 38088c2ecf20Sopenharmony_ci __u32 result, __u32 sn, 38098c2ecf20Sopenharmony_ci __u32 sender_tsn, 38108c2ecf20Sopenharmony_ci __u32 receiver_tsn) 38118c2ecf20Sopenharmony_ci{ 38128c2ecf20Sopenharmony_ci struct sctp_strreset_resptsn tsnresp; 38138c2ecf20Sopenharmony_ci __u16 length = sizeof(tsnresp); 38148c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci retval = sctp_make_reconf(asoc, length); 38178c2ecf20Sopenharmony_ci if (!retval) 38188c2ecf20Sopenharmony_ci return NULL; 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_ci tsnresp.param_hdr.type = SCTP_PARAM_RESET_RESPONSE; 38218c2ecf20Sopenharmony_ci tsnresp.param_hdr.length = htons(length); 38228c2ecf20Sopenharmony_ci 38238c2ecf20Sopenharmony_ci tsnresp.response_seq = htonl(sn); 38248c2ecf20Sopenharmony_ci tsnresp.result = htonl(result); 38258c2ecf20Sopenharmony_ci tsnresp.senders_next_tsn = htonl(sender_tsn); 38268c2ecf20Sopenharmony_ci tsnresp.receivers_next_tsn = htonl(receiver_tsn); 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci sctp_addto_chunk(retval, sizeof(tsnresp), &tsnresp); 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_ci return retval; 38318c2ecf20Sopenharmony_ci} 38328c2ecf20Sopenharmony_ci 38338c2ecf20Sopenharmony_cibool sctp_verify_reconf(const struct sctp_association *asoc, 38348c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 38358c2ecf20Sopenharmony_ci struct sctp_paramhdr **errp) 38368c2ecf20Sopenharmony_ci{ 38378c2ecf20Sopenharmony_ci struct sctp_reconf_chunk *hdr; 38388c2ecf20Sopenharmony_ci union sctp_params param; 38398c2ecf20Sopenharmony_ci __be16 last = 0; 38408c2ecf20Sopenharmony_ci __u16 cnt = 0; 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_ci hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr; 38438c2ecf20Sopenharmony_ci sctp_walk_params(param, hdr, params) { 38448c2ecf20Sopenharmony_ci __u16 length = ntohs(param.p->length); 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci *errp = param.p; 38478c2ecf20Sopenharmony_ci if (cnt++ > 2) 38488c2ecf20Sopenharmony_ci return false; 38498c2ecf20Sopenharmony_ci switch (param.p->type) { 38508c2ecf20Sopenharmony_ci case SCTP_PARAM_RESET_OUT_REQUEST: 38518c2ecf20Sopenharmony_ci if (length < sizeof(struct sctp_strreset_outreq) || 38528c2ecf20Sopenharmony_ci (last && last != SCTP_PARAM_RESET_RESPONSE && 38538c2ecf20Sopenharmony_ci last != SCTP_PARAM_RESET_IN_REQUEST)) 38548c2ecf20Sopenharmony_ci return false; 38558c2ecf20Sopenharmony_ci break; 38568c2ecf20Sopenharmony_ci case SCTP_PARAM_RESET_IN_REQUEST: 38578c2ecf20Sopenharmony_ci if (length < sizeof(struct sctp_strreset_inreq) || 38588c2ecf20Sopenharmony_ci (last && last != SCTP_PARAM_RESET_OUT_REQUEST)) 38598c2ecf20Sopenharmony_ci return false; 38608c2ecf20Sopenharmony_ci break; 38618c2ecf20Sopenharmony_ci case SCTP_PARAM_RESET_RESPONSE: 38628c2ecf20Sopenharmony_ci if ((length != sizeof(struct sctp_strreset_resp) && 38638c2ecf20Sopenharmony_ci length != sizeof(struct sctp_strreset_resptsn)) || 38648c2ecf20Sopenharmony_ci (last && last != SCTP_PARAM_RESET_RESPONSE && 38658c2ecf20Sopenharmony_ci last != SCTP_PARAM_RESET_OUT_REQUEST)) 38668c2ecf20Sopenharmony_ci return false; 38678c2ecf20Sopenharmony_ci break; 38688c2ecf20Sopenharmony_ci case SCTP_PARAM_RESET_TSN_REQUEST: 38698c2ecf20Sopenharmony_ci if (length != 38708c2ecf20Sopenharmony_ci sizeof(struct sctp_strreset_tsnreq) || last) 38718c2ecf20Sopenharmony_ci return false; 38728c2ecf20Sopenharmony_ci break; 38738c2ecf20Sopenharmony_ci case SCTP_PARAM_RESET_ADD_IN_STREAMS: 38748c2ecf20Sopenharmony_ci if (length != sizeof(struct sctp_strreset_addstrm) || 38758c2ecf20Sopenharmony_ci (last && last != SCTP_PARAM_RESET_ADD_OUT_STREAMS)) 38768c2ecf20Sopenharmony_ci return false; 38778c2ecf20Sopenharmony_ci break; 38788c2ecf20Sopenharmony_ci case SCTP_PARAM_RESET_ADD_OUT_STREAMS: 38798c2ecf20Sopenharmony_ci if (length != sizeof(struct sctp_strreset_addstrm) || 38808c2ecf20Sopenharmony_ci (last && last != SCTP_PARAM_RESET_ADD_IN_STREAMS)) 38818c2ecf20Sopenharmony_ci return false; 38828c2ecf20Sopenharmony_ci break; 38838c2ecf20Sopenharmony_ci default: 38848c2ecf20Sopenharmony_ci return false; 38858c2ecf20Sopenharmony_ci } 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci last = param.p->type; 38888c2ecf20Sopenharmony_ci } 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_ci return true; 38918c2ecf20Sopenharmony_ci} 3892