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-2003 Intel Corp. 78c2ecf20Sopenharmony_ci * Copyright (c) 2001-2002 Nokia, Inc. 88c2ecf20Sopenharmony_ci * Copyright (c) 2001 La Monte H.P. Yarroll 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This file is part of the SCTP kernel implementation 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * These functions interface with the sockets layer to implement the 138c2ecf20Sopenharmony_ci * SCTP Extensions for the Sockets API. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Note that the descriptions from the specification are USER level 168c2ecf20Sopenharmony_ci * functions--this file is the functions which populate the struct proto 178c2ecf20Sopenharmony_ci * for SCTP which is the BOTTOM of the sockets interface. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Please send any bug reports or fixes you make to the 208c2ecf20Sopenharmony_ci * email address(es): 218c2ecf20Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Written or modified by: 248c2ecf20Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 258c2ecf20Sopenharmony_ci * Narasimha Budihal <narsi@refcode.org> 268c2ecf20Sopenharmony_ci * Karl Knutson <karl@athena.chicago.il.us> 278c2ecf20Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 288c2ecf20Sopenharmony_ci * Xingang Guo <xingang.guo@intel.com> 298c2ecf20Sopenharmony_ci * Daisy Chang <daisyc@us.ibm.com> 308c2ecf20Sopenharmony_ci * Sridhar Samudrala <samudrala@us.ibm.com> 318c2ecf20Sopenharmony_ci * Inaky Perez-Gonzalez <inaky.gonzalez@intel.com> 328c2ecf20Sopenharmony_ci * Ardelle Fan <ardelle.fan@intel.com> 338c2ecf20Sopenharmony_ci * Ryan Layer <rmlayer@us.ibm.com> 348c2ecf20Sopenharmony_ci * Anup Pemmaiah <pemmaiah@cc.usu.edu> 358c2ecf20Sopenharmony_ci * Kevin Gao <kevin.gao@intel.com> 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <crypto/hash.h> 418c2ecf20Sopenharmony_ci#include <linux/types.h> 428c2ecf20Sopenharmony_ci#include <linux/kernel.h> 438c2ecf20Sopenharmony_ci#include <linux/wait.h> 448c2ecf20Sopenharmony_ci#include <linux/time.h> 458c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 468c2ecf20Sopenharmony_ci#include <linux/ip.h> 478c2ecf20Sopenharmony_ci#include <linux/capability.h> 488c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 498c2ecf20Sopenharmony_ci#include <linux/poll.h> 508c2ecf20Sopenharmony_ci#include <linux/init.h> 518c2ecf20Sopenharmony_ci#include <linux/slab.h> 528c2ecf20Sopenharmony_ci#include <linux/file.h> 538c2ecf20Sopenharmony_ci#include <linux/compat.h> 548c2ecf20Sopenharmony_ci#include <linux/rhashtable.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#include <net/ip.h> 578c2ecf20Sopenharmony_ci#include <net/icmp.h> 588c2ecf20Sopenharmony_ci#include <net/route.h> 598c2ecf20Sopenharmony_ci#include <net/ipv6.h> 608c2ecf20Sopenharmony_ci#include <net/inet_common.h> 618c2ecf20Sopenharmony_ci#include <net/busy_poll.h> 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#include <linux/socket.h> /* for sa_family_t */ 648c2ecf20Sopenharmony_ci#include <linux/export.h> 658c2ecf20Sopenharmony_ci#include <net/sock.h> 668c2ecf20Sopenharmony_ci#include <net/sctp/sctp.h> 678c2ecf20Sopenharmony_ci#include <net/sctp/sm.h> 688c2ecf20Sopenharmony_ci#include <net/sctp/stream_sched.h> 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Forward declarations for internal helper functions. */ 718c2ecf20Sopenharmony_cistatic bool sctp_writeable(const struct sock *sk); 728c2ecf20Sopenharmony_cistatic void sctp_wfree(struct sk_buff *skb); 738c2ecf20Sopenharmony_cistatic int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 748c2ecf20Sopenharmony_ci size_t msg_len); 758c2ecf20Sopenharmony_cistatic int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p); 768c2ecf20Sopenharmony_cistatic int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); 778c2ecf20Sopenharmony_cistatic int sctp_wait_for_accept(struct sock *sk, long timeo); 788c2ecf20Sopenharmony_cistatic void sctp_wait_for_close(struct sock *sk, long timeo); 798c2ecf20Sopenharmony_cistatic void sctp_destruct_sock(struct sock *sk); 808c2ecf20Sopenharmony_cistatic struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, 818c2ecf20Sopenharmony_ci union sctp_addr *addr, int len); 828c2ecf20Sopenharmony_cistatic int sctp_bindx_add(struct sock *, struct sockaddr *, int); 838c2ecf20Sopenharmony_cistatic int sctp_bindx_rem(struct sock *, struct sockaddr *, int); 848c2ecf20Sopenharmony_cistatic int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); 858c2ecf20Sopenharmony_cistatic int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int); 868c2ecf20Sopenharmony_cistatic int sctp_send_asconf(struct sctp_association *asoc, 878c2ecf20Sopenharmony_ci struct sctp_chunk *chunk); 888c2ecf20Sopenharmony_cistatic int sctp_do_bind(struct sock *, union sctp_addr *, int); 898c2ecf20Sopenharmony_cistatic int sctp_autobind(struct sock *sk); 908c2ecf20Sopenharmony_cistatic int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, 918c2ecf20Sopenharmony_ci struct sctp_association *assoc, 928c2ecf20Sopenharmony_ci enum sctp_socket_type type); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic unsigned long sctp_memory_pressure; 958c2ecf20Sopenharmony_cistatic atomic_long_t sctp_memory_allocated; 968c2ecf20Sopenharmony_cistruct percpu_counter sctp_sockets_allocated; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void sctp_enter_memory_pressure(struct sock *sk) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci WRITE_ONCE(sctp_memory_pressure, 1); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Get the sndbuf space available at the time on the association. */ 1058c2ecf20Sopenharmony_cistatic inline int sctp_wspace(struct sctp_association *asoc) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return asoc->ep->sndbuf_policy ? sk->sk_sndbuf - asoc->sndbuf_used 1108c2ecf20Sopenharmony_ci : sk_stream_wspace(sk); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* Increment the used sndbuf space count of the corresponding association by 1148c2ecf20Sopenharmony_ci * the size of the outgoing data chunk. 1158c2ecf20Sopenharmony_ci * Also, set the skb destructor for sndbuf accounting later. 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * Since it is always 1-1 between chunk and skb, and also a new skb is always 1188c2ecf20Sopenharmony_ci * allocated for chunk bundling in sctp_packet_transmit(), we can use the 1198c2ecf20Sopenharmony_ci * destructor in the data chunk skb for the purpose of the sndbuf space 1208c2ecf20Sopenharmony_ci * tracking. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_cistatic inline void sctp_set_owner_w(struct sctp_chunk *chunk) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct sctp_association *asoc = chunk->asoc; 1258c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* The sndbuf space is tracked per association. */ 1288c2ecf20Sopenharmony_ci sctp_association_hold(asoc); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (chunk->shkey) 1318c2ecf20Sopenharmony_ci sctp_auth_shkey_hold(chunk->shkey); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci skb_set_owner_w(chunk->skb, sk); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci chunk->skb->destructor = sctp_wfree; 1368c2ecf20Sopenharmony_ci /* Save the chunk pointer in skb for sctp_wfree to use later. */ 1378c2ecf20Sopenharmony_ci skb_shinfo(chunk->skb)->destructor_arg = chunk; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); 1408c2ecf20Sopenharmony_ci asoc->sndbuf_used += chunk->skb->truesize + sizeof(struct sctp_chunk); 1418c2ecf20Sopenharmony_ci sk_wmem_queued_add(sk, chunk->skb->truesize + sizeof(struct sctp_chunk)); 1428c2ecf20Sopenharmony_ci sk_mem_charge(sk, chunk->skb->truesize); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void sctp_clear_owner_w(struct sctp_chunk *chunk) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci skb_orphan(chunk->skb); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define traverse_and_process() \ 1518c2ecf20Sopenharmony_cido { \ 1528c2ecf20Sopenharmony_ci msg = chunk->msg; \ 1538c2ecf20Sopenharmony_ci if (msg == prev_msg) \ 1548c2ecf20Sopenharmony_ci continue; \ 1558c2ecf20Sopenharmony_ci list_for_each_entry(c, &msg->chunks, frag_list) { \ 1568c2ecf20Sopenharmony_ci if ((clear && asoc->base.sk == c->skb->sk) || \ 1578c2ecf20Sopenharmony_ci (!clear && asoc->base.sk != c->skb->sk)) \ 1588c2ecf20Sopenharmony_ci cb(c); \ 1598c2ecf20Sopenharmony_ci } \ 1608c2ecf20Sopenharmony_ci prev_msg = msg; \ 1618c2ecf20Sopenharmony_ci} while (0) 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void sctp_for_each_tx_datachunk(struct sctp_association *asoc, 1648c2ecf20Sopenharmony_ci bool clear, 1658c2ecf20Sopenharmony_ci void (*cb)(struct sctp_chunk *)) 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct sctp_datamsg *msg, *prev_msg = NULL; 1698c2ecf20Sopenharmony_ci struct sctp_outq *q = &asoc->outqueue; 1708c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, *c; 1718c2ecf20Sopenharmony_ci struct sctp_transport *t; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) 1748c2ecf20Sopenharmony_ci list_for_each_entry(chunk, &t->transmitted, transmitted_list) 1758c2ecf20Sopenharmony_ci traverse_and_process(); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci list_for_each_entry(chunk, &q->retransmit, transmitted_list) 1788c2ecf20Sopenharmony_ci traverse_and_process(); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci list_for_each_entry(chunk, &q->sacked, transmitted_list) 1818c2ecf20Sopenharmony_ci traverse_and_process(); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci list_for_each_entry(chunk, &q->abandoned, transmitted_list) 1848c2ecf20Sopenharmony_ci traverse_and_process(); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci list_for_each_entry(chunk, &q->out_chunk_list, list) 1878c2ecf20Sopenharmony_ci traverse_and_process(); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void sctp_for_each_rx_skb(struct sctp_association *asoc, struct sock *sk, 1918c2ecf20Sopenharmony_ci void (*cb)(struct sk_buff *, struct sock *)) 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct sk_buff *skb, *tmp; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci sctp_skb_for_each(skb, &asoc->ulpq.lobby, tmp) 1978c2ecf20Sopenharmony_ci cb(skb, sk); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci sctp_skb_for_each(skb, &asoc->ulpq.reasm, tmp) 2008c2ecf20Sopenharmony_ci cb(skb, sk); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci sctp_skb_for_each(skb, &asoc->ulpq.reasm_uo, tmp) 2038c2ecf20Sopenharmony_ci cb(skb, sk); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/* Verify that this is a valid address. */ 2078c2ecf20Sopenharmony_cistatic inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, 2088c2ecf20Sopenharmony_ci int len) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct sctp_af *af; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* Verify basic sockaddr. */ 2138c2ecf20Sopenharmony_ci af = sctp_sockaddr_af(sctp_sk(sk), addr, len); 2148c2ecf20Sopenharmony_ci if (!af) 2158c2ecf20Sopenharmony_ci return -EINVAL; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* Is this a valid SCTP address? */ 2188c2ecf20Sopenharmony_ci if (!af->addr_valid(addr, sctp_sk(sk), NULL)) 2198c2ecf20Sopenharmony_ci return -EINVAL; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) 2228c2ecf20Sopenharmony_ci return -EINVAL; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/* Look up the association by its id. If this is not a UDP-style 2288c2ecf20Sopenharmony_ci * socket, the ID field is always ignored. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_cistruct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct sctp_association *asoc = NULL; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* If this is not a UDP-style socket, assoc id should be ignored. */ 2358c2ecf20Sopenharmony_ci if (!sctp_style(sk, UDP)) { 2368c2ecf20Sopenharmony_ci /* Return NULL if the socket state is not ESTABLISHED. It 2378c2ecf20Sopenharmony_ci * could be a TCP-style listening socket or a socket which 2388c2ecf20Sopenharmony_ci * hasn't yet called connect() to establish an association. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci if (!sctp_sstate(sk, ESTABLISHED) && !sctp_sstate(sk, CLOSING)) 2418c2ecf20Sopenharmony_ci return NULL; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Get the first and the only association from the list. */ 2448c2ecf20Sopenharmony_ci if (!list_empty(&sctp_sk(sk)->ep->asocs)) 2458c2ecf20Sopenharmony_ci asoc = list_entry(sctp_sk(sk)->ep->asocs.next, 2468c2ecf20Sopenharmony_ci struct sctp_association, asocs); 2478c2ecf20Sopenharmony_ci return asoc; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* Otherwise this is a UDP-style socket. */ 2518c2ecf20Sopenharmony_ci if (id <= SCTP_ALL_ASSOC) 2528c2ecf20Sopenharmony_ci return NULL; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci spin_lock_bh(&sctp_assocs_id_lock); 2558c2ecf20Sopenharmony_ci asoc = (struct sctp_association *)idr_find(&sctp_assocs_id, (int)id); 2568c2ecf20Sopenharmony_ci if (asoc && (asoc->base.sk != sk || asoc->base.dead)) 2578c2ecf20Sopenharmony_ci asoc = NULL; 2588c2ecf20Sopenharmony_ci spin_unlock_bh(&sctp_assocs_id_lock); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return asoc; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/* Look up the transport from an address and an assoc id. If both address and 2648c2ecf20Sopenharmony_ci * id are specified, the associations matching the address and the id should be 2658c2ecf20Sopenharmony_ci * the same. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_cistatic struct sctp_transport *sctp_addr_id2transport(struct sock *sk, 2688c2ecf20Sopenharmony_ci struct sockaddr_storage *addr, 2698c2ecf20Sopenharmony_ci sctp_assoc_t id) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct sctp_association *addr_asoc = NULL, *id_asoc = NULL; 2728c2ecf20Sopenharmony_ci struct sctp_af *af = sctp_get_af_specific(addr->ss_family); 2738c2ecf20Sopenharmony_ci union sctp_addr *laddr = (union sctp_addr *)addr; 2748c2ecf20Sopenharmony_ci struct sctp_transport *transport; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (!af || sctp_verify_addr(sk, laddr, af->sockaddr_len)) 2778c2ecf20Sopenharmony_ci return NULL; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep, 2808c2ecf20Sopenharmony_ci laddr, 2818c2ecf20Sopenharmony_ci &transport); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (!addr_asoc) 2848c2ecf20Sopenharmony_ci return NULL; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci id_asoc = sctp_id2assoc(sk, id); 2878c2ecf20Sopenharmony_ci if (id_asoc && (id_asoc != addr_asoc)) 2888c2ecf20Sopenharmony_ci return NULL; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), 2918c2ecf20Sopenharmony_ci (union sctp_addr *)addr); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return transport; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/* API 3.1.2 bind() - UDP Style Syntax 2978c2ecf20Sopenharmony_ci * The syntax of bind() is, 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * ret = bind(int sd, struct sockaddr *addr, int addrlen); 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * sd - the socket descriptor returned by socket(). 3028c2ecf20Sopenharmony_ci * addr - the address structure (struct sockaddr_in or struct 3038c2ecf20Sopenharmony_ci * sockaddr_in6 [RFC 2553]), 3048c2ecf20Sopenharmony_ci * addr_len - the size of the address structure. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_cistatic int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci int retval = 0; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci lock_sock(sk); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, addr:%p, addr_len:%d\n", __func__, sk, 3138c2ecf20Sopenharmony_ci addr, addr_len); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Disallow binding twice. */ 3168c2ecf20Sopenharmony_ci if (!sctp_sk(sk)->ep->base.bind_addr.port) 3178c2ecf20Sopenharmony_ci retval = sctp_do_bind(sk, (union sctp_addr *)addr, 3188c2ecf20Sopenharmony_ci addr_len); 3198c2ecf20Sopenharmony_ci else 3208c2ecf20Sopenharmony_ci retval = -EINVAL; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci release_sock(sk); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return retval; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int sctp_get_port_local(struct sock *, union sctp_addr *); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* Verify this is a valid sockaddr. */ 3308c2ecf20Sopenharmony_cistatic struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, 3318c2ecf20Sopenharmony_ci union sctp_addr *addr, int len) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct sctp_af *af; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Check minimum size. */ 3368c2ecf20Sopenharmony_ci if (len < sizeof (struct sockaddr)) 3378c2ecf20Sopenharmony_ci return NULL; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (!opt->pf->af_supported(addr->sa.sa_family, opt)) 3408c2ecf20Sopenharmony_ci return NULL; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (addr->sa.sa_family == AF_INET6) { 3438c2ecf20Sopenharmony_ci if (len < SIN6_LEN_RFC2133) 3448c2ecf20Sopenharmony_ci return NULL; 3458c2ecf20Sopenharmony_ci /* V4 mapped address are really of AF_INET family */ 3468c2ecf20Sopenharmony_ci if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) && 3478c2ecf20Sopenharmony_ci !opt->pf->af_supported(AF_INET, opt)) 3488c2ecf20Sopenharmony_ci return NULL; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* If we get this far, af is valid. */ 3528c2ecf20Sopenharmony_ci af = sctp_get_af_specific(addr->sa.sa_family); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (len < af->sockaddr_len) 3558c2ecf20Sopenharmony_ci return NULL; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return af; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic void sctp_auto_asconf_init(struct sctp_sock *sp) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct net *net = sock_net(&sp->inet.sk); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (net->sctp.default_auto_asconf) { 3658c2ecf20Sopenharmony_ci spin_lock_bh(&net->sctp.addr_wq_lock); 3668c2ecf20Sopenharmony_ci list_add_tail(&sp->auto_asconf_list, &net->sctp.auto_asconf_splist); 3678c2ecf20Sopenharmony_ci spin_unlock_bh(&net->sctp.addr_wq_lock); 3688c2ecf20Sopenharmony_ci sp->do_auto_asconf = 1; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* Bind a local address either to an endpoint or to an association. */ 3738c2ecf20Sopenharmony_cistatic int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 3768c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 3778c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sp->ep; 3788c2ecf20Sopenharmony_ci struct sctp_bind_addr *bp = &ep->base.bind_addr; 3798c2ecf20Sopenharmony_ci struct sctp_af *af; 3808c2ecf20Sopenharmony_ci unsigned short snum; 3818c2ecf20Sopenharmony_ci int ret = 0; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Common sockaddr verification. */ 3848c2ecf20Sopenharmony_ci af = sctp_sockaddr_af(sp, addr, len); 3858c2ecf20Sopenharmony_ci if (!af) { 3868c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, newaddr:%p, len:%d EINVAL\n", 3878c2ecf20Sopenharmony_ci __func__, sk, addr, len); 3888c2ecf20Sopenharmony_ci return -EINVAL; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci snum = ntohs(addr->v4.sin_port); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, new addr:%pISc, port:%d, new port:%d, len:%d\n", 3948c2ecf20Sopenharmony_ci __func__, sk, &addr->sa, bp->port, snum, len); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* PF specific bind() address verification. */ 3978c2ecf20Sopenharmony_ci if (!sp->pf->bind_verify(sp, addr)) 3988c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* We must either be unbound, or bind to the same port. 4018c2ecf20Sopenharmony_ci * It's OK to allow 0 ports if we are already bound. 4028c2ecf20Sopenharmony_ci * We'll just inhert an already bound port in this case 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci if (bp->port) { 4058c2ecf20Sopenharmony_ci if (!snum) 4068c2ecf20Sopenharmony_ci snum = bp->port; 4078c2ecf20Sopenharmony_ci else if (snum != bp->port) { 4088c2ecf20Sopenharmony_ci pr_debug("%s: new port %d doesn't match existing port " 4098c2ecf20Sopenharmony_ci "%d\n", __func__, snum, bp->port); 4108c2ecf20Sopenharmony_ci return -EINVAL; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (snum && inet_port_requires_bind_service(net, snum) && 4158c2ecf20Sopenharmony_ci !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 4168c2ecf20Sopenharmony_ci return -EACCES; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* See if the address matches any of the addresses we may have 4198c2ecf20Sopenharmony_ci * already bound before checking against other endpoints. 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci if (sctp_bind_addr_match(bp, addr, sp)) 4228c2ecf20Sopenharmony_ci return -EINVAL; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* Make sure we are allowed to bind here. 4258c2ecf20Sopenharmony_ci * The function sctp_get_port_local() does duplicate address 4268c2ecf20Sopenharmony_ci * detection. 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci addr->v4.sin_port = htons(snum); 4298c2ecf20Sopenharmony_ci if (sctp_get_port_local(sk, addr)) 4308c2ecf20Sopenharmony_ci return -EADDRINUSE; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* Refresh ephemeral port. */ 4338c2ecf20Sopenharmony_ci if (!bp->port) { 4348c2ecf20Sopenharmony_ci bp->port = inet_sk(sk)->inet_num; 4358c2ecf20Sopenharmony_ci sctp_auto_asconf_init(sp); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Add the address to the bind address list. 4398c2ecf20Sopenharmony_ci * Use GFP_ATOMIC since BHs will be disabled. 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci ret = sctp_add_bind_addr(bp, addr, af->sockaddr_len, 4428c2ecf20Sopenharmony_ci SCTP_ADDR_SRC, GFP_ATOMIC); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (ret) { 4458c2ecf20Sopenharmony_ci sctp_put_port(sk); 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci /* Copy back into socket for getsockname() use. */ 4498c2ecf20Sopenharmony_ci inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num); 4508c2ecf20Sopenharmony_ci sp->pf->to_sk_saddr(addr, sk); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return ret; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks 4568c2ecf20Sopenharmony_ci * 4578c2ecf20Sopenharmony_ci * R1) One and only one ASCONF Chunk MAY be in transit and unacknowledged 4588c2ecf20Sopenharmony_ci * at any one time. If a sender, after sending an ASCONF chunk, decides 4598c2ecf20Sopenharmony_ci * it needs to transfer another ASCONF Chunk, it MUST wait until the 4608c2ecf20Sopenharmony_ci * ASCONF-ACK Chunk returns from the previous ASCONF Chunk before sending a 4618c2ecf20Sopenharmony_ci * subsequent ASCONF. Note this restriction binds each side, so at any 4628c2ecf20Sopenharmony_ci * time two ASCONF may be in-transit on any given association (one sent 4638c2ecf20Sopenharmony_ci * from each endpoint). 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_cistatic int sctp_send_asconf(struct sctp_association *asoc, 4668c2ecf20Sopenharmony_ci struct sctp_chunk *chunk) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci int retval = 0; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* If there is an outstanding ASCONF chunk, queue it for later 4718c2ecf20Sopenharmony_ci * transmission. 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci if (asoc->addip_last_asconf) { 4748c2ecf20Sopenharmony_ci list_add_tail(&chunk->list, &asoc->addip_chunk_list); 4758c2ecf20Sopenharmony_ci goto out; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* Hold the chunk until an ASCONF_ACK is received. */ 4798c2ecf20Sopenharmony_ci sctp_chunk_hold(chunk); 4808c2ecf20Sopenharmony_ci retval = sctp_primitive_ASCONF(asoc->base.net, asoc, chunk); 4818c2ecf20Sopenharmony_ci if (retval) 4828c2ecf20Sopenharmony_ci sctp_chunk_free(chunk); 4838c2ecf20Sopenharmony_ci else 4848c2ecf20Sopenharmony_ci asoc->addip_last_asconf = chunk; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ciout: 4878c2ecf20Sopenharmony_ci return retval; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* Add a list of addresses as bind addresses to local endpoint or 4918c2ecf20Sopenharmony_ci * association. 4928c2ecf20Sopenharmony_ci * 4938c2ecf20Sopenharmony_ci * Basically run through each address specified in the addrs/addrcnt 4948c2ecf20Sopenharmony_ci * array/length pair, determine if it is IPv6 or IPv4 and call 4958c2ecf20Sopenharmony_ci * sctp_do_bind() on it. 4968c2ecf20Sopenharmony_ci * 4978c2ecf20Sopenharmony_ci * If any of them fails, then the operation will be reversed and the 4988c2ecf20Sopenharmony_ci * ones that were added will be removed. 4998c2ecf20Sopenharmony_ci * 5008c2ecf20Sopenharmony_ci * Only sctp_setsockopt_bindx() is supposed to call this function. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_cistatic int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci int cnt; 5058c2ecf20Sopenharmony_ci int retval = 0; 5068c2ecf20Sopenharmony_ci void *addr_buf; 5078c2ecf20Sopenharmony_ci struct sockaddr *sa_addr; 5088c2ecf20Sopenharmony_ci struct sctp_af *af; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", __func__, sk, 5118c2ecf20Sopenharmony_ci addrs, addrcnt); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci addr_buf = addrs; 5148c2ecf20Sopenharmony_ci for (cnt = 0; cnt < addrcnt; cnt++) { 5158c2ecf20Sopenharmony_ci /* The list may contain either IPv4 or IPv6 address; 5168c2ecf20Sopenharmony_ci * determine the address length for walking thru the list. 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_ci sa_addr = addr_buf; 5198c2ecf20Sopenharmony_ci af = sctp_get_af_specific(sa_addr->sa_family); 5208c2ecf20Sopenharmony_ci if (!af) { 5218c2ecf20Sopenharmony_ci retval = -EINVAL; 5228c2ecf20Sopenharmony_ci goto err_bindx_add; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci retval = sctp_do_bind(sk, (union sctp_addr *)sa_addr, 5268c2ecf20Sopenharmony_ci af->sockaddr_len); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cierr_bindx_add: 5318c2ecf20Sopenharmony_ci if (retval < 0) { 5328c2ecf20Sopenharmony_ci /* Failed. Cleanup the ones that have been added */ 5338c2ecf20Sopenharmony_ci if (cnt > 0) 5348c2ecf20Sopenharmony_ci sctp_bindx_rem(sk, addrs, cnt); 5358c2ecf20Sopenharmony_ci return retval; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return retval; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci/* Send an ASCONF chunk with Add IP address parameters to all the peers of the 5438c2ecf20Sopenharmony_ci * associations that are part of the endpoint indicating that a list of local 5448c2ecf20Sopenharmony_ci * addresses are added to the endpoint. 5458c2ecf20Sopenharmony_ci * 5468c2ecf20Sopenharmony_ci * If any of the addresses is already in the bind address list of the 5478c2ecf20Sopenharmony_ci * association, we do not send the chunk for that association. But it will not 5488c2ecf20Sopenharmony_ci * affect other associations. 5498c2ecf20Sopenharmony_ci * 5508c2ecf20Sopenharmony_ci * Only sctp_setsockopt_bindx() is supposed to call this function. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_cistatic int sctp_send_asconf_add_ip(struct sock *sk, 5538c2ecf20Sopenharmony_ci struct sockaddr *addrs, 5548c2ecf20Sopenharmony_ci int addrcnt) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct sctp_sock *sp; 5578c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 5588c2ecf20Sopenharmony_ci struct sctp_association *asoc; 5598c2ecf20Sopenharmony_ci struct sctp_bind_addr *bp; 5608c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 5618c2ecf20Sopenharmony_ci struct sctp_sockaddr_entry *laddr; 5628c2ecf20Sopenharmony_ci union sctp_addr *addr; 5638c2ecf20Sopenharmony_ci union sctp_addr saveaddr; 5648c2ecf20Sopenharmony_ci void *addr_buf; 5658c2ecf20Sopenharmony_ci struct sctp_af *af; 5668c2ecf20Sopenharmony_ci struct list_head *p; 5678c2ecf20Sopenharmony_ci int i; 5688c2ecf20Sopenharmony_ci int retval = 0; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci sp = sctp_sk(sk); 5718c2ecf20Sopenharmony_ci ep = sp->ep; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (!ep->asconf_enable) 5748c2ecf20Sopenharmony_ci return retval; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 5778c2ecf20Sopenharmony_ci __func__, sk, addrs, addrcnt); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &ep->asocs, asocs) { 5808c2ecf20Sopenharmony_ci if (!asoc->peer.asconf_capable) 5818c2ecf20Sopenharmony_ci continue; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (asoc->peer.addip_disabled_mask & SCTP_PARAM_ADD_IP) 5848c2ecf20Sopenharmony_ci continue; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (!sctp_state(asoc, ESTABLISHED)) 5878c2ecf20Sopenharmony_ci continue; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* Check if any address in the packed array of addresses is 5908c2ecf20Sopenharmony_ci * in the bind address list of the association. If so, 5918c2ecf20Sopenharmony_ci * do not send the asconf chunk to its peer, but continue with 5928c2ecf20Sopenharmony_ci * other associations. 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_ci addr_buf = addrs; 5958c2ecf20Sopenharmony_ci for (i = 0; i < addrcnt; i++) { 5968c2ecf20Sopenharmony_ci addr = addr_buf; 5978c2ecf20Sopenharmony_ci af = sctp_get_af_specific(addr->v4.sin_family); 5988c2ecf20Sopenharmony_ci if (!af) { 5998c2ecf20Sopenharmony_ci retval = -EINVAL; 6008c2ecf20Sopenharmony_ci goto out; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (sctp_assoc_lookup_laddr(asoc, addr)) 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci if (i < addrcnt) 6098c2ecf20Sopenharmony_ci continue; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* Use the first valid address in bind addr list of 6128c2ecf20Sopenharmony_ci * association as Address Parameter of ASCONF CHUNK. 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_ci bp = &asoc->base.bind_addr; 6158c2ecf20Sopenharmony_ci p = bp->address_list.next; 6168c2ecf20Sopenharmony_ci laddr = list_entry(p, struct sctp_sockaddr_entry, list); 6178c2ecf20Sopenharmony_ci chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs, 6188c2ecf20Sopenharmony_ci addrcnt, SCTP_PARAM_ADD_IP); 6198c2ecf20Sopenharmony_ci if (!chunk) { 6208c2ecf20Sopenharmony_ci retval = -ENOMEM; 6218c2ecf20Sopenharmony_ci goto out; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Add the new addresses to the bind address list with 6258c2ecf20Sopenharmony_ci * use_as_src set to 0. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci addr_buf = addrs; 6288c2ecf20Sopenharmony_ci for (i = 0; i < addrcnt; i++) { 6298c2ecf20Sopenharmony_ci addr = addr_buf; 6308c2ecf20Sopenharmony_ci af = sctp_get_af_specific(addr->v4.sin_family); 6318c2ecf20Sopenharmony_ci memcpy(&saveaddr, addr, af->sockaddr_len); 6328c2ecf20Sopenharmony_ci retval = sctp_add_bind_addr(bp, &saveaddr, 6338c2ecf20Sopenharmony_ci sizeof(saveaddr), 6348c2ecf20Sopenharmony_ci SCTP_ADDR_NEW, GFP_ATOMIC); 6358c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci if (asoc->src_out_of_asoc_ok) { 6388c2ecf20Sopenharmony_ci struct sctp_transport *trans; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci list_for_each_entry(trans, 6418c2ecf20Sopenharmony_ci &asoc->peer.transport_addr_list, transports) { 6428c2ecf20Sopenharmony_ci trans->cwnd = min(4*asoc->pathmtu, max_t(__u32, 6438c2ecf20Sopenharmony_ci 2*asoc->pathmtu, 4380)); 6448c2ecf20Sopenharmony_ci trans->ssthresh = asoc->peer.i.a_rwnd; 6458c2ecf20Sopenharmony_ci trans->rto = asoc->rto_initial; 6468c2ecf20Sopenharmony_ci sctp_max_rto(asoc, trans); 6478c2ecf20Sopenharmony_ci trans->rtt = trans->srtt = trans->rttvar = 0; 6488c2ecf20Sopenharmony_ci /* Clear the source and route cache */ 6498c2ecf20Sopenharmony_ci sctp_transport_route(trans, NULL, 6508c2ecf20Sopenharmony_ci sctp_sk(asoc->base.sk)); 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci retval = sctp_send_asconf(asoc, chunk); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ciout: 6578c2ecf20Sopenharmony_ci return retval; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/* Remove a list of addresses from bind addresses list. Do not remove the 6618c2ecf20Sopenharmony_ci * last address. 6628c2ecf20Sopenharmony_ci * 6638c2ecf20Sopenharmony_ci * Basically run through each address specified in the addrs/addrcnt 6648c2ecf20Sopenharmony_ci * array/length pair, determine if it is IPv6 or IPv4 and call 6658c2ecf20Sopenharmony_ci * sctp_del_bind() on it. 6668c2ecf20Sopenharmony_ci * 6678c2ecf20Sopenharmony_ci * If any of them fails, then the operation will be reversed and the 6688c2ecf20Sopenharmony_ci * ones that were removed will be added back. 6698c2ecf20Sopenharmony_ci * 6708c2ecf20Sopenharmony_ci * At least one address has to be left; if only one address is 6718c2ecf20Sopenharmony_ci * available, the operation will return -EBUSY. 6728c2ecf20Sopenharmony_ci * 6738c2ecf20Sopenharmony_ci * Only sctp_setsockopt_bindx() is supposed to call this function. 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_cistatic int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 6788c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sp->ep; 6798c2ecf20Sopenharmony_ci int cnt; 6808c2ecf20Sopenharmony_ci struct sctp_bind_addr *bp = &ep->base.bind_addr; 6818c2ecf20Sopenharmony_ci int retval = 0; 6828c2ecf20Sopenharmony_ci void *addr_buf; 6838c2ecf20Sopenharmony_ci union sctp_addr *sa_addr; 6848c2ecf20Sopenharmony_ci struct sctp_af *af; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 6878c2ecf20Sopenharmony_ci __func__, sk, addrs, addrcnt); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci addr_buf = addrs; 6908c2ecf20Sopenharmony_ci for (cnt = 0; cnt < addrcnt; cnt++) { 6918c2ecf20Sopenharmony_ci /* If the bind address list is empty or if there is only one 6928c2ecf20Sopenharmony_ci * bind address, there is nothing more to be removed (we need 6938c2ecf20Sopenharmony_ci * at least one address here). 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_ci if (list_empty(&bp->address_list) || 6968c2ecf20Sopenharmony_ci (sctp_list_single_entry(&bp->address_list))) { 6978c2ecf20Sopenharmony_ci retval = -EBUSY; 6988c2ecf20Sopenharmony_ci goto err_bindx_rem; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci sa_addr = addr_buf; 7028c2ecf20Sopenharmony_ci af = sctp_get_af_specific(sa_addr->sa.sa_family); 7038c2ecf20Sopenharmony_ci if (!af) { 7048c2ecf20Sopenharmony_ci retval = -EINVAL; 7058c2ecf20Sopenharmony_ci goto err_bindx_rem; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (!af->addr_valid(sa_addr, sp, NULL)) { 7098c2ecf20Sopenharmony_ci retval = -EADDRNOTAVAIL; 7108c2ecf20Sopenharmony_ci goto err_bindx_rem; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (sa_addr->v4.sin_port && 7148c2ecf20Sopenharmony_ci sa_addr->v4.sin_port != htons(bp->port)) { 7158c2ecf20Sopenharmony_ci retval = -EINVAL; 7168c2ecf20Sopenharmony_ci goto err_bindx_rem; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (!sa_addr->v4.sin_port) 7208c2ecf20Sopenharmony_ci sa_addr->v4.sin_port = htons(bp->port); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* FIXME - There is probably a need to check if sk->sk_saddr and 7238c2ecf20Sopenharmony_ci * sk->sk_rcv_addr are currently set to one of the addresses to 7248c2ecf20Sopenharmony_ci * be removed. This is something which needs to be looked into 7258c2ecf20Sopenharmony_ci * when we are fixing the outstanding issues with multi-homing 7268c2ecf20Sopenharmony_ci * socket routing and failover schemes. Refer to comments in 7278c2ecf20Sopenharmony_ci * sctp_do_bind(). -daisy 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ci retval = sctp_del_bind_addr(bp, sa_addr); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 7328c2ecf20Sopenharmony_cierr_bindx_rem: 7338c2ecf20Sopenharmony_ci if (retval < 0) { 7348c2ecf20Sopenharmony_ci /* Failed. Add the ones that has been removed back */ 7358c2ecf20Sopenharmony_ci if (cnt > 0) 7368c2ecf20Sopenharmony_ci sctp_bindx_add(sk, addrs, cnt); 7378c2ecf20Sopenharmony_ci return retval; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return retval; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/* Send an ASCONF chunk with Delete IP address parameters to all the peers of 7458c2ecf20Sopenharmony_ci * the associations that are part of the endpoint indicating that a list of 7468c2ecf20Sopenharmony_ci * local addresses are removed from the endpoint. 7478c2ecf20Sopenharmony_ci * 7488c2ecf20Sopenharmony_ci * If any of the addresses is already in the bind address list of the 7498c2ecf20Sopenharmony_ci * association, we do not send the chunk for that association. But it will not 7508c2ecf20Sopenharmony_ci * affect other associations. 7518c2ecf20Sopenharmony_ci * 7528c2ecf20Sopenharmony_ci * Only sctp_setsockopt_bindx() is supposed to call this function. 7538c2ecf20Sopenharmony_ci */ 7548c2ecf20Sopenharmony_cistatic int sctp_send_asconf_del_ip(struct sock *sk, 7558c2ecf20Sopenharmony_ci struct sockaddr *addrs, 7568c2ecf20Sopenharmony_ci int addrcnt) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci struct sctp_sock *sp; 7598c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 7608c2ecf20Sopenharmony_ci struct sctp_association *asoc; 7618c2ecf20Sopenharmony_ci struct sctp_transport *transport; 7628c2ecf20Sopenharmony_ci struct sctp_bind_addr *bp; 7638c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 7648c2ecf20Sopenharmony_ci union sctp_addr *laddr; 7658c2ecf20Sopenharmony_ci void *addr_buf; 7668c2ecf20Sopenharmony_ci struct sctp_af *af; 7678c2ecf20Sopenharmony_ci struct sctp_sockaddr_entry *saddr; 7688c2ecf20Sopenharmony_ci int i; 7698c2ecf20Sopenharmony_ci int retval = 0; 7708c2ecf20Sopenharmony_ci int stored = 0; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci chunk = NULL; 7738c2ecf20Sopenharmony_ci sp = sctp_sk(sk); 7748c2ecf20Sopenharmony_ci ep = sp->ep; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (!ep->asconf_enable) 7778c2ecf20Sopenharmony_ci return retval; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 7808c2ecf20Sopenharmony_ci __func__, sk, addrs, addrcnt); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &ep->asocs, asocs) { 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (!asoc->peer.asconf_capable) 7858c2ecf20Sopenharmony_ci continue; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (asoc->peer.addip_disabled_mask & SCTP_PARAM_DEL_IP) 7888c2ecf20Sopenharmony_ci continue; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (!sctp_state(asoc, ESTABLISHED)) 7918c2ecf20Sopenharmony_ci continue; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* Check if any address in the packed array of addresses is 7948c2ecf20Sopenharmony_ci * not present in the bind address list of the association. 7958c2ecf20Sopenharmony_ci * If so, do not send the asconf chunk to its peer, but 7968c2ecf20Sopenharmony_ci * continue with other associations. 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci addr_buf = addrs; 7998c2ecf20Sopenharmony_ci for (i = 0; i < addrcnt; i++) { 8008c2ecf20Sopenharmony_ci laddr = addr_buf; 8018c2ecf20Sopenharmony_ci af = sctp_get_af_specific(laddr->v4.sin_family); 8028c2ecf20Sopenharmony_ci if (!af) { 8038c2ecf20Sopenharmony_ci retval = -EINVAL; 8048c2ecf20Sopenharmony_ci goto out; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (!sctp_assoc_lookup_laddr(asoc, laddr)) 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci if (i < addrcnt) 8138c2ecf20Sopenharmony_ci continue; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* Find one address in the association's bind address list 8168c2ecf20Sopenharmony_ci * that is not in the packed array of addresses. This is to 8178c2ecf20Sopenharmony_ci * make sure that we do not delete all the addresses in the 8188c2ecf20Sopenharmony_ci * association. 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_ci bp = &asoc->base.bind_addr; 8218c2ecf20Sopenharmony_ci laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, 8228c2ecf20Sopenharmony_ci addrcnt, sp); 8238c2ecf20Sopenharmony_ci if ((laddr == NULL) && (addrcnt == 1)) { 8248c2ecf20Sopenharmony_ci if (asoc->asconf_addr_del_pending) 8258c2ecf20Sopenharmony_ci continue; 8268c2ecf20Sopenharmony_ci asoc->asconf_addr_del_pending = 8278c2ecf20Sopenharmony_ci kzalloc(sizeof(union sctp_addr), GFP_ATOMIC); 8288c2ecf20Sopenharmony_ci if (asoc->asconf_addr_del_pending == NULL) { 8298c2ecf20Sopenharmony_ci retval = -ENOMEM; 8308c2ecf20Sopenharmony_ci goto out; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci asoc->asconf_addr_del_pending->sa.sa_family = 8338c2ecf20Sopenharmony_ci addrs->sa_family; 8348c2ecf20Sopenharmony_ci asoc->asconf_addr_del_pending->v4.sin_port = 8358c2ecf20Sopenharmony_ci htons(bp->port); 8368c2ecf20Sopenharmony_ci if (addrs->sa_family == AF_INET) { 8378c2ecf20Sopenharmony_ci struct sockaddr_in *sin; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci sin = (struct sockaddr_in *)addrs; 8408c2ecf20Sopenharmony_ci asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr; 8418c2ecf20Sopenharmony_ci } else if (addrs->sa_family == AF_INET6) { 8428c2ecf20Sopenharmony_ci struct sockaddr_in6 *sin6; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci sin6 = (struct sockaddr_in6 *)addrs; 8458c2ecf20Sopenharmony_ci asoc->asconf_addr_del_pending->v6.sin6_addr = sin6->sin6_addr; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci pr_debug("%s: keep the last address asoc:%p %pISc at %p\n", 8498c2ecf20Sopenharmony_ci __func__, asoc, &asoc->asconf_addr_del_pending->sa, 8508c2ecf20Sopenharmony_ci asoc->asconf_addr_del_pending); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci asoc->src_out_of_asoc_ok = 1; 8538c2ecf20Sopenharmony_ci stored = 1; 8548c2ecf20Sopenharmony_ci goto skip_mkasconf; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (laddr == NULL) 8588c2ecf20Sopenharmony_ci return -EINVAL; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* We do not need RCU protection throughout this loop 8618c2ecf20Sopenharmony_ci * because this is done under a socket lock from the 8628c2ecf20Sopenharmony_ci * setsockopt call. 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_ci chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt, 8658c2ecf20Sopenharmony_ci SCTP_PARAM_DEL_IP); 8668c2ecf20Sopenharmony_ci if (!chunk) { 8678c2ecf20Sopenharmony_ci retval = -ENOMEM; 8688c2ecf20Sopenharmony_ci goto out; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ciskip_mkasconf: 8728c2ecf20Sopenharmony_ci /* Reset use_as_src flag for the addresses in the bind address 8738c2ecf20Sopenharmony_ci * list that are to be deleted. 8748c2ecf20Sopenharmony_ci */ 8758c2ecf20Sopenharmony_ci addr_buf = addrs; 8768c2ecf20Sopenharmony_ci for (i = 0; i < addrcnt; i++) { 8778c2ecf20Sopenharmony_ci laddr = addr_buf; 8788c2ecf20Sopenharmony_ci af = sctp_get_af_specific(laddr->v4.sin_family); 8798c2ecf20Sopenharmony_ci list_for_each_entry(saddr, &bp->address_list, list) { 8808c2ecf20Sopenharmony_ci if (sctp_cmp_addr_exact(&saddr->a, laddr)) 8818c2ecf20Sopenharmony_ci saddr->state = SCTP_ADDR_DEL; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* Update the route and saddr entries for all the transports 8878c2ecf20Sopenharmony_ci * as some of the addresses in the bind address list are 8888c2ecf20Sopenharmony_ci * about to be deleted and cannot be used as source addresses. 8898c2ecf20Sopenharmony_ci */ 8908c2ecf20Sopenharmony_ci list_for_each_entry(transport, &asoc->peer.transport_addr_list, 8918c2ecf20Sopenharmony_ci transports) { 8928c2ecf20Sopenharmony_ci sctp_transport_route(transport, NULL, 8938c2ecf20Sopenharmony_ci sctp_sk(asoc->base.sk)); 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (stored) 8978c2ecf20Sopenharmony_ci /* We don't need to transmit ASCONF */ 8988c2ecf20Sopenharmony_ci continue; 8998c2ecf20Sopenharmony_ci retval = sctp_send_asconf(asoc, chunk); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ciout: 9028c2ecf20Sopenharmony_ci return retval; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci/* set addr events to assocs in the endpoint. ep and addr_wq must be locked */ 9068c2ecf20Sopenharmony_ciint sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci struct sock *sk = sctp_opt2sk(sp); 9098c2ecf20Sopenharmony_ci union sctp_addr *addr; 9108c2ecf20Sopenharmony_ci struct sctp_af *af; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* It is safe to write port space in caller. */ 9138c2ecf20Sopenharmony_ci addr = &addrw->a; 9148c2ecf20Sopenharmony_ci addr->v4.sin_port = htons(sp->ep->base.bind_addr.port); 9158c2ecf20Sopenharmony_ci af = sctp_get_af_specific(addr->sa.sa_family); 9168c2ecf20Sopenharmony_ci if (!af) 9178c2ecf20Sopenharmony_ci return -EINVAL; 9188c2ecf20Sopenharmony_ci if (sctp_verify_addr(sk, addr, af->sockaddr_len)) 9198c2ecf20Sopenharmony_ci return -EINVAL; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (addrw->state == SCTP_ADDR_NEW) 9228c2ecf20Sopenharmony_ci return sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1); 9238c2ecf20Sopenharmony_ci else 9248c2ecf20Sopenharmony_ci return sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1); 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci/* Helper for tunneling sctp_bindx() requests through sctp_setsockopt() 9288c2ecf20Sopenharmony_ci * 9298c2ecf20Sopenharmony_ci * API 8.1 9308c2ecf20Sopenharmony_ci * int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, 9318c2ecf20Sopenharmony_ci * int flags); 9328c2ecf20Sopenharmony_ci * 9338c2ecf20Sopenharmony_ci * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. 9348c2ecf20Sopenharmony_ci * If the sd is an IPv6 socket, the addresses passed can either be IPv4 9358c2ecf20Sopenharmony_ci * or IPv6 addresses. 9368c2ecf20Sopenharmony_ci * 9378c2ecf20Sopenharmony_ci * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see 9388c2ecf20Sopenharmony_ci * Section 3.1.2 for this usage. 9398c2ecf20Sopenharmony_ci * 9408c2ecf20Sopenharmony_ci * addrs is a pointer to an array of one or more socket addresses. Each 9418c2ecf20Sopenharmony_ci * address is contained in its appropriate structure (i.e. struct 9428c2ecf20Sopenharmony_ci * sockaddr_in or struct sockaddr_in6) the family of the address type 9438c2ecf20Sopenharmony_ci * must be used to distinguish the address length (note that this 9448c2ecf20Sopenharmony_ci * representation is termed a "packed array" of addresses). The caller 9458c2ecf20Sopenharmony_ci * specifies the number of addresses in the array with addrcnt. 9468c2ecf20Sopenharmony_ci * 9478c2ecf20Sopenharmony_ci * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns 9488c2ecf20Sopenharmony_ci * -1, and sets errno to the appropriate error code. 9498c2ecf20Sopenharmony_ci * 9508c2ecf20Sopenharmony_ci * For SCTP, the port given in each socket address must be the same, or 9518c2ecf20Sopenharmony_ci * sctp_bindx() will fail, setting errno to EINVAL. 9528c2ecf20Sopenharmony_ci * 9538c2ecf20Sopenharmony_ci * The flags parameter is formed from the bitwise OR of zero or more of 9548c2ecf20Sopenharmony_ci * the following currently defined flags: 9558c2ecf20Sopenharmony_ci * 9568c2ecf20Sopenharmony_ci * SCTP_BINDX_ADD_ADDR 9578c2ecf20Sopenharmony_ci * 9588c2ecf20Sopenharmony_ci * SCTP_BINDX_REM_ADDR 9598c2ecf20Sopenharmony_ci * 9608c2ecf20Sopenharmony_ci * SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the 9618c2ecf20Sopenharmony_ci * association, and SCTP_BINDX_REM_ADDR directs SCTP to remove the given 9628c2ecf20Sopenharmony_ci * addresses from the association. The two flags are mutually exclusive; 9638c2ecf20Sopenharmony_ci * if both are given, sctp_bindx() will fail with EINVAL. A caller may 9648c2ecf20Sopenharmony_ci * not remove all addresses from an association; sctp_bindx() will 9658c2ecf20Sopenharmony_ci * reject such an attempt with EINVAL. 9668c2ecf20Sopenharmony_ci * 9678c2ecf20Sopenharmony_ci * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate 9688c2ecf20Sopenharmony_ci * additional addresses with an endpoint after calling bind(). Or use 9698c2ecf20Sopenharmony_ci * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening 9708c2ecf20Sopenharmony_ci * socket is associated with so that no new association accepted will be 9718c2ecf20Sopenharmony_ci * associated with those addresses. If the endpoint supports dynamic 9728c2ecf20Sopenharmony_ci * address a SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR may cause a 9738c2ecf20Sopenharmony_ci * endpoint to send the appropriate message to the peer to change the 9748c2ecf20Sopenharmony_ci * peers address lists. 9758c2ecf20Sopenharmony_ci * 9768c2ecf20Sopenharmony_ci * Adding and removing addresses from a connected association is 9778c2ecf20Sopenharmony_ci * optional functionality. Implementations that do not support this 9788c2ecf20Sopenharmony_ci * functionality should return EOPNOTSUPP. 9798c2ecf20Sopenharmony_ci * 9808c2ecf20Sopenharmony_ci * Basically do nothing but copying the addresses from user to kernel 9818c2ecf20Sopenharmony_ci * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk. 9828c2ecf20Sopenharmony_ci * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() 9838c2ecf20Sopenharmony_ci * from userspace. 9848c2ecf20Sopenharmony_ci * 9858c2ecf20Sopenharmony_ci * On exit there is no need to do sockfd_put(), sys_setsockopt() does 9868c2ecf20Sopenharmony_ci * it. 9878c2ecf20Sopenharmony_ci * 9888c2ecf20Sopenharmony_ci * sk The sk of the socket 9898c2ecf20Sopenharmony_ci * addrs The pointer to the addresses 9908c2ecf20Sopenharmony_ci * addrssize Size of the addrs buffer 9918c2ecf20Sopenharmony_ci * op Operation to perform (add or remove, see the flags of 9928c2ecf20Sopenharmony_ci * sctp_bindx) 9938c2ecf20Sopenharmony_ci * 9948c2ecf20Sopenharmony_ci * Returns 0 if ok, <0 errno code on error. 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_cistatic int sctp_setsockopt_bindx(struct sock *sk, struct sockaddr *addrs, 9978c2ecf20Sopenharmony_ci int addrs_size, int op) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci int err; 10008c2ecf20Sopenharmony_ci int addrcnt = 0; 10018c2ecf20Sopenharmony_ci int walk_size = 0; 10028c2ecf20Sopenharmony_ci struct sockaddr *sa_addr; 10038c2ecf20Sopenharmony_ci void *addr_buf = addrs; 10048c2ecf20Sopenharmony_ci struct sctp_af *af; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p addrs:%p addrs_size:%d opt:%d\n", 10078c2ecf20Sopenharmony_ci __func__, sk, addr_buf, addrs_size, op); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (unlikely(addrs_size <= 0)) 10108c2ecf20Sopenharmony_ci return -EINVAL; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* Walk through the addrs buffer and count the number of addresses. */ 10138c2ecf20Sopenharmony_ci while (walk_size < addrs_size) { 10148c2ecf20Sopenharmony_ci if (walk_size + sizeof(sa_family_t) > addrs_size) 10158c2ecf20Sopenharmony_ci return -EINVAL; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci sa_addr = addr_buf; 10188c2ecf20Sopenharmony_ci af = sctp_get_af_specific(sa_addr->sa_family); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* If the address family is not supported or if this address 10218c2ecf20Sopenharmony_ci * causes the address buffer to overflow return EINVAL. 10228c2ecf20Sopenharmony_ci */ 10238c2ecf20Sopenharmony_ci if (!af || (walk_size + af->sockaddr_len) > addrs_size) 10248c2ecf20Sopenharmony_ci return -EINVAL; 10258c2ecf20Sopenharmony_ci addrcnt++; 10268c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 10278c2ecf20Sopenharmony_ci walk_size += af->sockaddr_len; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* Do the work. */ 10318c2ecf20Sopenharmony_ci switch (op) { 10328c2ecf20Sopenharmony_ci case SCTP_BINDX_ADD_ADDR: 10338c2ecf20Sopenharmony_ci /* Allow security module to validate bindx addresses. */ 10348c2ecf20Sopenharmony_ci err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_BINDX_ADD, 10358c2ecf20Sopenharmony_ci addrs, addrs_size); 10368c2ecf20Sopenharmony_ci if (err) 10378c2ecf20Sopenharmony_ci return err; 10388c2ecf20Sopenharmony_ci err = sctp_bindx_add(sk, addrs, addrcnt); 10398c2ecf20Sopenharmony_ci if (err) 10408c2ecf20Sopenharmony_ci return err; 10418c2ecf20Sopenharmony_ci return sctp_send_asconf_add_ip(sk, addrs, addrcnt); 10428c2ecf20Sopenharmony_ci case SCTP_BINDX_REM_ADDR: 10438c2ecf20Sopenharmony_ci err = sctp_bindx_rem(sk, addrs, addrcnt); 10448c2ecf20Sopenharmony_ci if (err) 10458c2ecf20Sopenharmony_ci return err; 10468c2ecf20Sopenharmony_ci return sctp_send_asconf_del_ip(sk, addrs, addrcnt); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci default: 10498c2ecf20Sopenharmony_ci return -EINVAL; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic int sctp_bind_add(struct sock *sk, struct sockaddr *addrs, 10548c2ecf20Sopenharmony_ci int addrlen) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci int err; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci lock_sock(sk); 10598c2ecf20Sopenharmony_ci err = sctp_setsockopt_bindx(sk, addrs, addrlen, SCTP_BINDX_ADD_ADDR); 10608c2ecf20Sopenharmony_ci release_sock(sk); 10618c2ecf20Sopenharmony_ci return err; 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic int sctp_connect_new_asoc(struct sctp_endpoint *ep, 10658c2ecf20Sopenharmony_ci const union sctp_addr *daddr, 10668c2ecf20Sopenharmony_ci const struct sctp_initmsg *init, 10678c2ecf20Sopenharmony_ci struct sctp_transport **tp) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct sctp_association *asoc; 10708c2ecf20Sopenharmony_ci struct sock *sk = ep->base.sk; 10718c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 10728c2ecf20Sopenharmony_ci enum sctp_scope scope; 10738c2ecf20Sopenharmony_ci int err; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (sctp_endpoint_is_peeled_off(ep, daddr)) 10768c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (!ep->base.bind_addr.port) { 10798c2ecf20Sopenharmony_ci if (sctp_autobind(sk)) 10808c2ecf20Sopenharmony_ci return -EAGAIN; 10818c2ecf20Sopenharmony_ci } else { 10828c2ecf20Sopenharmony_ci if (inet_port_requires_bind_service(net, ep->base.bind_addr.port) && 10838c2ecf20Sopenharmony_ci !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 10848c2ecf20Sopenharmony_ci return -EACCES; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci scope = sctp_scope(daddr); 10888c2ecf20Sopenharmony_ci asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); 10898c2ecf20Sopenharmony_ci if (!asoc) 10908c2ecf20Sopenharmony_ci return -ENOMEM; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL); 10938c2ecf20Sopenharmony_ci if (err < 0) 10948c2ecf20Sopenharmony_ci goto free; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci *tp = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN); 10978c2ecf20Sopenharmony_ci if (!*tp) { 10988c2ecf20Sopenharmony_ci err = -ENOMEM; 10998c2ecf20Sopenharmony_ci goto free; 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (!init) 11038c2ecf20Sopenharmony_ci return 0; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (init->sinit_num_ostreams) { 11068c2ecf20Sopenharmony_ci __u16 outcnt = init->sinit_num_ostreams; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci asoc->c.sinit_num_ostreams = outcnt; 11098c2ecf20Sopenharmony_ci /* outcnt has been changed, need to re-init stream */ 11108c2ecf20Sopenharmony_ci err = sctp_stream_init(&asoc->stream, outcnt, 0, GFP_KERNEL); 11118c2ecf20Sopenharmony_ci if (err) 11128c2ecf20Sopenharmony_ci goto free; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (init->sinit_max_instreams) 11168c2ecf20Sopenharmony_ci asoc->c.sinit_max_instreams = init->sinit_max_instreams; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (init->sinit_max_attempts) 11198c2ecf20Sopenharmony_ci asoc->max_init_attempts = init->sinit_max_attempts; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (init->sinit_max_init_timeo) 11228c2ecf20Sopenharmony_ci asoc->max_init_timeo = 11238c2ecf20Sopenharmony_ci msecs_to_jiffies(init->sinit_max_init_timeo); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci return 0; 11268c2ecf20Sopenharmony_cifree: 11278c2ecf20Sopenharmony_ci sctp_association_free(asoc); 11288c2ecf20Sopenharmony_ci return err; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic int sctp_connect_add_peer(struct sctp_association *asoc, 11328c2ecf20Sopenharmony_ci union sctp_addr *daddr, int addr_len) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = asoc->ep; 11358c2ecf20Sopenharmony_ci struct sctp_association *old; 11368c2ecf20Sopenharmony_ci struct sctp_transport *t; 11378c2ecf20Sopenharmony_ci int err; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci err = sctp_verify_addr(ep->base.sk, daddr, addr_len); 11408c2ecf20Sopenharmony_ci if (err) 11418c2ecf20Sopenharmony_ci return err; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci old = sctp_endpoint_lookup_assoc(ep, daddr, &t); 11448c2ecf20Sopenharmony_ci if (old && old != asoc) 11458c2ecf20Sopenharmony_ci return old->state >= SCTP_STATE_ESTABLISHED ? -EISCONN 11468c2ecf20Sopenharmony_ci : -EALREADY; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (sctp_endpoint_is_peeled_off(ep, daddr)) 11498c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci t = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN); 11528c2ecf20Sopenharmony_ci if (!t) 11538c2ecf20Sopenharmony_ci return -ENOMEM; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci return 0; 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci/* __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, int addrs_size) 11598c2ecf20Sopenharmony_ci * 11608c2ecf20Sopenharmony_ci * Common routine for handling connect() and sctp_connectx(). 11618c2ecf20Sopenharmony_ci * Connect will come in with just a single address. 11628c2ecf20Sopenharmony_ci */ 11638c2ecf20Sopenharmony_cistatic int __sctp_connect(struct sock *sk, struct sockaddr *kaddrs, 11648c2ecf20Sopenharmony_ci int addrs_size, int flags, sctp_assoc_t *assoc_id) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 11678c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sp->ep; 11688c2ecf20Sopenharmony_ci struct sctp_transport *transport; 11698c2ecf20Sopenharmony_ci struct sctp_association *asoc; 11708c2ecf20Sopenharmony_ci void *addr_buf = kaddrs; 11718c2ecf20Sopenharmony_ci union sctp_addr *daddr; 11728c2ecf20Sopenharmony_ci struct sctp_af *af; 11738c2ecf20Sopenharmony_ci int walk_size, err; 11748c2ecf20Sopenharmony_ci long timeo; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING) || 11778c2ecf20Sopenharmony_ci (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) 11788c2ecf20Sopenharmony_ci return -EISCONN; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci daddr = addr_buf; 11818c2ecf20Sopenharmony_ci af = sctp_get_af_specific(daddr->sa.sa_family); 11828c2ecf20Sopenharmony_ci if (!af || af->sockaddr_len > addrs_size) 11838c2ecf20Sopenharmony_ci return -EINVAL; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci err = sctp_verify_addr(sk, daddr, af->sockaddr_len); 11868c2ecf20Sopenharmony_ci if (err) 11878c2ecf20Sopenharmony_ci return err; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport); 11908c2ecf20Sopenharmony_ci if (asoc) 11918c2ecf20Sopenharmony_ci return asoc->state >= SCTP_STATE_ESTABLISHED ? -EISCONN 11928c2ecf20Sopenharmony_ci : -EALREADY; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci err = sctp_connect_new_asoc(ep, daddr, NULL, &transport); 11958c2ecf20Sopenharmony_ci if (err) 11968c2ecf20Sopenharmony_ci return err; 11978c2ecf20Sopenharmony_ci asoc = transport->asoc; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 12008c2ecf20Sopenharmony_ci walk_size = af->sockaddr_len; 12018c2ecf20Sopenharmony_ci while (walk_size < addrs_size) { 12028c2ecf20Sopenharmony_ci err = -EINVAL; 12038c2ecf20Sopenharmony_ci if (walk_size + sizeof(sa_family_t) > addrs_size) 12048c2ecf20Sopenharmony_ci goto out_free; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci daddr = addr_buf; 12078c2ecf20Sopenharmony_ci af = sctp_get_af_specific(daddr->sa.sa_family); 12088c2ecf20Sopenharmony_ci if (!af || af->sockaddr_len + walk_size > addrs_size) 12098c2ecf20Sopenharmony_ci goto out_free; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (asoc->peer.port != ntohs(daddr->v4.sin_port)) 12128c2ecf20Sopenharmony_ci goto out_free; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci err = sctp_connect_add_peer(asoc, daddr, af->sockaddr_len); 12158c2ecf20Sopenharmony_ci if (err) 12168c2ecf20Sopenharmony_ci goto out_free; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci addr_buf += af->sockaddr_len; 12198c2ecf20Sopenharmony_ci walk_size += af->sockaddr_len; 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci /* In case the user of sctp_connectx() wants an association 12238c2ecf20Sopenharmony_ci * id back, assign one now. 12248c2ecf20Sopenharmony_ci */ 12258c2ecf20Sopenharmony_ci if (assoc_id) { 12268c2ecf20Sopenharmony_ci err = sctp_assoc_set_id(asoc, GFP_KERNEL); 12278c2ecf20Sopenharmony_ci if (err < 0) 12288c2ecf20Sopenharmony_ci goto out_free; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci err = sctp_primitive_ASSOCIATE(sock_net(sk), asoc, NULL); 12328c2ecf20Sopenharmony_ci if (err < 0) 12338c2ecf20Sopenharmony_ci goto out_free; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci /* Initialize sk's dport and daddr for getpeername() */ 12368c2ecf20Sopenharmony_ci inet_sk(sk)->inet_dport = htons(asoc->peer.port); 12378c2ecf20Sopenharmony_ci sp->pf->to_sk_daddr(daddr, sk); 12388c2ecf20Sopenharmony_ci sk->sk_err = 0; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (assoc_id) 12418c2ecf20Sopenharmony_ci *assoc_id = asoc->assoc_id; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); 12448c2ecf20Sopenharmony_ci return sctp_wait_for_connect(asoc, &timeo); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ciout_free: 12478c2ecf20Sopenharmony_ci pr_debug("%s: took out_free path with asoc:%p kaddrs:%p err:%d\n", 12488c2ecf20Sopenharmony_ci __func__, asoc, kaddrs, err); 12498c2ecf20Sopenharmony_ci sctp_association_free(asoc); 12508c2ecf20Sopenharmony_ci return err; 12518c2ecf20Sopenharmony_ci} 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci/* Helper for tunneling sctp_connectx() requests through sctp_setsockopt() 12548c2ecf20Sopenharmony_ci * 12558c2ecf20Sopenharmony_ci * API 8.9 12568c2ecf20Sopenharmony_ci * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt, 12578c2ecf20Sopenharmony_ci * sctp_assoc_t *asoc); 12588c2ecf20Sopenharmony_ci * 12598c2ecf20Sopenharmony_ci * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. 12608c2ecf20Sopenharmony_ci * If the sd is an IPv6 socket, the addresses passed can either be IPv4 12618c2ecf20Sopenharmony_ci * or IPv6 addresses. 12628c2ecf20Sopenharmony_ci * 12638c2ecf20Sopenharmony_ci * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see 12648c2ecf20Sopenharmony_ci * Section 3.1.2 for this usage. 12658c2ecf20Sopenharmony_ci * 12668c2ecf20Sopenharmony_ci * addrs is a pointer to an array of one or more socket addresses. Each 12678c2ecf20Sopenharmony_ci * address is contained in its appropriate structure (i.e. struct 12688c2ecf20Sopenharmony_ci * sockaddr_in or struct sockaddr_in6) the family of the address type 12698c2ecf20Sopenharmony_ci * must be used to distengish the address length (note that this 12708c2ecf20Sopenharmony_ci * representation is termed a "packed array" of addresses). The caller 12718c2ecf20Sopenharmony_ci * specifies the number of addresses in the array with addrcnt. 12728c2ecf20Sopenharmony_ci * 12738c2ecf20Sopenharmony_ci * On success, sctp_connectx() returns 0. It also sets the assoc_id to 12748c2ecf20Sopenharmony_ci * the association id of the new association. On failure, sctp_connectx() 12758c2ecf20Sopenharmony_ci * returns -1, and sets errno to the appropriate error code. The assoc_id 12768c2ecf20Sopenharmony_ci * is not touched by the kernel. 12778c2ecf20Sopenharmony_ci * 12788c2ecf20Sopenharmony_ci * For SCTP, the port given in each socket address must be the same, or 12798c2ecf20Sopenharmony_ci * sctp_connectx() will fail, setting errno to EINVAL. 12808c2ecf20Sopenharmony_ci * 12818c2ecf20Sopenharmony_ci * An application can use sctp_connectx to initiate an association with 12828c2ecf20Sopenharmony_ci * an endpoint that is multi-homed. Much like sctp_bindx() this call 12838c2ecf20Sopenharmony_ci * allows a caller to specify multiple addresses at which a peer can be 12848c2ecf20Sopenharmony_ci * reached. The way the SCTP stack uses the list of addresses to set up 12858c2ecf20Sopenharmony_ci * the association is implementation dependent. This function only 12868c2ecf20Sopenharmony_ci * specifies that the stack will try to make use of all the addresses in 12878c2ecf20Sopenharmony_ci * the list when needed. 12888c2ecf20Sopenharmony_ci * 12898c2ecf20Sopenharmony_ci * Note that the list of addresses passed in is only used for setting up 12908c2ecf20Sopenharmony_ci * the association. It does not necessarily equal the set of addresses 12918c2ecf20Sopenharmony_ci * the peer uses for the resulting association. If the caller wants to 12928c2ecf20Sopenharmony_ci * find out the set of peer addresses, it must use sctp_getpaddrs() to 12938c2ecf20Sopenharmony_ci * retrieve them after the association has been set up. 12948c2ecf20Sopenharmony_ci * 12958c2ecf20Sopenharmony_ci * Basically do nothing but copying the addresses from user to kernel 12968c2ecf20Sopenharmony_ci * land and invoking either sctp_connectx(). This is used for tunneling 12978c2ecf20Sopenharmony_ci * the sctp_connectx() request through sctp_setsockopt() from userspace. 12988c2ecf20Sopenharmony_ci * 12998c2ecf20Sopenharmony_ci * On exit there is no need to do sockfd_put(), sys_setsockopt() does 13008c2ecf20Sopenharmony_ci * it. 13018c2ecf20Sopenharmony_ci * 13028c2ecf20Sopenharmony_ci * sk The sk of the socket 13038c2ecf20Sopenharmony_ci * addrs The pointer to the addresses 13048c2ecf20Sopenharmony_ci * addrssize Size of the addrs buffer 13058c2ecf20Sopenharmony_ci * 13068c2ecf20Sopenharmony_ci * Returns >=0 if ok, <0 errno code on error. 13078c2ecf20Sopenharmony_ci */ 13088c2ecf20Sopenharmony_cistatic int __sctp_setsockopt_connectx(struct sock *sk, struct sockaddr *kaddrs, 13098c2ecf20Sopenharmony_ci int addrs_size, sctp_assoc_t *assoc_id) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci int err = 0, flags = 0; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n", 13148c2ecf20Sopenharmony_ci __func__, sk, kaddrs, addrs_size); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* make sure the 1st addr's sa_family is accessible later */ 13178c2ecf20Sopenharmony_ci if (unlikely(addrs_size < sizeof(sa_family_t))) 13188c2ecf20Sopenharmony_ci return -EINVAL; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* Allow security module to validate connectx addresses. */ 13218c2ecf20Sopenharmony_ci err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX, 13228c2ecf20Sopenharmony_ci (struct sockaddr *)kaddrs, 13238c2ecf20Sopenharmony_ci addrs_size); 13248c2ecf20Sopenharmony_ci if (err) 13258c2ecf20Sopenharmony_ci return err; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci /* in-kernel sockets don't generally have a file allocated to them 13288c2ecf20Sopenharmony_ci * if all they do is call sock_create_kern(). 13298c2ecf20Sopenharmony_ci */ 13308c2ecf20Sopenharmony_ci if (sk->sk_socket->file) 13318c2ecf20Sopenharmony_ci flags = sk->sk_socket->file->f_flags; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci return __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id); 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci/* 13378c2ecf20Sopenharmony_ci * This is an older interface. It's kept for backward compatibility 13388c2ecf20Sopenharmony_ci * to the option that doesn't provide association id. 13398c2ecf20Sopenharmony_ci */ 13408c2ecf20Sopenharmony_cistatic int sctp_setsockopt_connectx_old(struct sock *sk, 13418c2ecf20Sopenharmony_ci struct sockaddr *kaddrs, 13428c2ecf20Sopenharmony_ci int addrs_size) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci return __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, NULL); 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci/* 13488c2ecf20Sopenharmony_ci * New interface for the API. The since the API is done with a socket 13498c2ecf20Sopenharmony_ci * option, to make it simple we feed back the association id is as a return 13508c2ecf20Sopenharmony_ci * indication to the call. Error is always negative and association id is 13518c2ecf20Sopenharmony_ci * always positive. 13528c2ecf20Sopenharmony_ci */ 13538c2ecf20Sopenharmony_cistatic int sctp_setsockopt_connectx(struct sock *sk, 13548c2ecf20Sopenharmony_ci struct sockaddr *kaddrs, 13558c2ecf20Sopenharmony_ci int addrs_size) 13568c2ecf20Sopenharmony_ci{ 13578c2ecf20Sopenharmony_ci sctp_assoc_t assoc_id = 0; 13588c2ecf20Sopenharmony_ci int err = 0; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci err = __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, &assoc_id); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (err) 13638c2ecf20Sopenharmony_ci return err; 13648c2ecf20Sopenharmony_ci else 13658c2ecf20Sopenharmony_ci return assoc_id; 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci/* 13698c2ecf20Sopenharmony_ci * New (hopefully final) interface for the API. 13708c2ecf20Sopenharmony_ci * We use the sctp_getaddrs_old structure so that use-space library 13718c2ecf20Sopenharmony_ci * can avoid any unnecessary allocations. The only different part 13728c2ecf20Sopenharmony_ci * is that we store the actual length of the address buffer into the 13738c2ecf20Sopenharmony_ci * addrs_num structure member. That way we can re-use the existing 13748c2ecf20Sopenharmony_ci * code. 13758c2ecf20Sopenharmony_ci */ 13768c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 13778c2ecf20Sopenharmony_cistruct compat_sctp_getaddrs_old { 13788c2ecf20Sopenharmony_ci sctp_assoc_t assoc_id; 13798c2ecf20Sopenharmony_ci s32 addr_num; 13808c2ecf20Sopenharmony_ci compat_uptr_t addrs; /* struct sockaddr * */ 13818c2ecf20Sopenharmony_ci}; 13828c2ecf20Sopenharmony_ci#endif 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic int sctp_getsockopt_connectx3(struct sock *sk, int len, 13858c2ecf20Sopenharmony_ci char __user *optval, 13868c2ecf20Sopenharmony_ci int __user *optlen) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci struct sctp_getaddrs_old param; 13898c2ecf20Sopenharmony_ci sctp_assoc_t assoc_id = 0; 13908c2ecf20Sopenharmony_ci struct sockaddr *kaddrs; 13918c2ecf20Sopenharmony_ci int err = 0; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 13948c2ecf20Sopenharmony_ci if (in_compat_syscall()) { 13958c2ecf20Sopenharmony_ci struct compat_sctp_getaddrs_old param32; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (len < sizeof(param32)) 13988c2ecf20Sopenharmony_ci return -EINVAL; 13998c2ecf20Sopenharmony_ci if (copy_from_user(¶m32, optval, sizeof(param32))) 14008c2ecf20Sopenharmony_ci return -EFAULT; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci param.assoc_id = param32.assoc_id; 14038c2ecf20Sopenharmony_ci param.addr_num = param32.addr_num; 14048c2ecf20Sopenharmony_ci param.addrs = compat_ptr(param32.addrs); 14058c2ecf20Sopenharmony_ci } else 14068c2ecf20Sopenharmony_ci#endif 14078c2ecf20Sopenharmony_ci { 14088c2ecf20Sopenharmony_ci if (len < sizeof(param)) 14098c2ecf20Sopenharmony_ci return -EINVAL; 14108c2ecf20Sopenharmony_ci if (copy_from_user(¶m, optval, sizeof(param))) 14118c2ecf20Sopenharmony_ci return -EFAULT; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci kaddrs = memdup_user(param.addrs, param.addr_num); 14158c2ecf20Sopenharmony_ci if (IS_ERR(kaddrs)) 14168c2ecf20Sopenharmony_ci return PTR_ERR(kaddrs); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci err = __sctp_setsockopt_connectx(sk, kaddrs, param.addr_num, &assoc_id); 14198c2ecf20Sopenharmony_ci kfree(kaddrs); 14208c2ecf20Sopenharmony_ci if (err == 0 || err == -EINPROGRESS) { 14218c2ecf20Sopenharmony_ci if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) 14228c2ecf20Sopenharmony_ci return -EFAULT; 14238c2ecf20Sopenharmony_ci if (put_user(sizeof(assoc_id), optlen)) 14248c2ecf20Sopenharmony_ci return -EFAULT; 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci return err; 14288c2ecf20Sopenharmony_ci} 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci/* API 3.1.4 close() - UDP Style Syntax 14318c2ecf20Sopenharmony_ci * Applications use close() to perform graceful shutdown (as described in 14328c2ecf20Sopenharmony_ci * Section 10.1 of [SCTP]) on ALL the associations currently represented 14338c2ecf20Sopenharmony_ci * by a UDP-style socket. 14348c2ecf20Sopenharmony_ci * 14358c2ecf20Sopenharmony_ci * The syntax is 14368c2ecf20Sopenharmony_ci * 14378c2ecf20Sopenharmony_ci * ret = close(int sd); 14388c2ecf20Sopenharmony_ci * 14398c2ecf20Sopenharmony_ci * sd - the socket descriptor of the associations to be closed. 14408c2ecf20Sopenharmony_ci * 14418c2ecf20Sopenharmony_ci * To gracefully shutdown a specific association represented by the 14428c2ecf20Sopenharmony_ci * UDP-style socket, an application should use the sendmsg() call, 14438c2ecf20Sopenharmony_ci * passing no user data, but including the appropriate flag in the 14448c2ecf20Sopenharmony_ci * ancillary data (see Section xxxx). 14458c2ecf20Sopenharmony_ci * 14468c2ecf20Sopenharmony_ci * If sd in the close() call is a branched-off socket representing only 14478c2ecf20Sopenharmony_ci * one association, the shutdown is performed on that association only. 14488c2ecf20Sopenharmony_ci * 14498c2ecf20Sopenharmony_ci * 4.1.6 close() - TCP Style Syntax 14508c2ecf20Sopenharmony_ci * 14518c2ecf20Sopenharmony_ci * Applications use close() to gracefully close down an association. 14528c2ecf20Sopenharmony_ci * 14538c2ecf20Sopenharmony_ci * The syntax is: 14548c2ecf20Sopenharmony_ci * 14558c2ecf20Sopenharmony_ci * int close(int sd); 14568c2ecf20Sopenharmony_ci * 14578c2ecf20Sopenharmony_ci * sd - the socket descriptor of the association to be closed. 14588c2ecf20Sopenharmony_ci * 14598c2ecf20Sopenharmony_ci * After an application calls close() on a socket descriptor, no further 14608c2ecf20Sopenharmony_ci * socket operations will succeed on that descriptor. 14618c2ecf20Sopenharmony_ci * 14628c2ecf20Sopenharmony_ci * API 7.1.4 SO_LINGER 14638c2ecf20Sopenharmony_ci * 14648c2ecf20Sopenharmony_ci * An application using the TCP-style socket can use this option to 14658c2ecf20Sopenharmony_ci * perform the SCTP ABORT primitive. The linger option structure is: 14668c2ecf20Sopenharmony_ci * 14678c2ecf20Sopenharmony_ci * struct linger { 14688c2ecf20Sopenharmony_ci * int l_onoff; // option on/off 14698c2ecf20Sopenharmony_ci * int l_linger; // linger time 14708c2ecf20Sopenharmony_ci * }; 14718c2ecf20Sopenharmony_ci * 14728c2ecf20Sopenharmony_ci * To enable the option, set l_onoff to 1. If the l_linger value is set 14738c2ecf20Sopenharmony_ci * to 0, calling close() is the same as the ABORT primitive. If the 14748c2ecf20Sopenharmony_ci * value is set to a negative value, the setsockopt() call will return 14758c2ecf20Sopenharmony_ci * an error. If the value is set to a positive value linger_time, the 14768c2ecf20Sopenharmony_ci * close() can be blocked for at most linger_time ms. If the graceful 14778c2ecf20Sopenharmony_ci * shutdown phase does not finish during this period, close() will 14788c2ecf20Sopenharmony_ci * return but the graceful shutdown phase continues in the system. 14798c2ecf20Sopenharmony_ci */ 14808c2ecf20Sopenharmony_cistatic void sctp_close(struct sock *sk, long timeout) 14818c2ecf20Sopenharmony_ci{ 14828c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 14838c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 14848c2ecf20Sopenharmony_ci struct sctp_association *asoc; 14858c2ecf20Sopenharmony_ci struct list_head *pos, *temp; 14868c2ecf20Sopenharmony_ci unsigned int data_was_unread; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci lock_sock_nested(sk, SINGLE_DEPTH_NESTING); 14918c2ecf20Sopenharmony_ci sk->sk_shutdown = SHUTDOWN_MASK; 14928c2ecf20Sopenharmony_ci inet_sk_set_state(sk, SCTP_SS_CLOSING); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci ep = sctp_sk(sk)->ep; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci /* Clean up any skbs sitting on the receive queue. */ 14978c2ecf20Sopenharmony_ci data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue); 14988c2ecf20Sopenharmony_ci data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci /* Walk all associations on an endpoint. */ 15018c2ecf20Sopenharmony_ci list_for_each_safe(pos, temp, &ep->asocs) { 15028c2ecf20Sopenharmony_ci asoc = list_entry(pos, struct sctp_association, asocs); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) { 15058c2ecf20Sopenharmony_ci /* A closed association can still be in the list if 15068c2ecf20Sopenharmony_ci * it belongs to a TCP-style listening socket that is 15078c2ecf20Sopenharmony_ci * not yet accepted. If so, free it. If not, send an 15088c2ecf20Sopenharmony_ci * ABORT or SHUTDOWN based on the linger options. 15098c2ecf20Sopenharmony_ci */ 15108c2ecf20Sopenharmony_ci if (sctp_state(asoc, CLOSED)) { 15118c2ecf20Sopenharmony_ci sctp_association_free(asoc); 15128c2ecf20Sopenharmony_ci continue; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) || 15178c2ecf20Sopenharmony_ci !skb_queue_empty(&asoc->ulpq.reasm) || 15188c2ecf20Sopenharmony_ci !skb_queue_empty(&asoc->ulpq.reasm_uo) || 15198c2ecf20Sopenharmony_ci (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { 15208c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci chunk = sctp_make_abort_user(asoc, NULL, 0); 15238c2ecf20Sopenharmony_ci sctp_primitive_ABORT(net, asoc, chunk); 15248c2ecf20Sopenharmony_ci } else 15258c2ecf20Sopenharmony_ci sctp_primitive_SHUTDOWN(net, asoc, NULL); 15268c2ecf20Sopenharmony_ci } 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /* On a TCP-style socket, block for at most linger_time if set. */ 15298c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP) && timeout) 15308c2ecf20Sopenharmony_ci sctp_wait_for_close(sk, timeout); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci /* This will run the backlog queue. */ 15338c2ecf20Sopenharmony_ci release_sock(sk); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci /* Supposedly, no process has access to the socket, but 15368c2ecf20Sopenharmony_ci * the net layers still may. 15378c2ecf20Sopenharmony_ci * Also, sctp_destroy_sock() needs to be called with addr_wq_lock 15388c2ecf20Sopenharmony_ci * held and that should be grabbed before socket lock. 15398c2ecf20Sopenharmony_ci */ 15408c2ecf20Sopenharmony_ci spin_lock_bh(&net->sctp.addr_wq_lock); 15418c2ecf20Sopenharmony_ci bh_lock_sock_nested(sk); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci /* Hold the sock, since sk_common_release() will put sock_put() 15448c2ecf20Sopenharmony_ci * and we have just a little more cleanup. 15458c2ecf20Sopenharmony_ci */ 15468c2ecf20Sopenharmony_ci sock_hold(sk); 15478c2ecf20Sopenharmony_ci sk_common_release(sk); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci bh_unlock_sock(sk); 15508c2ecf20Sopenharmony_ci spin_unlock_bh(&net->sctp.addr_wq_lock); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci sock_put(sk); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_DEC(sock); 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci/* Handle EPIPE error. */ 15588c2ecf20Sopenharmony_cistatic int sctp_error(struct sock *sk, int flags, int err) 15598c2ecf20Sopenharmony_ci{ 15608c2ecf20Sopenharmony_ci if (err == -EPIPE) 15618c2ecf20Sopenharmony_ci err = sock_error(sk) ? : -EPIPE; 15628c2ecf20Sopenharmony_ci if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) 15638c2ecf20Sopenharmony_ci send_sig(SIGPIPE, current, 0); 15648c2ecf20Sopenharmony_ci return err; 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci/* API 3.1.3 sendmsg() - UDP Style Syntax 15688c2ecf20Sopenharmony_ci * 15698c2ecf20Sopenharmony_ci * An application uses sendmsg() and recvmsg() calls to transmit data to 15708c2ecf20Sopenharmony_ci * and receive data from its peer. 15718c2ecf20Sopenharmony_ci * 15728c2ecf20Sopenharmony_ci * ssize_t sendmsg(int socket, const struct msghdr *message, 15738c2ecf20Sopenharmony_ci * int flags); 15748c2ecf20Sopenharmony_ci * 15758c2ecf20Sopenharmony_ci * socket - the socket descriptor of the endpoint. 15768c2ecf20Sopenharmony_ci * message - pointer to the msghdr structure which contains a single 15778c2ecf20Sopenharmony_ci * user message and possibly some ancillary data. 15788c2ecf20Sopenharmony_ci * 15798c2ecf20Sopenharmony_ci * See Section 5 for complete description of the data 15808c2ecf20Sopenharmony_ci * structures. 15818c2ecf20Sopenharmony_ci * 15828c2ecf20Sopenharmony_ci * flags - flags sent or received with the user message, see Section 15838c2ecf20Sopenharmony_ci * 5 for complete description of the flags. 15848c2ecf20Sopenharmony_ci * 15858c2ecf20Sopenharmony_ci * Note: This function could use a rewrite especially when explicit 15868c2ecf20Sopenharmony_ci * connect support comes in. 15878c2ecf20Sopenharmony_ci */ 15888c2ecf20Sopenharmony_ci/* BUG: We do not implement the equivalent of sk_stream_wait_memory(). */ 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_cistatic int sctp_msghdr_parse(const struct msghdr *msg, 15918c2ecf20Sopenharmony_ci struct sctp_cmsgs *cmsgs); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_cistatic int sctp_sendmsg_parse(struct sock *sk, struct sctp_cmsgs *cmsgs, 15948c2ecf20Sopenharmony_ci struct sctp_sndrcvinfo *srinfo, 15958c2ecf20Sopenharmony_ci const struct msghdr *msg, size_t msg_len) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci __u16 sflags; 15988c2ecf20Sopenharmony_ci int err; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (sctp_sstate(sk, LISTENING) && sctp_style(sk, TCP)) 16018c2ecf20Sopenharmony_ci return -EPIPE; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (msg_len > sk->sk_sndbuf) 16048c2ecf20Sopenharmony_ci return -EMSGSIZE; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci memset(cmsgs, 0, sizeof(*cmsgs)); 16078c2ecf20Sopenharmony_ci err = sctp_msghdr_parse(msg, cmsgs); 16088c2ecf20Sopenharmony_ci if (err) { 16098c2ecf20Sopenharmony_ci pr_debug("%s: msghdr parse err:%x\n", __func__, err); 16108c2ecf20Sopenharmony_ci return err; 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci memset(srinfo, 0, sizeof(*srinfo)); 16148c2ecf20Sopenharmony_ci if (cmsgs->srinfo) { 16158c2ecf20Sopenharmony_ci srinfo->sinfo_stream = cmsgs->srinfo->sinfo_stream; 16168c2ecf20Sopenharmony_ci srinfo->sinfo_flags = cmsgs->srinfo->sinfo_flags; 16178c2ecf20Sopenharmony_ci srinfo->sinfo_ppid = cmsgs->srinfo->sinfo_ppid; 16188c2ecf20Sopenharmony_ci srinfo->sinfo_context = cmsgs->srinfo->sinfo_context; 16198c2ecf20Sopenharmony_ci srinfo->sinfo_assoc_id = cmsgs->srinfo->sinfo_assoc_id; 16208c2ecf20Sopenharmony_ci srinfo->sinfo_timetolive = cmsgs->srinfo->sinfo_timetolive; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (cmsgs->sinfo) { 16248c2ecf20Sopenharmony_ci srinfo->sinfo_stream = cmsgs->sinfo->snd_sid; 16258c2ecf20Sopenharmony_ci srinfo->sinfo_flags = cmsgs->sinfo->snd_flags; 16268c2ecf20Sopenharmony_ci srinfo->sinfo_ppid = cmsgs->sinfo->snd_ppid; 16278c2ecf20Sopenharmony_ci srinfo->sinfo_context = cmsgs->sinfo->snd_context; 16288c2ecf20Sopenharmony_ci srinfo->sinfo_assoc_id = cmsgs->sinfo->snd_assoc_id; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (cmsgs->prinfo) { 16328c2ecf20Sopenharmony_ci srinfo->sinfo_timetolive = cmsgs->prinfo->pr_value; 16338c2ecf20Sopenharmony_ci SCTP_PR_SET_POLICY(srinfo->sinfo_flags, 16348c2ecf20Sopenharmony_ci cmsgs->prinfo->pr_policy); 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci sflags = srinfo->sinfo_flags; 16388c2ecf20Sopenharmony_ci if (!sflags && msg_len) 16398c2ecf20Sopenharmony_ci return 0; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP) && (sflags & (SCTP_EOF | SCTP_ABORT))) 16428c2ecf20Sopenharmony_ci return -EINVAL; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (((sflags & SCTP_EOF) && msg_len > 0) || 16458c2ecf20Sopenharmony_ci (!(sflags & (SCTP_EOF | SCTP_ABORT)) && msg_len == 0)) 16468c2ecf20Sopenharmony_ci return -EINVAL; 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci if ((sflags & SCTP_ADDR_OVER) && !msg->msg_name) 16498c2ecf20Sopenharmony_ci return -EINVAL; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci return 0; 16528c2ecf20Sopenharmony_ci} 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_cistatic int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags, 16558c2ecf20Sopenharmony_ci struct sctp_cmsgs *cmsgs, 16568c2ecf20Sopenharmony_ci union sctp_addr *daddr, 16578c2ecf20Sopenharmony_ci struct sctp_transport **tp) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 16608c2ecf20Sopenharmony_ci struct sctp_association *asoc; 16618c2ecf20Sopenharmony_ci struct cmsghdr *cmsg; 16628c2ecf20Sopenharmony_ci __be32 flowinfo = 0; 16638c2ecf20Sopenharmony_ci struct sctp_af *af; 16648c2ecf20Sopenharmony_ci int err; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci *tp = NULL; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (sflags & (SCTP_EOF | SCTP_ABORT)) 16698c2ecf20Sopenharmony_ci return -EINVAL; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP) && (sctp_sstate(sk, ESTABLISHED) || 16728c2ecf20Sopenharmony_ci sctp_sstate(sk, CLOSING))) 16738c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci /* Label connection socket for first association 1-to-many 16768c2ecf20Sopenharmony_ci * style for client sequence socket()->sendmsg(). This 16778c2ecf20Sopenharmony_ci * needs to be done before sctp_assoc_add_peer() as that will 16788c2ecf20Sopenharmony_ci * set up the initial packet that needs to account for any 16798c2ecf20Sopenharmony_ci * security ip options (CIPSO/CALIPSO) added to the packet. 16808c2ecf20Sopenharmony_ci */ 16818c2ecf20Sopenharmony_ci af = sctp_get_af_specific(daddr->sa.sa_family); 16828c2ecf20Sopenharmony_ci if (!af) 16838c2ecf20Sopenharmony_ci return -EINVAL; 16848c2ecf20Sopenharmony_ci err = security_sctp_bind_connect(sk, SCTP_SENDMSG_CONNECT, 16858c2ecf20Sopenharmony_ci (struct sockaddr *)daddr, 16868c2ecf20Sopenharmony_ci af->sockaddr_len); 16878c2ecf20Sopenharmony_ci if (err < 0) 16888c2ecf20Sopenharmony_ci return err; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci err = sctp_connect_new_asoc(ep, daddr, cmsgs->init, tp); 16918c2ecf20Sopenharmony_ci if (err) 16928c2ecf20Sopenharmony_ci return err; 16938c2ecf20Sopenharmony_ci asoc = (*tp)->asoc; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci if (!cmsgs->addrs_msg) 16968c2ecf20Sopenharmony_ci return 0; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci if (daddr->sa.sa_family == AF_INET6) 16998c2ecf20Sopenharmony_ci flowinfo = daddr->v6.sin6_flowinfo; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci /* sendv addr list parse */ 17028c2ecf20Sopenharmony_ci for_each_cmsghdr(cmsg, cmsgs->addrs_msg) { 17038c2ecf20Sopenharmony_ci union sctp_addr _daddr; 17048c2ecf20Sopenharmony_ci int dlen; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci if (cmsg->cmsg_level != IPPROTO_SCTP || 17078c2ecf20Sopenharmony_ci (cmsg->cmsg_type != SCTP_DSTADDRV4 && 17088c2ecf20Sopenharmony_ci cmsg->cmsg_type != SCTP_DSTADDRV6)) 17098c2ecf20Sopenharmony_ci continue; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci daddr = &_daddr; 17128c2ecf20Sopenharmony_ci memset(daddr, 0, sizeof(*daddr)); 17138c2ecf20Sopenharmony_ci dlen = cmsg->cmsg_len - sizeof(struct cmsghdr); 17148c2ecf20Sopenharmony_ci if (cmsg->cmsg_type == SCTP_DSTADDRV4) { 17158c2ecf20Sopenharmony_ci if (dlen < sizeof(struct in_addr)) { 17168c2ecf20Sopenharmony_ci err = -EINVAL; 17178c2ecf20Sopenharmony_ci goto free; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci dlen = sizeof(struct in_addr); 17218c2ecf20Sopenharmony_ci daddr->v4.sin_family = AF_INET; 17228c2ecf20Sopenharmony_ci daddr->v4.sin_port = htons(asoc->peer.port); 17238c2ecf20Sopenharmony_ci memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen); 17248c2ecf20Sopenharmony_ci } else { 17258c2ecf20Sopenharmony_ci if (dlen < sizeof(struct in6_addr)) { 17268c2ecf20Sopenharmony_ci err = -EINVAL; 17278c2ecf20Sopenharmony_ci goto free; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci dlen = sizeof(struct in6_addr); 17318c2ecf20Sopenharmony_ci daddr->v6.sin6_flowinfo = flowinfo; 17328c2ecf20Sopenharmony_ci daddr->v6.sin6_family = AF_INET6; 17338c2ecf20Sopenharmony_ci daddr->v6.sin6_port = htons(asoc->peer.port); 17348c2ecf20Sopenharmony_ci memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen); 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci err = sctp_connect_add_peer(asoc, daddr, sizeof(*daddr)); 17388c2ecf20Sopenharmony_ci if (err) 17398c2ecf20Sopenharmony_ci goto free; 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci return 0; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cifree: 17458c2ecf20Sopenharmony_ci sctp_association_free(asoc); 17468c2ecf20Sopenharmony_ci return err; 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cistatic int sctp_sendmsg_check_sflags(struct sctp_association *asoc, 17508c2ecf20Sopenharmony_ci __u16 sflags, struct msghdr *msg, 17518c2ecf20Sopenharmony_ci size_t msg_len) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 17548c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) 17578c2ecf20Sopenharmony_ci return -EPIPE; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP) && 17608c2ecf20Sopenharmony_ci !sctp_state(asoc, ESTABLISHED)) 17618c2ecf20Sopenharmony_ci return 0; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci if (sflags & SCTP_EOF) { 17648c2ecf20Sopenharmony_ci pr_debug("%s: shutting down association:%p\n", __func__, asoc); 17658c2ecf20Sopenharmony_ci sctp_primitive_SHUTDOWN(net, asoc, NULL); 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci return 0; 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci if (sflags & SCTP_ABORT) { 17718c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci chunk = sctp_make_abort_user(asoc, msg, msg_len); 17748c2ecf20Sopenharmony_ci if (!chunk) 17758c2ecf20Sopenharmony_ci return -ENOMEM; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci pr_debug("%s: aborting association:%p\n", __func__, asoc); 17788c2ecf20Sopenharmony_ci sctp_primitive_ABORT(net, asoc, chunk); 17798c2ecf20Sopenharmony_ci iov_iter_revert(&msg->msg_iter, msg_len); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci return 0; 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci return 1; 17858c2ecf20Sopenharmony_ci} 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_cistatic int sctp_sendmsg_to_asoc(struct sctp_association *asoc, 17888c2ecf20Sopenharmony_ci struct msghdr *msg, size_t msg_len, 17898c2ecf20Sopenharmony_ci struct sctp_transport *transport, 17908c2ecf20Sopenharmony_ci struct sctp_sndrcvinfo *sinfo) 17918c2ecf20Sopenharmony_ci{ 17928c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 17938c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 17948c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 17958c2ecf20Sopenharmony_ci struct sctp_datamsg *datamsg; 17968c2ecf20Sopenharmony_ci bool wait_connect = false; 17978c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 17988c2ecf20Sopenharmony_ci long timeo; 17998c2ecf20Sopenharmony_ci int err; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (sinfo->sinfo_stream >= asoc->stream.outcnt) { 18028c2ecf20Sopenharmony_ci err = -EINVAL; 18038c2ecf20Sopenharmony_ci goto err; 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci if (unlikely(!SCTP_SO(&asoc->stream, sinfo->sinfo_stream)->ext)) { 18078c2ecf20Sopenharmony_ci err = sctp_stream_init_ext(&asoc->stream, sinfo->sinfo_stream); 18088c2ecf20Sopenharmony_ci if (err) 18098c2ecf20Sopenharmony_ci goto err; 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci if (sp->disable_fragments && msg_len > asoc->frag_point) { 18138c2ecf20Sopenharmony_ci err = -EMSGSIZE; 18148c2ecf20Sopenharmony_ci goto err; 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci if (asoc->pmtu_pending) { 18188c2ecf20Sopenharmony_ci if (sp->param_flags & SPP_PMTUD_ENABLE) 18198c2ecf20Sopenharmony_ci sctp_assoc_sync_pmtu(asoc); 18208c2ecf20Sopenharmony_ci asoc->pmtu_pending = 0; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci if (sctp_wspace(asoc) < (int)msg_len) 18248c2ecf20Sopenharmony_ci sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc)); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (sk_under_memory_pressure(sk)) 18278c2ecf20Sopenharmony_ci sk_mem_reclaim(sk); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci if (sctp_wspace(asoc) <= 0 || !sk_wmem_schedule(sk, msg_len)) { 18308c2ecf20Sopenharmony_ci timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 18318c2ecf20Sopenharmony_ci err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); 18328c2ecf20Sopenharmony_ci if (err) 18338c2ecf20Sopenharmony_ci goto err; 18348c2ecf20Sopenharmony_ci if (unlikely(sinfo->sinfo_stream >= asoc->stream.outcnt)) { 18358c2ecf20Sopenharmony_ci err = -EINVAL; 18368c2ecf20Sopenharmony_ci goto err; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci } 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (sctp_state(asoc, CLOSED)) { 18418c2ecf20Sopenharmony_ci err = sctp_primitive_ASSOCIATE(net, asoc, NULL); 18428c2ecf20Sopenharmony_ci if (err) 18438c2ecf20Sopenharmony_ci goto err; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (asoc->ep->intl_enable) { 18468c2ecf20Sopenharmony_ci timeo = sock_sndtimeo(sk, 0); 18478c2ecf20Sopenharmony_ci err = sctp_wait_for_connect(asoc, &timeo); 18488c2ecf20Sopenharmony_ci if (err) { 18498c2ecf20Sopenharmony_ci err = -ESRCH; 18508c2ecf20Sopenharmony_ci goto err; 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci } else { 18538c2ecf20Sopenharmony_ci wait_connect = true; 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci pr_debug("%s: we associated primitively\n", __func__); 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci datamsg = sctp_datamsg_from_user(asoc, sinfo, &msg->msg_iter); 18608c2ecf20Sopenharmony_ci if (IS_ERR(datamsg)) { 18618c2ecf20Sopenharmony_ci err = PTR_ERR(datamsg); 18628c2ecf20Sopenharmony_ci goto err; 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci asoc->force_delay = !!(msg->msg_flags & MSG_MORE); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci list_for_each_entry(chunk, &datamsg->chunks, frag_list) { 18688c2ecf20Sopenharmony_ci sctp_chunk_hold(chunk); 18698c2ecf20Sopenharmony_ci sctp_set_owner_w(chunk); 18708c2ecf20Sopenharmony_ci chunk->transport = transport; 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci err = sctp_primitive_SEND(net, asoc, datamsg); 18748c2ecf20Sopenharmony_ci if (err) { 18758c2ecf20Sopenharmony_ci sctp_datamsg_free(datamsg); 18768c2ecf20Sopenharmony_ci goto err; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci pr_debug("%s: we sent primitively\n", __func__); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci sctp_datamsg_put(datamsg); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci if (unlikely(wait_connect)) { 18848c2ecf20Sopenharmony_ci timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 18858c2ecf20Sopenharmony_ci sctp_wait_for_connect(asoc, &timeo); 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci err = msg_len; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_cierr: 18918c2ecf20Sopenharmony_ci return err; 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_cistatic union sctp_addr *sctp_sendmsg_get_daddr(struct sock *sk, 18958c2ecf20Sopenharmony_ci const struct msghdr *msg, 18968c2ecf20Sopenharmony_ci struct sctp_cmsgs *cmsgs) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci union sctp_addr *daddr = NULL; 18998c2ecf20Sopenharmony_ci int err; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) { 19028c2ecf20Sopenharmony_ci int len = msg->msg_namelen; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (len > sizeof(*daddr)) 19058c2ecf20Sopenharmony_ci len = sizeof(*daddr); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci daddr = (union sctp_addr *)msg->msg_name; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci err = sctp_verify_addr(sk, daddr, len); 19108c2ecf20Sopenharmony_ci if (err) 19118c2ecf20Sopenharmony_ci return ERR_PTR(err); 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci return daddr; 19158c2ecf20Sopenharmony_ci} 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_cistatic void sctp_sendmsg_update_sinfo(struct sctp_association *asoc, 19188c2ecf20Sopenharmony_ci struct sctp_sndrcvinfo *sinfo, 19198c2ecf20Sopenharmony_ci struct sctp_cmsgs *cmsgs) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci if (!cmsgs->srinfo && !cmsgs->sinfo) { 19228c2ecf20Sopenharmony_ci sinfo->sinfo_stream = asoc->default_stream; 19238c2ecf20Sopenharmony_ci sinfo->sinfo_ppid = asoc->default_ppid; 19248c2ecf20Sopenharmony_ci sinfo->sinfo_context = asoc->default_context; 19258c2ecf20Sopenharmony_ci sinfo->sinfo_assoc_id = sctp_assoc2id(asoc); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci if (!cmsgs->prinfo) 19288c2ecf20Sopenharmony_ci sinfo->sinfo_flags = asoc->default_flags; 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci if (!cmsgs->srinfo && !cmsgs->prinfo) 19328c2ecf20Sopenharmony_ci sinfo->sinfo_timetolive = asoc->default_timetolive; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci if (cmsgs->authinfo) { 19358c2ecf20Sopenharmony_ci /* Reuse sinfo_tsn to indicate that authinfo was set and 19368c2ecf20Sopenharmony_ci * sinfo_ssn to save the keyid on tx path. 19378c2ecf20Sopenharmony_ci */ 19388c2ecf20Sopenharmony_ci sinfo->sinfo_tsn = 1; 19398c2ecf20Sopenharmony_ci sinfo->sinfo_ssn = cmsgs->authinfo->auth_keynumber; 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci} 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_cistatic int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) 19448c2ecf20Sopenharmony_ci{ 19458c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 19468c2ecf20Sopenharmony_ci struct sctp_transport *transport = NULL; 19478c2ecf20Sopenharmony_ci struct sctp_sndrcvinfo _sinfo, *sinfo; 19488c2ecf20Sopenharmony_ci struct sctp_association *asoc, *tmp; 19498c2ecf20Sopenharmony_ci struct sctp_cmsgs cmsgs; 19508c2ecf20Sopenharmony_ci union sctp_addr *daddr; 19518c2ecf20Sopenharmony_ci bool new = false; 19528c2ecf20Sopenharmony_ci __u16 sflags; 19538c2ecf20Sopenharmony_ci int err; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci /* Parse and get snd_info */ 19568c2ecf20Sopenharmony_ci err = sctp_sendmsg_parse(sk, &cmsgs, &_sinfo, msg, msg_len); 19578c2ecf20Sopenharmony_ci if (err) 19588c2ecf20Sopenharmony_ci goto out; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci sinfo = &_sinfo; 19618c2ecf20Sopenharmony_ci sflags = sinfo->sinfo_flags; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci /* Get daddr from msg */ 19648c2ecf20Sopenharmony_ci daddr = sctp_sendmsg_get_daddr(sk, msg, &cmsgs); 19658c2ecf20Sopenharmony_ci if (IS_ERR(daddr)) { 19668c2ecf20Sopenharmony_ci err = PTR_ERR(daddr); 19678c2ecf20Sopenharmony_ci goto out; 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci lock_sock(sk); 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci /* SCTP_SENDALL process */ 19738c2ecf20Sopenharmony_ci if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) { 19748c2ecf20Sopenharmony_ci list_for_each_entry_safe(asoc, tmp, &ep->asocs, asocs) { 19758c2ecf20Sopenharmony_ci err = sctp_sendmsg_check_sflags(asoc, sflags, msg, 19768c2ecf20Sopenharmony_ci msg_len); 19778c2ecf20Sopenharmony_ci if (err == 0) 19788c2ecf20Sopenharmony_ci continue; 19798c2ecf20Sopenharmony_ci if (err < 0) 19808c2ecf20Sopenharmony_ci goto out_unlock; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci err = sctp_sendmsg_to_asoc(asoc, msg, msg_len, 19858c2ecf20Sopenharmony_ci NULL, sinfo); 19868c2ecf20Sopenharmony_ci if (err < 0) 19878c2ecf20Sopenharmony_ci goto out_unlock; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci iov_iter_revert(&msg->msg_iter, err); 19908c2ecf20Sopenharmony_ci } 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci goto out_unlock; 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci /* Get and check or create asoc */ 19968c2ecf20Sopenharmony_ci if (daddr) { 19978c2ecf20Sopenharmony_ci asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport); 19988c2ecf20Sopenharmony_ci if (asoc) { 19998c2ecf20Sopenharmony_ci err = sctp_sendmsg_check_sflags(asoc, sflags, msg, 20008c2ecf20Sopenharmony_ci msg_len); 20018c2ecf20Sopenharmony_ci if (err <= 0) 20028c2ecf20Sopenharmony_ci goto out_unlock; 20038c2ecf20Sopenharmony_ci } else { 20048c2ecf20Sopenharmony_ci err = sctp_sendmsg_new_asoc(sk, sflags, &cmsgs, daddr, 20058c2ecf20Sopenharmony_ci &transport); 20068c2ecf20Sopenharmony_ci if (err) 20078c2ecf20Sopenharmony_ci goto out_unlock; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci asoc = transport->asoc; 20108c2ecf20Sopenharmony_ci new = true; 20118c2ecf20Sopenharmony_ci } 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci if (!sctp_style(sk, TCP) && !(sflags & SCTP_ADDR_OVER)) 20148c2ecf20Sopenharmony_ci transport = NULL; 20158c2ecf20Sopenharmony_ci } else { 20168c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, sinfo->sinfo_assoc_id); 20178c2ecf20Sopenharmony_ci if (!asoc) { 20188c2ecf20Sopenharmony_ci err = -EPIPE; 20198c2ecf20Sopenharmony_ci goto out_unlock; 20208c2ecf20Sopenharmony_ci } 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci err = sctp_sendmsg_check_sflags(asoc, sflags, msg, msg_len); 20238c2ecf20Sopenharmony_ci if (err <= 0) 20248c2ecf20Sopenharmony_ci goto out_unlock; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci /* Update snd_info with the asoc */ 20288c2ecf20Sopenharmony_ci sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci /* Send msg to the asoc */ 20318c2ecf20Sopenharmony_ci err = sctp_sendmsg_to_asoc(asoc, msg, msg_len, transport, sinfo); 20328c2ecf20Sopenharmony_ci if (err < 0 && err != -ESRCH && new) 20338c2ecf20Sopenharmony_ci sctp_association_free(asoc); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ciout_unlock: 20368c2ecf20Sopenharmony_ci release_sock(sk); 20378c2ecf20Sopenharmony_ciout: 20388c2ecf20Sopenharmony_ci return sctp_error(sk, msg->msg_flags, err); 20398c2ecf20Sopenharmony_ci} 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci/* This is an extended version of skb_pull() that removes the data from the 20428c2ecf20Sopenharmony_ci * start of a skb even when data is spread across the list of skb's in the 20438c2ecf20Sopenharmony_ci * frag_list. len specifies the total amount of data that needs to be removed. 20448c2ecf20Sopenharmony_ci * when 'len' bytes could be removed from the skb, it returns 0. 20458c2ecf20Sopenharmony_ci * If 'len' exceeds the total skb length, it returns the no. of bytes that 20468c2ecf20Sopenharmony_ci * could not be removed. 20478c2ecf20Sopenharmony_ci */ 20488c2ecf20Sopenharmony_cistatic int sctp_skb_pull(struct sk_buff *skb, int len) 20498c2ecf20Sopenharmony_ci{ 20508c2ecf20Sopenharmony_ci struct sk_buff *list; 20518c2ecf20Sopenharmony_ci int skb_len = skb_headlen(skb); 20528c2ecf20Sopenharmony_ci int rlen; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci if (len <= skb_len) { 20558c2ecf20Sopenharmony_ci __skb_pull(skb, len); 20568c2ecf20Sopenharmony_ci return 0; 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci len -= skb_len; 20598c2ecf20Sopenharmony_ci __skb_pull(skb, skb_len); 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci skb_walk_frags(skb, list) { 20628c2ecf20Sopenharmony_ci rlen = sctp_skb_pull(list, len); 20638c2ecf20Sopenharmony_ci skb->len -= (len-rlen); 20648c2ecf20Sopenharmony_ci skb->data_len -= (len-rlen); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci if (!rlen) 20678c2ecf20Sopenharmony_ci return 0; 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci len = rlen; 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci return len; 20738c2ecf20Sopenharmony_ci} 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci/* API 3.1.3 recvmsg() - UDP Style Syntax 20768c2ecf20Sopenharmony_ci * 20778c2ecf20Sopenharmony_ci * ssize_t recvmsg(int socket, struct msghdr *message, 20788c2ecf20Sopenharmony_ci * int flags); 20798c2ecf20Sopenharmony_ci * 20808c2ecf20Sopenharmony_ci * socket - the socket descriptor of the endpoint. 20818c2ecf20Sopenharmony_ci * message - pointer to the msghdr structure which contains a single 20828c2ecf20Sopenharmony_ci * user message and possibly some ancillary data. 20838c2ecf20Sopenharmony_ci * 20848c2ecf20Sopenharmony_ci * See Section 5 for complete description of the data 20858c2ecf20Sopenharmony_ci * structures. 20868c2ecf20Sopenharmony_ci * 20878c2ecf20Sopenharmony_ci * flags - flags sent or received with the user message, see Section 20888c2ecf20Sopenharmony_ci * 5 for complete description of the flags. 20898c2ecf20Sopenharmony_ci */ 20908c2ecf20Sopenharmony_cistatic int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 20918c2ecf20Sopenharmony_ci int noblock, int flags, int *addr_len) 20928c2ecf20Sopenharmony_ci{ 20938c2ecf20Sopenharmony_ci struct sctp_ulpevent *event = NULL; 20948c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 20958c2ecf20Sopenharmony_ci struct sk_buff *skb, *head_skb; 20968c2ecf20Sopenharmony_ci int copied; 20978c2ecf20Sopenharmony_ci int err = 0; 20988c2ecf20Sopenharmony_ci int skb_len; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, msghdr:%p, len:%zd, noblock:%d, flags:0x%x, " 21018c2ecf20Sopenharmony_ci "addr_len:%p)\n", __func__, sk, msg, len, noblock, flags, 21028c2ecf20Sopenharmony_ci addr_len); 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci lock_sock(sk); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED) && 21078c2ecf20Sopenharmony_ci !sctp_sstate(sk, CLOSING) && !sctp_sstate(sk, CLOSED)) { 21088c2ecf20Sopenharmony_ci err = -ENOTCONN; 21098c2ecf20Sopenharmony_ci goto out; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); 21138c2ecf20Sopenharmony_ci if (!skb) 21148c2ecf20Sopenharmony_ci goto out; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci /* Get the total length of the skb including any skb's in the 21178c2ecf20Sopenharmony_ci * frag_list. 21188c2ecf20Sopenharmony_ci */ 21198c2ecf20Sopenharmony_ci skb_len = skb->len; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci copied = skb_len; 21228c2ecf20Sopenharmony_ci if (copied > len) 21238c2ecf20Sopenharmony_ci copied = len; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci err = skb_copy_datagram_msg(skb, 0, msg, copied); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci if (err) 21308c2ecf20Sopenharmony_ci goto out_free; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci if (event->chunk && event->chunk->head_skb) 21338c2ecf20Sopenharmony_ci head_skb = event->chunk->head_skb; 21348c2ecf20Sopenharmony_ci else 21358c2ecf20Sopenharmony_ci head_skb = skb; 21368c2ecf20Sopenharmony_ci sock_recv_ts_and_drops(msg, sk, head_skb); 21378c2ecf20Sopenharmony_ci if (sctp_ulpevent_is_notification(event)) { 21388c2ecf20Sopenharmony_ci msg->msg_flags |= MSG_NOTIFICATION; 21398c2ecf20Sopenharmony_ci sp->pf->event_msgname(event, msg->msg_name, addr_len); 21408c2ecf20Sopenharmony_ci } else { 21418c2ecf20Sopenharmony_ci sp->pf->skb_msgname(head_skb, msg->msg_name, addr_len); 21428c2ecf20Sopenharmony_ci } 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci /* Check if we allow SCTP_NXTINFO. */ 21458c2ecf20Sopenharmony_ci if (sp->recvnxtinfo) 21468c2ecf20Sopenharmony_ci sctp_ulpevent_read_nxtinfo(event, msg, sk); 21478c2ecf20Sopenharmony_ci /* Check if we allow SCTP_RCVINFO. */ 21488c2ecf20Sopenharmony_ci if (sp->recvrcvinfo) 21498c2ecf20Sopenharmony_ci sctp_ulpevent_read_rcvinfo(event, msg); 21508c2ecf20Sopenharmony_ci /* Check if we allow SCTP_SNDRCVINFO. */ 21518c2ecf20Sopenharmony_ci if (sctp_ulpevent_type_enabled(sp->subscribe, SCTP_DATA_IO_EVENT)) 21528c2ecf20Sopenharmony_ci sctp_ulpevent_read_sndrcvinfo(event, msg); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci err = copied; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci /* If skb's length exceeds the user's buffer, update the skb and 21578c2ecf20Sopenharmony_ci * push it back to the receive_queue so that the next call to 21588c2ecf20Sopenharmony_ci * recvmsg() will return the remaining data. Don't set MSG_EOR. 21598c2ecf20Sopenharmony_ci */ 21608c2ecf20Sopenharmony_ci if (skb_len > copied) { 21618c2ecf20Sopenharmony_ci msg->msg_flags &= ~MSG_EOR; 21628c2ecf20Sopenharmony_ci if (flags & MSG_PEEK) 21638c2ecf20Sopenharmony_ci goto out_free; 21648c2ecf20Sopenharmony_ci sctp_skb_pull(skb, copied); 21658c2ecf20Sopenharmony_ci skb_queue_head(&sk->sk_receive_queue, skb); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci /* When only partial message is copied to the user, increase 21688c2ecf20Sopenharmony_ci * rwnd by that amount. If all the data in the skb is read, 21698c2ecf20Sopenharmony_ci * rwnd is updated when the event is freed. 21708c2ecf20Sopenharmony_ci */ 21718c2ecf20Sopenharmony_ci if (!sctp_ulpevent_is_notification(event)) 21728c2ecf20Sopenharmony_ci sctp_assoc_rwnd_increase(event->asoc, copied); 21738c2ecf20Sopenharmony_ci goto out; 21748c2ecf20Sopenharmony_ci } else if ((event->msg_flags & MSG_NOTIFICATION) || 21758c2ecf20Sopenharmony_ci (event->msg_flags & MSG_EOR)) 21768c2ecf20Sopenharmony_ci msg->msg_flags |= MSG_EOR; 21778c2ecf20Sopenharmony_ci else 21788c2ecf20Sopenharmony_ci msg->msg_flags &= ~MSG_EOR; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ciout_free: 21818c2ecf20Sopenharmony_ci if (flags & MSG_PEEK) { 21828c2ecf20Sopenharmony_ci /* Release the skb reference acquired after peeking the skb in 21838c2ecf20Sopenharmony_ci * sctp_skb_recv_datagram(). 21848c2ecf20Sopenharmony_ci */ 21858c2ecf20Sopenharmony_ci kfree_skb(skb); 21868c2ecf20Sopenharmony_ci } else { 21878c2ecf20Sopenharmony_ci /* Free the event which includes releasing the reference to 21888c2ecf20Sopenharmony_ci * the owner of the skb, freeing the skb and updating the 21898c2ecf20Sopenharmony_ci * rwnd. 21908c2ecf20Sopenharmony_ci */ 21918c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ciout: 21948c2ecf20Sopenharmony_ci release_sock(sk); 21958c2ecf20Sopenharmony_ci return err; 21968c2ecf20Sopenharmony_ci} 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) 21998c2ecf20Sopenharmony_ci * 22008c2ecf20Sopenharmony_ci * This option is a on/off flag. If enabled no SCTP message 22018c2ecf20Sopenharmony_ci * fragmentation will be performed. Instead if a message being sent 22028c2ecf20Sopenharmony_ci * exceeds the current PMTU size, the message will NOT be sent and 22038c2ecf20Sopenharmony_ci * instead a error will be indicated to the user. 22048c2ecf20Sopenharmony_ci */ 22058c2ecf20Sopenharmony_cistatic int sctp_setsockopt_disable_fragments(struct sock *sk, int *val, 22068c2ecf20Sopenharmony_ci unsigned int optlen) 22078c2ecf20Sopenharmony_ci{ 22088c2ecf20Sopenharmony_ci if (optlen < sizeof(int)) 22098c2ecf20Sopenharmony_ci return -EINVAL; 22108c2ecf20Sopenharmony_ci sctp_sk(sk)->disable_fragments = (*val == 0) ? 0 : 1; 22118c2ecf20Sopenharmony_ci return 0; 22128c2ecf20Sopenharmony_ci} 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_cistatic int sctp_setsockopt_events(struct sock *sk, __u8 *sn_type, 22158c2ecf20Sopenharmony_ci unsigned int optlen) 22168c2ecf20Sopenharmony_ci{ 22178c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 22188c2ecf20Sopenharmony_ci struct sctp_association *asoc; 22198c2ecf20Sopenharmony_ci int i; 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci if (optlen > sizeof(struct sctp_event_subscribe)) 22228c2ecf20Sopenharmony_ci return -EINVAL; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci for (i = 0; i < optlen; i++) 22258c2ecf20Sopenharmony_ci sctp_ulpevent_type_set(&sp->subscribe, SCTP_SN_TYPE_BASE + i, 22268c2ecf20Sopenharmony_ci sn_type[i]); 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sp->ep->asocs, asocs) 22298c2ecf20Sopenharmony_ci asoc->subscribe = sctp_sk(sk)->subscribe; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci /* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, 22328c2ecf20Sopenharmony_ci * if there is no data to be sent or retransmit, the stack will 22338c2ecf20Sopenharmony_ci * immediately send up this notification. 22348c2ecf20Sopenharmony_ci */ 22358c2ecf20Sopenharmony_ci if (sctp_ulpevent_type_enabled(sp->subscribe, SCTP_SENDER_DRY_EVENT)) { 22368c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, 0); 22398c2ecf20Sopenharmony_ci if (asoc && sctp_outq_is_empty(&asoc->outqueue)) { 22408c2ecf20Sopenharmony_ci event = sctp_ulpevent_make_sender_dry_event(asoc, 22418c2ecf20Sopenharmony_ci GFP_USER | __GFP_NOWARN); 22428c2ecf20Sopenharmony_ci if (!event) 22438c2ecf20Sopenharmony_ci return -ENOMEM; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci asoc->stream.si->enqueue_event(&asoc->ulpq, event); 22468c2ecf20Sopenharmony_ci } 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci return 0; 22508c2ecf20Sopenharmony_ci} 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci/* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) 22538c2ecf20Sopenharmony_ci * 22548c2ecf20Sopenharmony_ci * This socket option is applicable to the UDP-style socket only. When 22558c2ecf20Sopenharmony_ci * set it will cause associations that are idle for more than the 22568c2ecf20Sopenharmony_ci * specified number of seconds to automatically close. An association 22578c2ecf20Sopenharmony_ci * being idle is defined an association that has NOT sent or received 22588c2ecf20Sopenharmony_ci * user data. The special value of '0' indicates that no automatic 22598c2ecf20Sopenharmony_ci * close of any associations should be performed. The option expects an 22608c2ecf20Sopenharmony_ci * integer defining the number of seconds of idle time before an 22618c2ecf20Sopenharmony_ci * association is closed. 22628c2ecf20Sopenharmony_ci */ 22638c2ecf20Sopenharmony_cistatic int sctp_setsockopt_autoclose(struct sock *sk, u32 *optval, 22648c2ecf20Sopenharmony_ci unsigned int optlen) 22658c2ecf20Sopenharmony_ci{ 22668c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 22678c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci /* Applicable to UDP-style socket only */ 22708c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 22718c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 22728c2ecf20Sopenharmony_ci if (optlen != sizeof(int)) 22738c2ecf20Sopenharmony_ci return -EINVAL; 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci sp->autoclose = *optval; 22768c2ecf20Sopenharmony_ci if (sp->autoclose > net->sctp.max_autoclose) 22778c2ecf20Sopenharmony_ci sp->autoclose = net->sctp.max_autoclose; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci return 0; 22808c2ecf20Sopenharmony_ci} 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci/* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) 22838c2ecf20Sopenharmony_ci * 22848c2ecf20Sopenharmony_ci * Applications can enable or disable heartbeats for any peer address of 22858c2ecf20Sopenharmony_ci * an association, modify an address's heartbeat interval, force a 22868c2ecf20Sopenharmony_ci * heartbeat to be sent immediately, and adjust the address's maximum 22878c2ecf20Sopenharmony_ci * number of retransmissions sent before an address is considered 22888c2ecf20Sopenharmony_ci * unreachable. The following structure is used to access and modify an 22898c2ecf20Sopenharmony_ci * address's parameters: 22908c2ecf20Sopenharmony_ci * 22918c2ecf20Sopenharmony_ci * struct sctp_paddrparams { 22928c2ecf20Sopenharmony_ci * sctp_assoc_t spp_assoc_id; 22938c2ecf20Sopenharmony_ci * struct sockaddr_storage spp_address; 22948c2ecf20Sopenharmony_ci * uint32_t spp_hbinterval; 22958c2ecf20Sopenharmony_ci * uint16_t spp_pathmaxrxt; 22968c2ecf20Sopenharmony_ci * uint32_t spp_pathmtu; 22978c2ecf20Sopenharmony_ci * uint32_t spp_sackdelay; 22988c2ecf20Sopenharmony_ci * uint32_t spp_flags; 22998c2ecf20Sopenharmony_ci * uint32_t spp_ipv6_flowlabel; 23008c2ecf20Sopenharmony_ci * uint8_t spp_dscp; 23018c2ecf20Sopenharmony_ci * }; 23028c2ecf20Sopenharmony_ci * 23038c2ecf20Sopenharmony_ci * spp_assoc_id - (one-to-many style socket) This is filled in the 23048c2ecf20Sopenharmony_ci * application, and identifies the association for 23058c2ecf20Sopenharmony_ci * this query. 23068c2ecf20Sopenharmony_ci * spp_address - This specifies which address is of interest. 23078c2ecf20Sopenharmony_ci * spp_hbinterval - This contains the value of the heartbeat interval, 23088c2ecf20Sopenharmony_ci * in milliseconds. If a value of zero 23098c2ecf20Sopenharmony_ci * is present in this field then no changes are to 23108c2ecf20Sopenharmony_ci * be made to this parameter. 23118c2ecf20Sopenharmony_ci * spp_pathmaxrxt - This contains the maximum number of 23128c2ecf20Sopenharmony_ci * retransmissions before this address shall be 23138c2ecf20Sopenharmony_ci * considered unreachable. If a value of zero 23148c2ecf20Sopenharmony_ci * is present in this field then no changes are to 23158c2ecf20Sopenharmony_ci * be made to this parameter. 23168c2ecf20Sopenharmony_ci * spp_pathmtu - When Path MTU discovery is disabled the value 23178c2ecf20Sopenharmony_ci * specified here will be the "fixed" path mtu. 23188c2ecf20Sopenharmony_ci * Note that if the spp_address field is empty 23198c2ecf20Sopenharmony_ci * then all associations on this address will 23208c2ecf20Sopenharmony_ci * have this fixed path mtu set upon them. 23218c2ecf20Sopenharmony_ci * 23228c2ecf20Sopenharmony_ci * spp_sackdelay - When delayed sack is enabled, this value specifies 23238c2ecf20Sopenharmony_ci * the number of milliseconds that sacks will be delayed 23248c2ecf20Sopenharmony_ci * for. This value will apply to all addresses of an 23258c2ecf20Sopenharmony_ci * association if the spp_address field is empty. Note 23268c2ecf20Sopenharmony_ci * also, that if delayed sack is enabled and this 23278c2ecf20Sopenharmony_ci * value is set to 0, no change is made to the last 23288c2ecf20Sopenharmony_ci * recorded delayed sack timer value. 23298c2ecf20Sopenharmony_ci * 23308c2ecf20Sopenharmony_ci * spp_flags - These flags are used to control various features 23318c2ecf20Sopenharmony_ci * on an association. The flag field may contain 23328c2ecf20Sopenharmony_ci * zero or more of the following options. 23338c2ecf20Sopenharmony_ci * 23348c2ecf20Sopenharmony_ci * SPP_HB_ENABLE - Enable heartbeats on the 23358c2ecf20Sopenharmony_ci * specified address. Note that if the address 23368c2ecf20Sopenharmony_ci * field is empty all addresses for the association 23378c2ecf20Sopenharmony_ci * have heartbeats enabled upon them. 23388c2ecf20Sopenharmony_ci * 23398c2ecf20Sopenharmony_ci * SPP_HB_DISABLE - Disable heartbeats on the 23408c2ecf20Sopenharmony_ci * speicifed address. Note that if the address 23418c2ecf20Sopenharmony_ci * field is empty all addresses for the association 23428c2ecf20Sopenharmony_ci * will have their heartbeats disabled. Note also 23438c2ecf20Sopenharmony_ci * that SPP_HB_ENABLE and SPP_HB_DISABLE are 23448c2ecf20Sopenharmony_ci * mutually exclusive, only one of these two should 23458c2ecf20Sopenharmony_ci * be specified. Enabling both fields will have 23468c2ecf20Sopenharmony_ci * undetermined results. 23478c2ecf20Sopenharmony_ci * 23488c2ecf20Sopenharmony_ci * SPP_HB_DEMAND - Request a user initiated heartbeat 23498c2ecf20Sopenharmony_ci * to be made immediately. 23508c2ecf20Sopenharmony_ci * 23518c2ecf20Sopenharmony_ci * SPP_HB_TIME_IS_ZERO - Specify's that the time for 23528c2ecf20Sopenharmony_ci * heartbeat delayis to be set to the value of 0 23538c2ecf20Sopenharmony_ci * milliseconds. 23548c2ecf20Sopenharmony_ci * 23558c2ecf20Sopenharmony_ci * SPP_PMTUD_ENABLE - This field will enable PMTU 23568c2ecf20Sopenharmony_ci * discovery upon the specified address. Note that 23578c2ecf20Sopenharmony_ci * if the address feild is empty then all addresses 23588c2ecf20Sopenharmony_ci * on the association are effected. 23598c2ecf20Sopenharmony_ci * 23608c2ecf20Sopenharmony_ci * SPP_PMTUD_DISABLE - This field will disable PMTU 23618c2ecf20Sopenharmony_ci * discovery upon the specified address. Note that 23628c2ecf20Sopenharmony_ci * if the address feild is empty then all addresses 23638c2ecf20Sopenharmony_ci * on the association are effected. Not also that 23648c2ecf20Sopenharmony_ci * SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually 23658c2ecf20Sopenharmony_ci * exclusive. Enabling both will have undetermined 23668c2ecf20Sopenharmony_ci * results. 23678c2ecf20Sopenharmony_ci * 23688c2ecf20Sopenharmony_ci * SPP_SACKDELAY_ENABLE - Setting this flag turns 23698c2ecf20Sopenharmony_ci * on delayed sack. The time specified in spp_sackdelay 23708c2ecf20Sopenharmony_ci * is used to specify the sack delay for this address. Note 23718c2ecf20Sopenharmony_ci * that if spp_address is empty then all addresses will 23728c2ecf20Sopenharmony_ci * enable delayed sack and take on the sack delay 23738c2ecf20Sopenharmony_ci * value specified in spp_sackdelay. 23748c2ecf20Sopenharmony_ci * SPP_SACKDELAY_DISABLE - Setting this flag turns 23758c2ecf20Sopenharmony_ci * off delayed sack. If the spp_address field is blank then 23768c2ecf20Sopenharmony_ci * delayed sack is disabled for the entire association. Note 23778c2ecf20Sopenharmony_ci * also that this field is mutually exclusive to 23788c2ecf20Sopenharmony_ci * SPP_SACKDELAY_ENABLE, setting both will have undefined 23798c2ecf20Sopenharmony_ci * results. 23808c2ecf20Sopenharmony_ci * 23818c2ecf20Sopenharmony_ci * SPP_IPV6_FLOWLABEL: Setting this flag enables the 23828c2ecf20Sopenharmony_ci * setting of the IPV6 flow label value. The value is 23838c2ecf20Sopenharmony_ci * contained in the spp_ipv6_flowlabel field. 23848c2ecf20Sopenharmony_ci * Upon retrieval, this flag will be set to indicate that 23858c2ecf20Sopenharmony_ci * the spp_ipv6_flowlabel field has a valid value returned. 23868c2ecf20Sopenharmony_ci * If a specific destination address is set (in the 23878c2ecf20Sopenharmony_ci * spp_address field), then the value returned is that of 23888c2ecf20Sopenharmony_ci * the address. If just an association is specified (and 23898c2ecf20Sopenharmony_ci * no address), then the association's default flow label 23908c2ecf20Sopenharmony_ci * is returned. If neither an association nor a destination 23918c2ecf20Sopenharmony_ci * is specified, then the socket's default flow label is 23928c2ecf20Sopenharmony_ci * returned. For non-IPv6 sockets, this flag will be left 23938c2ecf20Sopenharmony_ci * cleared. 23948c2ecf20Sopenharmony_ci * 23958c2ecf20Sopenharmony_ci * SPP_DSCP: Setting this flag enables the setting of the 23968c2ecf20Sopenharmony_ci * Differentiated Services Code Point (DSCP) value 23978c2ecf20Sopenharmony_ci * associated with either the association or a specific 23988c2ecf20Sopenharmony_ci * address. The value is obtained in the spp_dscp field. 23998c2ecf20Sopenharmony_ci * Upon retrieval, this flag will be set to indicate that 24008c2ecf20Sopenharmony_ci * the spp_dscp field has a valid value returned. If a 24018c2ecf20Sopenharmony_ci * specific destination address is set when called (in the 24028c2ecf20Sopenharmony_ci * spp_address field), then that specific destination 24038c2ecf20Sopenharmony_ci * address's DSCP value is returned. If just an association 24048c2ecf20Sopenharmony_ci * is specified, then the association's default DSCP is 24058c2ecf20Sopenharmony_ci * returned. If neither an association nor a destination is 24068c2ecf20Sopenharmony_ci * specified, then the socket's default DSCP is returned. 24078c2ecf20Sopenharmony_ci * 24088c2ecf20Sopenharmony_ci * spp_ipv6_flowlabel 24098c2ecf20Sopenharmony_ci * - This field is used in conjunction with the 24108c2ecf20Sopenharmony_ci * SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label. 24118c2ecf20Sopenharmony_ci * The 20 least significant bits are used for the flow 24128c2ecf20Sopenharmony_ci * label. This setting has precedence over any IPv6-layer 24138c2ecf20Sopenharmony_ci * setting. 24148c2ecf20Sopenharmony_ci * 24158c2ecf20Sopenharmony_ci * spp_dscp - This field is used in conjunction with the SPP_DSCP flag 24168c2ecf20Sopenharmony_ci * and contains the DSCP. The 6 most significant bits are 24178c2ecf20Sopenharmony_ci * used for the DSCP. This setting has precedence over any 24188c2ecf20Sopenharmony_ci * IPv4- or IPv6- layer setting. 24198c2ecf20Sopenharmony_ci */ 24208c2ecf20Sopenharmony_cistatic int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, 24218c2ecf20Sopenharmony_ci struct sctp_transport *trans, 24228c2ecf20Sopenharmony_ci struct sctp_association *asoc, 24238c2ecf20Sopenharmony_ci struct sctp_sock *sp, 24248c2ecf20Sopenharmony_ci int hb_change, 24258c2ecf20Sopenharmony_ci int pmtud_change, 24268c2ecf20Sopenharmony_ci int sackdelay_change) 24278c2ecf20Sopenharmony_ci{ 24288c2ecf20Sopenharmony_ci int error; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci if (params->spp_flags & SPP_HB_DEMAND && trans) { 24318c2ecf20Sopenharmony_ci error = sctp_primitive_REQUESTHEARTBEAT(trans->asoc->base.net, 24328c2ecf20Sopenharmony_ci trans->asoc, trans); 24338c2ecf20Sopenharmony_ci if (error) 24348c2ecf20Sopenharmony_ci return error; 24358c2ecf20Sopenharmony_ci } 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci /* Note that unless the spp_flag is set to SPP_HB_ENABLE the value of 24388c2ecf20Sopenharmony_ci * this field is ignored. Note also that a value of zero indicates 24398c2ecf20Sopenharmony_ci * the current setting should be left unchanged. 24408c2ecf20Sopenharmony_ci */ 24418c2ecf20Sopenharmony_ci if (params->spp_flags & SPP_HB_ENABLE) { 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci /* Re-zero the interval if the SPP_HB_TIME_IS_ZERO is 24448c2ecf20Sopenharmony_ci * set. This lets us use 0 value when this flag 24458c2ecf20Sopenharmony_ci * is set. 24468c2ecf20Sopenharmony_ci */ 24478c2ecf20Sopenharmony_ci if (params->spp_flags & SPP_HB_TIME_IS_ZERO) 24488c2ecf20Sopenharmony_ci params->spp_hbinterval = 0; 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci if (params->spp_hbinterval || 24518c2ecf20Sopenharmony_ci (params->spp_flags & SPP_HB_TIME_IS_ZERO)) { 24528c2ecf20Sopenharmony_ci if (trans) { 24538c2ecf20Sopenharmony_ci trans->hbinterval = 24548c2ecf20Sopenharmony_ci msecs_to_jiffies(params->spp_hbinterval); 24558c2ecf20Sopenharmony_ci sctp_transport_reset_hb_timer(trans); 24568c2ecf20Sopenharmony_ci } else if (asoc) { 24578c2ecf20Sopenharmony_ci asoc->hbinterval = 24588c2ecf20Sopenharmony_ci msecs_to_jiffies(params->spp_hbinterval); 24598c2ecf20Sopenharmony_ci } else { 24608c2ecf20Sopenharmony_ci sp->hbinterval = params->spp_hbinterval; 24618c2ecf20Sopenharmony_ci } 24628c2ecf20Sopenharmony_ci } 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci if (hb_change) { 24668c2ecf20Sopenharmony_ci if (trans) { 24678c2ecf20Sopenharmony_ci trans->param_flags = 24688c2ecf20Sopenharmony_ci (trans->param_flags & ~SPP_HB) | hb_change; 24698c2ecf20Sopenharmony_ci } else if (asoc) { 24708c2ecf20Sopenharmony_ci asoc->param_flags = 24718c2ecf20Sopenharmony_ci (asoc->param_flags & ~SPP_HB) | hb_change; 24728c2ecf20Sopenharmony_ci } else { 24738c2ecf20Sopenharmony_ci sp->param_flags = 24748c2ecf20Sopenharmony_ci (sp->param_flags & ~SPP_HB) | hb_change; 24758c2ecf20Sopenharmony_ci } 24768c2ecf20Sopenharmony_ci } 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci /* When Path MTU discovery is disabled the value specified here will 24798c2ecf20Sopenharmony_ci * be the "fixed" path mtu (i.e. the value of the spp_flags field must 24808c2ecf20Sopenharmony_ci * include the flag SPP_PMTUD_DISABLE for this field to have any 24818c2ecf20Sopenharmony_ci * effect). 24828c2ecf20Sopenharmony_ci */ 24838c2ecf20Sopenharmony_ci if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { 24848c2ecf20Sopenharmony_ci if (trans) { 24858c2ecf20Sopenharmony_ci trans->pathmtu = params->spp_pathmtu; 24868c2ecf20Sopenharmony_ci sctp_assoc_sync_pmtu(asoc); 24878c2ecf20Sopenharmony_ci } else if (asoc) { 24888c2ecf20Sopenharmony_ci sctp_assoc_set_pmtu(asoc, params->spp_pathmtu); 24898c2ecf20Sopenharmony_ci } else { 24908c2ecf20Sopenharmony_ci sp->pathmtu = params->spp_pathmtu; 24918c2ecf20Sopenharmony_ci } 24928c2ecf20Sopenharmony_ci } 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci if (pmtud_change) { 24958c2ecf20Sopenharmony_ci if (trans) { 24968c2ecf20Sopenharmony_ci int update = (trans->param_flags & SPP_PMTUD_DISABLE) && 24978c2ecf20Sopenharmony_ci (params->spp_flags & SPP_PMTUD_ENABLE); 24988c2ecf20Sopenharmony_ci trans->param_flags = 24998c2ecf20Sopenharmony_ci (trans->param_flags & ~SPP_PMTUD) | pmtud_change; 25008c2ecf20Sopenharmony_ci if (update) { 25018c2ecf20Sopenharmony_ci sctp_transport_pmtu(trans, sctp_opt2sk(sp)); 25028c2ecf20Sopenharmony_ci sctp_assoc_sync_pmtu(asoc); 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci } else if (asoc) { 25058c2ecf20Sopenharmony_ci asoc->param_flags = 25068c2ecf20Sopenharmony_ci (asoc->param_flags & ~SPP_PMTUD) | pmtud_change; 25078c2ecf20Sopenharmony_ci } else { 25088c2ecf20Sopenharmony_ci sp->param_flags = 25098c2ecf20Sopenharmony_ci (sp->param_flags & ~SPP_PMTUD) | pmtud_change; 25108c2ecf20Sopenharmony_ci } 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci /* Note that unless the spp_flag is set to SPP_SACKDELAY_ENABLE the 25148c2ecf20Sopenharmony_ci * value of this field is ignored. Note also that a value of zero 25158c2ecf20Sopenharmony_ci * indicates the current setting should be left unchanged. 25168c2ecf20Sopenharmony_ci */ 25178c2ecf20Sopenharmony_ci if ((params->spp_flags & SPP_SACKDELAY_ENABLE) && params->spp_sackdelay) { 25188c2ecf20Sopenharmony_ci if (trans) { 25198c2ecf20Sopenharmony_ci trans->sackdelay = 25208c2ecf20Sopenharmony_ci msecs_to_jiffies(params->spp_sackdelay); 25218c2ecf20Sopenharmony_ci } else if (asoc) { 25228c2ecf20Sopenharmony_ci asoc->sackdelay = 25238c2ecf20Sopenharmony_ci msecs_to_jiffies(params->spp_sackdelay); 25248c2ecf20Sopenharmony_ci } else { 25258c2ecf20Sopenharmony_ci sp->sackdelay = params->spp_sackdelay; 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci } 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci if (sackdelay_change) { 25308c2ecf20Sopenharmony_ci if (trans) { 25318c2ecf20Sopenharmony_ci trans->param_flags = 25328c2ecf20Sopenharmony_ci (trans->param_flags & ~SPP_SACKDELAY) | 25338c2ecf20Sopenharmony_ci sackdelay_change; 25348c2ecf20Sopenharmony_ci } else if (asoc) { 25358c2ecf20Sopenharmony_ci asoc->param_flags = 25368c2ecf20Sopenharmony_ci (asoc->param_flags & ~SPP_SACKDELAY) | 25378c2ecf20Sopenharmony_ci sackdelay_change; 25388c2ecf20Sopenharmony_ci } else { 25398c2ecf20Sopenharmony_ci sp->param_flags = 25408c2ecf20Sopenharmony_ci (sp->param_flags & ~SPP_SACKDELAY) | 25418c2ecf20Sopenharmony_ci sackdelay_change; 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci } 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci /* Note that a value of zero indicates the current setting should be 25468c2ecf20Sopenharmony_ci left unchanged. 25478c2ecf20Sopenharmony_ci */ 25488c2ecf20Sopenharmony_ci if (params->spp_pathmaxrxt) { 25498c2ecf20Sopenharmony_ci if (trans) { 25508c2ecf20Sopenharmony_ci trans->pathmaxrxt = params->spp_pathmaxrxt; 25518c2ecf20Sopenharmony_ci } else if (asoc) { 25528c2ecf20Sopenharmony_ci asoc->pathmaxrxt = params->spp_pathmaxrxt; 25538c2ecf20Sopenharmony_ci } else { 25548c2ecf20Sopenharmony_ci sp->pathmaxrxt = params->spp_pathmaxrxt; 25558c2ecf20Sopenharmony_ci } 25568c2ecf20Sopenharmony_ci } 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci if (params->spp_flags & SPP_IPV6_FLOWLABEL) { 25598c2ecf20Sopenharmony_ci if (trans) { 25608c2ecf20Sopenharmony_ci if (trans->ipaddr.sa.sa_family == AF_INET6) { 25618c2ecf20Sopenharmony_ci trans->flowlabel = params->spp_ipv6_flowlabel & 25628c2ecf20Sopenharmony_ci SCTP_FLOWLABEL_VAL_MASK; 25638c2ecf20Sopenharmony_ci trans->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 25648c2ecf20Sopenharmony_ci } 25658c2ecf20Sopenharmony_ci } else if (asoc) { 25668c2ecf20Sopenharmony_ci struct sctp_transport *t; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci list_for_each_entry(t, &asoc->peer.transport_addr_list, 25698c2ecf20Sopenharmony_ci transports) { 25708c2ecf20Sopenharmony_ci if (t->ipaddr.sa.sa_family != AF_INET6) 25718c2ecf20Sopenharmony_ci continue; 25728c2ecf20Sopenharmony_ci t->flowlabel = params->spp_ipv6_flowlabel & 25738c2ecf20Sopenharmony_ci SCTP_FLOWLABEL_VAL_MASK; 25748c2ecf20Sopenharmony_ci t->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 25758c2ecf20Sopenharmony_ci } 25768c2ecf20Sopenharmony_ci asoc->flowlabel = params->spp_ipv6_flowlabel & 25778c2ecf20Sopenharmony_ci SCTP_FLOWLABEL_VAL_MASK; 25788c2ecf20Sopenharmony_ci asoc->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 25798c2ecf20Sopenharmony_ci } else if (sctp_opt2sk(sp)->sk_family == AF_INET6) { 25808c2ecf20Sopenharmony_ci sp->flowlabel = params->spp_ipv6_flowlabel & 25818c2ecf20Sopenharmony_ci SCTP_FLOWLABEL_VAL_MASK; 25828c2ecf20Sopenharmony_ci sp->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci } 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci if (params->spp_flags & SPP_DSCP) { 25878c2ecf20Sopenharmony_ci if (trans) { 25888c2ecf20Sopenharmony_ci trans->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK; 25898c2ecf20Sopenharmony_ci trans->dscp |= SCTP_DSCP_SET_MASK; 25908c2ecf20Sopenharmony_ci } else if (asoc) { 25918c2ecf20Sopenharmony_ci struct sctp_transport *t; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci list_for_each_entry(t, &asoc->peer.transport_addr_list, 25948c2ecf20Sopenharmony_ci transports) { 25958c2ecf20Sopenharmony_ci t->dscp = params->spp_dscp & 25968c2ecf20Sopenharmony_ci SCTP_DSCP_VAL_MASK; 25978c2ecf20Sopenharmony_ci t->dscp |= SCTP_DSCP_SET_MASK; 25988c2ecf20Sopenharmony_ci } 25998c2ecf20Sopenharmony_ci asoc->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK; 26008c2ecf20Sopenharmony_ci asoc->dscp |= SCTP_DSCP_SET_MASK; 26018c2ecf20Sopenharmony_ci } else { 26028c2ecf20Sopenharmony_ci sp->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK; 26038c2ecf20Sopenharmony_ci sp->dscp |= SCTP_DSCP_SET_MASK; 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci return 0; 26088c2ecf20Sopenharmony_ci} 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_cistatic int sctp_setsockopt_peer_addr_params(struct sock *sk, 26118c2ecf20Sopenharmony_ci struct sctp_paddrparams *params, 26128c2ecf20Sopenharmony_ci unsigned int optlen) 26138c2ecf20Sopenharmony_ci{ 26148c2ecf20Sopenharmony_ci struct sctp_transport *trans = NULL; 26158c2ecf20Sopenharmony_ci struct sctp_association *asoc = NULL; 26168c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 26178c2ecf20Sopenharmony_ci int error; 26188c2ecf20Sopenharmony_ci int hb_change, pmtud_change, sackdelay_change; 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci if (optlen == ALIGN(offsetof(struct sctp_paddrparams, 26218c2ecf20Sopenharmony_ci spp_ipv6_flowlabel), 4)) { 26228c2ecf20Sopenharmony_ci if (params->spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL)) 26238c2ecf20Sopenharmony_ci return -EINVAL; 26248c2ecf20Sopenharmony_ci } else if (optlen != sizeof(*params)) { 26258c2ecf20Sopenharmony_ci return -EINVAL; 26268c2ecf20Sopenharmony_ci } 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci /* Validate flags and value parameters. */ 26298c2ecf20Sopenharmony_ci hb_change = params->spp_flags & SPP_HB; 26308c2ecf20Sopenharmony_ci pmtud_change = params->spp_flags & SPP_PMTUD; 26318c2ecf20Sopenharmony_ci sackdelay_change = params->spp_flags & SPP_SACKDELAY; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci if (hb_change == SPP_HB || 26348c2ecf20Sopenharmony_ci pmtud_change == SPP_PMTUD || 26358c2ecf20Sopenharmony_ci sackdelay_change == SPP_SACKDELAY || 26368c2ecf20Sopenharmony_ci params->spp_sackdelay > 500 || 26378c2ecf20Sopenharmony_ci (params->spp_pathmtu && 26388c2ecf20Sopenharmony_ci params->spp_pathmtu < SCTP_DEFAULT_MINSEGMENT)) 26398c2ecf20Sopenharmony_ci return -EINVAL; 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci /* If an address other than INADDR_ANY is specified, and 26428c2ecf20Sopenharmony_ci * no transport is found, then the request is invalid. 26438c2ecf20Sopenharmony_ci */ 26448c2ecf20Sopenharmony_ci if (!sctp_is_any(sk, (union sctp_addr *)¶ms->spp_address)) { 26458c2ecf20Sopenharmony_ci trans = sctp_addr_id2transport(sk, ¶ms->spp_address, 26468c2ecf20Sopenharmony_ci params->spp_assoc_id); 26478c2ecf20Sopenharmony_ci if (!trans) 26488c2ecf20Sopenharmony_ci return -EINVAL; 26498c2ecf20Sopenharmony_ci } 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci /* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the 26528c2ecf20Sopenharmony_ci * socket is a one to many style socket, and an association 26538c2ecf20Sopenharmony_ci * was not found, then the id was invalid. 26548c2ecf20Sopenharmony_ci */ 26558c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->spp_assoc_id); 26568c2ecf20Sopenharmony_ci if (!asoc && params->spp_assoc_id != SCTP_FUTURE_ASSOC && 26578c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 26588c2ecf20Sopenharmony_ci return -EINVAL; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci /* Heartbeat demand can only be sent on a transport or 26618c2ecf20Sopenharmony_ci * association, but not a socket. 26628c2ecf20Sopenharmony_ci */ 26638c2ecf20Sopenharmony_ci if (params->spp_flags & SPP_HB_DEMAND && !trans && !asoc) 26648c2ecf20Sopenharmony_ci return -EINVAL; 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci /* Process parameters. */ 26678c2ecf20Sopenharmony_ci error = sctp_apply_peer_addr_params(params, trans, asoc, sp, 26688c2ecf20Sopenharmony_ci hb_change, pmtud_change, 26698c2ecf20Sopenharmony_ci sackdelay_change); 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci if (error) 26728c2ecf20Sopenharmony_ci return error; 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci /* If changes are for association, also apply parameters to each 26758c2ecf20Sopenharmony_ci * transport. 26768c2ecf20Sopenharmony_ci */ 26778c2ecf20Sopenharmony_ci if (!trans && asoc) { 26788c2ecf20Sopenharmony_ci list_for_each_entry(trans, &asoc->peer.transport_addr_list, 26798c2ecf20Sopenharmony_ci transports) { 26808c2ecf20Sopenharmony_ci sctp_apply_peer_addr_params(params, trans, asoc, sp, 26818c2ecf20Sopenharmony_ci hb_change, pmtud_change, 26828c2ecf20Sopenharmony_ci sackdelay_change); 26838c2ecf20Sopenharmony_ci } 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci return 0; 26878c2ecf20Sopenharmony_ci} 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_cistatic inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags) 26908c2ecf20Sopenharmony_ci{ 26918c2ecf20Sopenharmony_ci return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; 26928c2ecf20Sopenharmony_ci} 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_cistatic inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags) 26958c2ecf20Sopenharmony_ci{ 26968c2ecf20Sopenharmony_ci return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; 26978c2ecf20Sopenharmony_ci} 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_cistatic void sctp_apply_asoc_delayed_ack(struct sctp_sack_info *params, 27008c2ecf20Sopenharmony_ci struct sctp_association *asoc) 27018c2ecf20Sopenharmony_ci{ 27028c2ecf20Sopenharmony_ci struct sctp_transport *trans; 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci if (params->sack_delay) { 27058c2ecf20Sopenharmony_ci asoc->sackdelay = msecs_to_jiffies(params->sack_delay); 27068c2ecf20Sopenharmony_ci asoc->param_flags = 27078c2ecf20Sopenharmony_ci sctp_spp_sackdelay_enable(asoc->param_flags); 27088c2ecf20Sopenharmony_ci } 27098c2ecf20Sopenharmony_ci if (params->sack_freq == 1) { 27108c2ecf20Sopenharmony_ci asoc->param_flags = 27118c2ecf20Sopenharmony_ci sctp_spp_sackdelay_disable(asoc->param_flags); 27128c2ecf20Sopenharmony_ci } else if (params->sack_freq > 1) { 27138c2ecf20Sopenharmony_ci asoc->sackfreq = params->sack_freq; 27148c2ecf20Sopenharmony_ci asoc->param_flags = 27158c2ecf20Sopenharmony_ci sctp_spp_sackdelay_enable(asoc->param_flags); 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci list_for_each_entry(trans, &asoc->peer.transport_addr_list, 27198c2ecf20Sopenharmony_ci transports) { 27208c2ecf20Sopenharmony_ci if (params->sack_delay) { 27218c2ecf20Sopenharmony_ci trans->sackdelay = msecs_to_jiffies(params->sack_delay); 27228c2ecf20Sopenharmony_ci trans->param_flags = 27238c2ecf20Sopenharmony_ci sctp_spp_sackdelay_enable(trans->param_flags); 27248c2ecf20Sopenharmony_ci } 27258c2ecf20Sopenharmony_ci if (params->sack_freq == 1) { 27268c2ecf20Sopenharmony_ci trans->param_flags = 27278c2ecf20Sopenharmony_ci sctp_spp_sackdelay_disable(trans->param_flags); 27288c2ecf20Sopenharmony_ci } else if (params->sack_freq > 1) { 27298c2ecf20Sopenharmony_ci trans->sackfreq = params->sack_freq; 27308c2ecf20Sopenharmony_ci trans->param_flags = 27318c2ecf20Sopenharmony_ci sctp_spp_sackdelay_enable(trans->param_flags); 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci } 27348c2ecf20Sopenharmony_ci} 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci/* 27378c2ecf20Sopenharmony_ci * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 27388c2ecf20Sopenharmony_ci * 27398c2ecf20Sopenharmony_ci * This option will effect the way delayed acks are performed. This 27408c2ecf20Sopenharmony_ci * option allows you to get or set the delayed ack time, in 27418c2ecf20Sopenharmony_ci * milliseconds. It also allows changing the delayed ack frequency. 27428c2ecf20Sopenharmony_ci * Changing the frequency to 1 disables the delayed sack algorithm. If 27438c2ecf20Sopenharmony_ci * the assoc_id is 0, then this sets or gets the endpoints default 27448c2ecf20Sopenharmony_ci * values. If the assoc_id field is non-zero, then the set or get 27458c2ecf20Sopenharmony_ci * effects the specified association for the one to many model (the 27468c2ecf20Sopenharmony_ci * assoc_id field is ignored by the one to one model). Note that if 27478c2ecf20Sopenharmony_ci * sack_delay or sack_freq are 0 when setting this option, then the 27488c2ecf20Sopenharmony_ci * current values will remain unchanged. 27498c2ecf20Sopenharmony_ci * 27508c2ecf20Sopenharmony_ci * struct sctp_sack_info { 27518c2ecf20Sopenharmony_ci * sctp_assoc_t sack_assoc_id; 27528c2ecf20Sopenharmony_ci * uint32_t sack_delay; 27538c2ecf20Sopenharmony_ci * uint32_t sack_freq; 27548c2ecf20Sopenharmony_ci * }; 27558c2ecf20Sopenharmony_ci * 27568c2ecf20Sopenharmony_ci * sack_assoc_id - This parameter, indicates which association the user 27578c2ecf20Sopenharmony_ci * is performing an action upon. Note that if this field's value is 27588c2ecf20Sopenharmony_ci * zero then the endpoints default value is changed (effecting future 27598c2ecf20Sopenharmony_ci * associations only). 27608c2ecf20Sopenharmony_ci * 27618c2ecf20Sopenharmony_ci * sack_delay - This parameter contains the number of milliseconds that 27628c2ecf20Sopenharmony_ci * the user is requesting the delayed ACK timer be set to. Note that 27638c2ecf20Sopenharmony_ci * this value is defined in the standard to be between 200 and 500 27648c2ecf20Sopenharmony_ci * milliseconds. 27658c2ecf20Sopenharmony_ci * 27668c2ecf20Sopenharmony_ci * sack_freq - This parameter contains the number of packets that must 27678c2ecf20Sopenharmony_ci * be received before a sack is sent without waiting for the delay 27688c2ecf20Sopenharmony_ci * timer to expire. The default value for this is 2, setting this 27698c2ecf20Sopenharmony_ci * value to 1 will disable the delayed sack algorithm. 27708c2ecf20Sopenharmony_ci */ 27718c2ecf20Sopenharmony_cistatic int __sctp_setsockopt_delayed_ack(struct sock *sk, 27728c2ecf20Sopenharmony_ci struct sctp_sack_info *params) 27738c2ecf20Sopenharmony_ci{ 27748c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 27758c2ecf20Sopenharmony_ci struct sctp_association *asoc; 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci /* Validate value parameter. */ 27788c2ecf20Sopenharmony_ci if (params->sack_delay > 500) 27798c2ecf20Sopenharmony_ci return -EINVAL; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci /* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the 27828c2ecf20Sopenharmony_ci * socket is a one to many style socket, and an association 27838c2ecf20Sopenharmony_ci * was not found, then the id was invalid. 27848c2ecf20Sopenharmony_ci */ 27858c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->sack_assoc_id); 27868c2ecf20Sopenharmony_ci if (!asoc && params->sack_assoc_id > SCTP_ALL_ASSOC && 27878c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 27888c2ecf20Sopenharmony_ci return -EINVAL; 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (asoc) { 27918c2ecf20Sopenharmony_ci sctp_apply_asoc_delayed_ack(params, asoc); 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci return 0; 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 27978c2ecf20Sopenharmony_ci params->sack_assoc_id = SCTP_FUTURE_ASSOC; 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci if (params->sack_assoc_id == SCTP_FUTURE_ASSOC || 28008c2ecf20Sopenharmony_ci params->sack_assoc_id == SCTP_ALL_ASSOC) { 28018c2ecf20Sopenharmony_ci if (params->sack_delay) { 28028c2ecf20Sopenharmony_ci sp->sackdelay = params->sack_delay; 28038c2ecf20Sopenharmony_ci sp->param_flags = 28048c2ecf20Sopenharmony_ci sctp_spp_sackdelay_enable(sp->param_flags); 28058c2ecf20Sopenharmony_ci } 28068c2ecf20Sopenharmony_ci if (params->sack_freq == 1) { 28078c2ecf20Sopenharmony_ci sp->param_flags = 28088c2ecf20Sopenharmony_ci sctp_spp_sackdelay_disable(sp->param_flags); 28098c2ecf20Sopenharmony_ci } else if (params->sack_freq > 1) { 28108c2ecf20Sopenharmony_ci sp->sackfreq = params->sack_freq; 28118c2ecf20Sopenharmony_ci sp->param_flags = 28128c2ecf20Sopenharmony_ci sctp_spp_sackdelay_enable(sp->param_flags); 28138c2ecf20Sopenharmony_ci } 28148c2ecf20Sopenharmony_ci } 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci if (params->sack_assoc_id == SCTP_CURRENT_ASSOC || 28178c2ecf20Sopenharmony_ci params->sack_assoc_id == SCTP_ALL_ASSOC) 28188c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sp->ep->asocs, asocs) 28198c2ecf20Sopenharmony_ci sctp_apply_asoc_delayed_ack(params, asoc); 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci return 0; 28228c2ecf20Sopenharmony_ci} 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_cistatic int sctp_setsockopt_delayed_ack(struct sock *sk, 28258c2ecf20Sopenharmony_ci struct sctp_sack_info *params, 28268c2ecf20Sopenharmony_ci unsigned int optlen) 28278c2ecf20Sopenharmony_ci{ 28288c2ecf20Sopenharmony_ci if (optlen == sizeof(struct sctp_assoc_value)) { 28298c2ecf20Sopenharmony_ci struct sctp_assoc_value *v = (struct sctp_assoc_value *)params; 28308c2ecf20Sopenharmony_ci struct sctp_sack_info p; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci pr_warn_ratelimited(DEPRECATED 28338c2ecf20Sopenharmony_ci "%s (pid %d) " 28348c2ecf20Sopenharmony_ci "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 28358c2ecf20Sopenharmony_ci "Use struct sctp_sack_info instead\n", 28368c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current)); 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci p.sack_assoc_id = v->assoc_id; 28398c2ecf20Sopenharmony_ci p.sack_delay = v->assoc_value; 28408c2ecf20Sopenharmony_ci p.sack_freq = v->assoc_value ? 0 : 1; 28418c2ecf20Sopenharmony_ci return __sctp_setsockopt_delayed_ack(sk, &p); 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_sack_info)) 28458c2ecf20Sopenharmony_ci return -EINVAL; 28468c2ecf20Sopenharmony_ci if (params->sack_delay == 0 && params->sack_freq == 0) 28478c2ecf20Sopenharmony_ci return 0; 28488c2ecf20Sopenharmony_ci return __sctp_setsockopt_delayed_ack(sk, params); 28498c2ecf20Sopenharmony_ci} 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci/* 7.1.3 Initialization Parameters (SCTP_INITMSG) 28528c2ecf20Sopenharmony_ci * 28538c2ecf20Sopenharmony_ci * Applications can specify protocol parameters for the default association 28548c2ecf20Sopenharmony_ci * initialization. The option name argument to setsockopt() and getsockopt() 28558c2ecf20Sopenharmony_ci * is SCTP_INITMSG. 28568c2ecf20Sopenharmony_ci * 28578c2ecf20Sopenharmony_ci * Setting initialization parameters is effective only on an unconnected 28588c2ecf20Sopenharmony_ci * socket (for UDP-style sockets only future associations are effected 28598c2ecf20Sopenharmony_ci * by the change). With TCP-style sockets, this option is inherited by 28608c2ecf20Sopenharmony_ci * sockets derived from a listener socket. 28618c2ecf20Sopenharmony_ci */ 28628c2ecf20Sopenharmony_cistatic int sctp_setsockopt_initmsg(struct sock *sk, struct sctp_initmsg *sinit, 28638c2ecf20Sopenharmony_ci unsigned int optlen) 28648c2ecf20Sopenharmony_ci{ 28658c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_initmsg)) 28688c2ecf20Sopenharmony_ci return -EINVAL; 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci if (sinit->sinit_num_ostreams) 28718c2ecf20Sopenharmony_ci sp->initmsg.sinit_num_ostreams = sinit->sinit_num_ostreams; 28728c2ecf20Sopenharmony_ci if (sinit->sinit_max_instreams) 28738c2ecf20Sopenharmony_ci sp->initmsg.sinit_max_instreams = sinit->sinit_max_instreams; 28748c2ecf20Sopenharmony_ci if (sinit->sinit_max_attempts) 28758c2ecf20Sopenharmony_ci sp->initmsg.sinit_max_attempts = sinit->sinit_max_attempts; 28768c2ecf20Sopenharmony_ci if (sinit->sinit_max_init_timeo) 28778c2ecf20Sopenharmony_ci sp->initmsg.sinit_max_init_timeo = sinit->sinit_max_init_timeo; 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci return 0; 28808c2ecf20Sopenharmony_ci} 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci/* 28838c2ecf20Sopenharmony_ci * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 28848c2ecf20Sopenharmony_ci * 28858c2ecf20Sopenharmony_ci * Applications that wish to use the sendto() system call may wish to 28868c2ecf20Sopenharmony_ci * specify a default set of parameters that would normally be supplied 28878c2ecf20Sopenharmony_ci * through the inclusion of ancillary data. This socket option allows 28888c2ecf20Sopenharmony_ci * such an application to set the default sctp_sndrcvinfo structure. 28898c2ecf20Sopenharmony_ci * The application that wishes to use this socket option simply passes 28908c2ecf20Sopenharmony_ci * in to this call the sctp_sndrcvinfo structure defined in Section 28918c2ecf20Sopenharmony_ci * 5.2.2) The input parameters accepted by this call include 28928c2ecf20Sopenharmony_ci * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 28938c2ecf20Sopenharmony_ci * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 28948c2ecf20Sopenharmony_ci * to this call if the caller is using the UDP model. 28958c2ecf20Sopenharmony_ci */ 28968c2ecf20Sopenharmony_cistatic int sctp_setsockopt_default_send_param(struct sock *sk, 28978c2ecf20Sopenharmony_ci struct sctp_sndrcvinfo *info, 28988c2ecf20Sopenharmony_ci unsigned int optlen) 28998c2ecf20Sopenharmony_ci{ 29008c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 29018c2ecf20Sopenharmony_ci struct sctp_association *asoc; 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci if (optlen != sizeof(*info)) 29048c2ecf20Sopenharmony_ci return -EINVAL; 29058c2ecf20Sopenharmony_ci if (info->sinfo_flags & 29068c2ecf20Sopenharmony_ci ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 29078c2ecf20Sopenharmony_ci SCTP_ABORT | SCTP_EOF)) 29088c2ecf20Sopenharmony_ci return -EINVAL; 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, info->sinfo_assoc_id); 29118c2ecf20Sopenharmony_ci if (!asoc && info->sinfo_assoc_id > SCTP_ALL_ASSOC && 29128c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 29138c2ecf20Sopenharmony_ci return -EINVAL; 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci if (asoc) { 29168c2ecf20Sopenharmony_ci asoc->default_stream = info->sinfo_stream; 29178c2ecf20Sopenharmony_ci asoc->default_flags = info->sinfo_flags; 29188c2ecf20Sopenharmony_ci asoc->default_ppid = info->sinfo_ppid; 29198c2ecf20Sopenharmony_ci asoc->default_context = info->sinfo_context; 29208c2ecf20Sopenharmony_ci asoc->default_timetolive = info->sinfo_timetolive; 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci return 0; 29238c2ecf20Sopenharmony_ci } 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 29268c2ecf20Sopenharmony_ci info->sinfo_assoc_id = SCTP_FUTURE_ASSOC; 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci if (info->sinfo_assoc_id == SCTP_FUTURE_ASSOC || 29298c2ecf20Sopenharmony_ci info->sinfo_assoc_id == SCTP_ALL_ASSOC) { 29308c2ecf20Sopenharmony_ci sp->default_stream = info->sinfo_stream; 29318c2ecf20Sopenharmony_ci sp->default_flags = info->sinfo_flags; 29328c2ecf20Sopenharmony_ci sp->default_ppid = info->sinfo_ppid; 29338c2ecf20Sopenharmony_ci sp->default_context = info->sinfo_context; 29348c2ecf20Sopenharmony_ci sp->default_timetolive = info->sinfo_timetolive; 29358c2ecf20Sopenharmony_ci } 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci if (info->sinfo_assoc_id == SCTP_CURRENT_ASSOC || 29388c2ecf20Sopenharmony_ci info->sinfo_assoc_id == SCTP_ALL_ASSOC) { 29398c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 29408c2ecf20Sopenharmony_ci asoc->default_stream = info->sinfo_stream; 29418c2ecf20Sopenharmony_ci asoc->default_flags = info->sinfo_flags; 29428c2ecf20Sopenharmony_ci asoc->default_ppid = info->sinfo_ppid; 29438c2ecf20Sopenharmony_ci asoc->default_context = info->sinfo_context; 29448c2ecf20Sopenharmony_ci asoc->default_timetolive = info->sinfo_timetolive; 29458c2ecf20Sopenharmony_ci } 29468c2ecf20Sopenharmony_ci } 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci return 0; 29498c2ecf20Sopenharmony_ci} 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_ci/* RFC6458, Section 8.1.31. Set/get Default Send Parameters 29528c2ecf20Sopenharmony_ci * (SCTP_DEFAULT_SNDINFO) 29538c2ecf20Sopenharmony_ci */ 29548c2ecf20Sopenharmony_cistatic int sctp_setsockopt_default_sndinfo(struct sock *sk, 29558c2ecf20Sopenharmony_ci struct sctp_sndinfo *info, 29568c2ecf20Sopenharmony_ci unsigned int optlen) 29578c2ecf20Sopenharmony_ci{ 29588c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 29598c2ecf20Sopenharmony_ci struct sctp_association *asoc; 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci if (optlen != sizeof(*info)) 29628c2ecf20Sopenharmony_ci return -EINVAL; 29638c2ecf20Sopenharmony_ci if (info->snd_flags & 29648c2ecf20Sopenharmony_ci ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 29658c2ecf20Sopenharmony_ci SCTP_ABORT | SCTP_EOF)) 29668c2ecf20Sopenharmony_ci return -EINVAL; 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, info->snd_assoc_id); 29698c2ecf20Sopenharmony_ci if (!asoc && info->snd_assoc_id > SCTP_ALL_ASSOC && 29708c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 29718c2ecf20Sopenharmony_ci return -EINVAL; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci if (asoc) { 29748c2ecf20Sopenharmony_ci asoc->default_stream = info->snd_sid; 29758c2ecf20Sopenharmony_ci asoc->default_flags = info->snd_flags; 29768c2ecf20Sopenharmony_ci asoc->default_ppid = info->snd_ppid; 29778c2ecf20Sopenharmony_ci asoc->default_context = info->snd_context; 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci return 0; 29808c2ecf20Sopenharmony_ci } 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 29838c2ecf20Sopenharmony_ci info->snd_assoc_id = SCTP_FUTURE_ASSOC; 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci if (info->snd_assoc_id == SCTP_FUTURE_ASSOC || 29868c2ecf20Sopenharmony_ci info->snd_assoc_id == SCTP_ALL_ASSOC) { 29878c2ecf20Sopenharmony_ci sp->default_stream = info->snd_sid; 29888c2ecf20Sopenharmony_ci sp->default_flags = info->snd_flags; 29898c2ecf20Sopenharmony_ci sp->default_ppid = info->snd_ppid; 29908c2ecf20Sopenharmony_ci sp->default_context = info->snd_context; 29918c2ecf20Sopenharmony_ci } 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci if (info->snd_assoc_id == SCTP_CURRENT_ASSOC || 29948c2ecf20Sopenharmony_ci info->snd_assoc_id == SCTP_ALL_ASSOC) { 29958c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 29968c2ecf20Sopenharmony_ci asoc->default_stream = info->snd_sid; 29978c2ecf20Sopenharmony_ci asoc->default_flags = info->snd_flags; 29988c2ecf20Sopenharmony_ci asoc->default_ppid = info->snd_ppid; 29998c2ecf20Sopenharmony_ci asoc->default_context = info->snd_context; 30008c2ecf20Sopenharmony_ci } 30018c2ecf20Sopenharmony_ci } 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci return 0; 30048c2ecf20Sopenharmony_ci} 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci/* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 30078c2ecf20Sopenharmony_ci * 30088c2ecf20Sopenharmony_ci * Requests that the local SCTP stack use the enclosed peer address as 30098c2ecf20Sopenharmony_ci * the association primary. The enclosed address must be one of the 30108c2ecf20Sopenharmony_ci * association peer's addresses. 30118c2ecf20Sopenharmony_ci */ 30128c2ecf20Sopenharmony_cistatic int sctp_setsockopt_primary_addr(struct sock *sk, struct sctp_prim *prim, 30138c2ecf20Sopenharmony_ci unsigned int optlen) 30148c2ecf20Sopenharmony_ci{ 30158c2ecf20Sopenharmony_ci struct sctp_transport *trans; 30168c2ecf20Sopenharmony_ci struct sctp_af *af; 30178c2ecf20Sopenharmony_ci int err; 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_prim)) 30208c2ecf20Sopenharmony_ci return -EINVAL; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci /* Allow security module to validate address but need address len. */ 30238c2ecf20Sopenharmony_ci af = sctp_get_af_specific(prim->ssp_addr.ss_family); 30248c2ecf20Sopenharmony_ci if (!af) 30258c2ecf20Sopenharmony_ci return -EINVAL; 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR, 30288c2ecf20Sopenharmony_ci (struct sockaddr *)&prim->ssp_addr, 30298c2ecf20Sopenharmony_ci af->sockaddr_len); 30308c2ecf20Sopenharmony_ci if (err) 30318c2ecf20Sopenharmony_ci return err; 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci trans = sctp_addr_id2transport(sk, &prim->ssp_addr, prim->ssp_assoc_id); 30348c2ecf20Sopenharmony_ci if (!trans) 30358c2ecf20Sopenharmony_ci return -EINVAL; 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci sctp_assoc_set_primary(trans->asoc, trans); 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci return 0; 30408c2ecf20Sopenharmony_ci} 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci/* 30438c2ecf20Sopenharmony_ci * 7.1.5 SCTP_NODELAY 30448c2ecf20Sopenharmony_ci * 30458c2ecf20Sopenharmony_ci * Turn on/off any Nagle-like algorithm. This means that packets are 30468c2ecf20Sopenharmony_ci * generally sent as soon as possible and no unnecessary delays are 30478c2ecf20Sopenharmony_ci * introduced, at the cost of more packets in the network. Expects an 30488c2ecf20Sopenharmony_ci * integer boolean flag. 30498c2ecf20Sopenharmony_ci */ 30508c2ecf20Sopenharmony_cistatic int sctp_setsockopt_nodelay(struct sock *sk, int *val, 30518c2ecf20Sopenharmony_ci unsigned int optlen) 30528c2ecf20Sopenharmony_ci{ 30538c2ecf20Sopenharmony_ci if (optlen < sizeof(int)) 30548c2ecf20Sopenharmony_ci return -EINVAL; 30558c2ecf20Sopenharmony_ci sctp_sk(sk)->nodelay = (*val == 0) ? 0 : 1; 30568c2ecf20Sopenharmony_ci return 0; 30578c2ecf20Sopenharmony_ci} 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci/* 30608c2ecf20Sopenharmony_ci * 30618c2ecf20Sopenharmony_ci * 7.1.1 SCTP_RTOINFO 30628c2ecf20Sopenharmony_ci * 30638c2ecf20Sopenharmony_ci * The protocol parameters used to initialize and bound retransmission 30648c2ecf20Sopenharmony_ci * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 30658c2ecf20Sopenharmony_ci * and modify these parameters. 30668c2ecf20Sopenharmony_ci * All parameters are time values, in milliseconds. A value of 0, when 30678c2ecf20Sopenharmony_ci * modifying the parameters, indicates that the current value should not 30688c2ecf20Sopenharmony_ci * be changed. 30698c2ecf20Sopenharmony_ci * 30708c2ecf20Sopenharmony_ci */ 30718c2ecf20Sopenharmony_cistatic int sctp_setsockopt_rtoinfo(struct sock *sk, 30728c2ecf20Sopenharmony_ci struct sctp_rtoinfo *rtoinfo, 30738c2ecf20Sopenharmony_ci unsigned int optlen) 30748c2ecf20Sopenharmony_ci{ 30758c2ecf20Sopenharmony_ci struct sctp_association *asoc; 30768c2ecf20Sopenharmony_ci unsigned long rto_min, rto_max; 30778c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci if (optlen != sizeof (struct sctp_rtoinfo)) 30808c2ecf20Sopenharmony_ci return -EINVAL; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, rtoinfo->srto_assoc_id); 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci /* Set the values to the specific association */ 30858c2ecf20Sopenharmony_ci if (!asoc && rtoinfo->srto_assoc_id != SCTP_FUTURE_ASSOC && 30868c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 30878c2ecf20Sopenharmony_ci return -EINVAL; 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci rto_max = rtoinfo->srto_max; 30908c2ecf20Sopenharmony_ci rto_min = rtoinfo->srto_min; 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci if (rto_max) 30938c2ecf20Sopenharmony_ci rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max; 30948c2ecf20Sopenharmony_ci else 30958c2ecf20Sopenharmony_ci rto_max = asoc ? asoc->rto_max : sp->rtoinfo.srto_max; 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci if (rto_min) 30988c2ecf20Sopenharmony_ci rto_min = asoc ? msecs_to_jiffies(rto_min) : rto_min; 30998c2ecf20Sopenharmony_ci else 31008c2ecf20Sopenharmony_ci rto_min = asoc ? asoc->rto_min : sp->rtoinfo.srto_min; 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci if (rto_min > rto_max) 31038c2ecf20Sopenharmony_ci return -EINVAL; 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci if (asoc) { 31068c2ecf20Sopenharmony_ci if (rtoinfo->srto_initial != 0) 31078c2ecf20Sopenharmony_ci asoc->rto_initial = 31088c2ecf20Sopenharmony_ci msecs_to_jiffies(rtoinfo->srto_initial); 31098c2ecf20Sopenharmony_ci asoc->rto_max = rto_max; 31108c2ecf20Sopenharmony_ci asoc->rto_min = rto_min; 31118c2ecf20Sopenharmony_ci } else { 31128c2ecf20Sopenharmony_ci /* If there is no association or the association-id = 0 31138c2ecf20Sopenharmony_ci * set the values to the endpoint. 31148c2ecf20Sopenharmony_ci */ 31158c2ecf20Sopenharmony_ci if (rtoinfo->srto_initial != 0) 31168c2ecf20Sopenharmony_ci sp->rtoinfo.srto_initial = rtoinfo->srto_initial; 31178c2ecf20Sopenharmony_ci sp->rtoinfo.srto_max = rto_max; 31188c2ecf20Sopenharmony_ci sp->rtoinfo.srto_min = rto_min; 31198c2ecf20Sopenharmony_ci } 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci return 0; 31228c2ecf20Sopenharmony_ci} 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci/* 31258c2ecf20Sopenharmony_ci * 31268c2ecf20Sopenharmony_ci * 7.1.2 SCTP_ASSOCINFO 31278c2ecf20Sopenharmony_ci * 31288c2ecf20Sopenharmony_ci * This option is used to tune the maximum retransmission attempts 31298c2ecf20Sopenharmony_ci * of the association. 31308c2ecf20Sopenharmony_ci * Returns an error if the new association retransmission value is 31318c2ecf20Sopenharmony_ci * greater than the sum of the retransmission value of the peer. 31328c2ecf20Sopenharmony_ci * See [SCTP] for more information. 31338c2ecf20Sopenharmony_ci * 31348c2ecf20Sopenharmony_ci */ 31358c2ecf20Sopenharmony_cistatic int sctp_setsockopt_associnfo(struct sock *sk, 31368c2ecf20Sopenharmony_ci struct sctp_assocparams *assocparams, 31378c2ecf20Sopenharmony_ci unsigned int optlen) 31388c2ecf20Sopenharmony_ci{ 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci struct sctp_association *asoc; 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_assocparams)) 31438c2ecf20Sopenharmony_ci return -EINVAL; 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, assocparams->sasoc_assoc_id); 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci if (!asoc && assocparams->sasoc_assoc_id != SCTP_FUTURE_ASSOC && 31488c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 31498c2ecf20Sopenharmony_ci return -EINVAL; 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci /* Set the values to the specific association */ 31528c2ecf20Sopenharmony_ci if (asoc) { 31538c2ecf20Sopenharmony_ci if (assocparams->sasoc_asocmaxrxt != 0) { 31548c2ecf20Sopenharmony_ci __u32 path_sum = 0; 31558c2ecf20Sopenharmony_ci int paths = 0; 31568c2ecf20Sopenharmony_ci struct sctp_transport *peer_addr; 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list, 31598c2ecf20Sopenharmony_ci transports) { 31608c2ecf20Sopenharmony_ci path_sum += peer_addr->pathmaxrxt; 31618c2ecf20Sopenharmony_ci paths++; 31628c2ecf20Sopenharmony_ci } 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci /* Only validate asocmaxrxt if we have more than 31658c2ecf20Sopenharmony_ci * one path/transport. We do this because path 31668c2ecf20Sopenharmony_ci * retransmissions are only counted when we have more 31678c2ecf20Sopenharmony_ci * then one path. 31688c2ecf20Sopenharmony_ci */ 31698c2ecf20Sopenharmony_ci if (paths > 1 && 31708c2ecf20Sopenharmony_ci assocparams->sasoc_asocmaxrxt > path_sum) 31718c2ecf20Sopenharmony_ci return -EINVAL; 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci asoc->max_retrans = assocparams->sasoc_asocmaxrxt; 31748c2ecf20Sopenharmony_ci } 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci if (assocparams->sasoc_cookie_life != 0) 31778c2ecf20Sopenharmony_ci asoc->cookie_life = 31788c2ecf20Sopenharmony_ci ms_to_ktime(assocparams->sasoc_cookie_life); 31798c2ecf20Sopenharmony_ci } else { 31808c2ecf20Sopenharmony_ci /* Set the values to the endpoint */ 31818c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci if (assocparams->sasoc_asocmaxrxt != 0) 31848c2ecf20Sopenharmony_ci sp->assocparams.sasoc_asocmaxrxt = 31858c2ecf20Sopenharmony_ci assocparams->sasoc_asocmaxrxt; 31868c2ecf20Sopenharmony_ci if (assocparams->sasoc_cookie_life != 0) 31878c2ecf20Sopenharmony_ci sp->assocparams.sasoc_cookie_life = 31888c2ecf20Sopenharmony_ci assocparams->sasoc_cookie_life; 31898c2ecf20Sopenharmony_ci } 31908c2ecf20Sopenharmony_ci return 0; 31918c2ecf20Sopenharmony_ci} 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci/* 31948c2ecf20Sopenharmony_ci * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 31958c2ecf20Sopenharmony_ci * 31968c2ecf20Sopenharmony_ci * This socket option is a boolean flag which turns on or off mapped V4 31978c2ecf20Sopenharmony_ci * addresses. If this option is turned on and the socket is type 31988c2ecf20Sopenharmony_ci * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 31998c2ecf20Sopenharmony_ci * If this option is turned off, then no mapping will be done of V4 32008c2ecf20Sopenharmony_ci * addresses and a user will receive both PF_INET6 and PF_INET type 32018c2ecf20Sopenharmony_ci * addresses on the socket. 32028c2ecf20Sopenharmony_ci */ 32038c2ecf20Sopenharmony_cistatic int sctp_setsockopt_mappedv4(struct sock *sk, int *val, 32048c2ecf20Sopenharmony_ci unsigned int optlen) 32058c2ecf20Sopenharmony_ci{ 32068c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci if (optlen < sizeof(int)) 32098c2ecf20Sopenharmony_ci return -EINVAL; 32108c2ecf20Sopenharmony_ci if (*val) 32118c2ecf20Sopenharmony_ci sp->v4mapped = 1; 32128c2ecf20Sopenharmony_ci else 32138c2ecf20Sopenharmony_ci sp->v4mapped = 0; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci return 0; 32168c2ecf20Sopenharmony_ci} 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci/* 32198c2ecf20Sopenharmony_ci * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 32208c2ecf20Sopenharmony_ci * This option will get or set the maximum size to put in any outgoing 32218c2ecf20Sopenharmony_ci * SCTP DATA chunk. If a message is larger than this size it will be 32228c2ecf20Sopenharmony_ci * fragmented by SCTP into the specified size. Note that the underlying 32238c2ecf20Sopenharmony_ci * SCTP implementation may fragment into smaller sized chunks when the 32248c2ecf20Sopenharmony_ci * PMTU of the underlying association is smaller than the value set by 32258c2ecf20Sopenharmony_ci * the user. The default value for this option is '0' which indicates 32268c2ecf20Sopenharmony_ci * the user is NOT limiting fragmentation and only the PMTU will effect 32278c2ecf20Sopenharmony_ci * SCTP's choice of DATA chunk size. Note also that values set larger 32288c2ecf20Sopenharmony_ci * than the maximum size of an IP datagram will effectively let SCTP 32298c2ecf20Sopenharmony_ci * control fragmentation (i.e. the same as setting this option to 0). 32308c2ecf20Sopenharmony_ci * 32318c2ecf20Sopenharmony_ci * The following structure is used to access and modify this parameter: 32328c2ecf20Sopenharmony_ci * 32338c2ecf20Sopenharmony_ci * struct sctp_assoc_value { 32348c2ecf20Sopenharmony_ci * sctp_assoc_t assoc_id; 32358c2ecf20Sopenharmony_ci * uint32_t assoc_value; 32368c2ecf20Sopenharmony_ci * }; 32378c2ecf20Sopenharmony_ci * 32388c2ecf20Sopenharmony_ci * assoc_id: This parameter is ignored for one-to-one style sockets. 32398c2ecf20Sopenharmony_ci * For one-to-many style sockets this parameter indicates which 32408c2ecf20Sopenharmony_ci * association the user is performing an action upon. Note that if 32418c2ecf20Sopenharmony_ci * this field's value is zero then the endpoints default value is 32428c2ecf20Sopenharmony_ci * changed (effecting future associations only). 32438c2ecf20Sopenharmony_ci * assoc_value: This parameter specifies the maximum size in bytes. 32448c2ecf20Sopenharmony_ci */ 32458c2ecf20Sopenharmony_cistatic int sctp_setsockopt_maxseg(struct sock *sk, 32468c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 32478c2ecf20Sopenharmony_ci unsigned int optlen) 32488c2ecf20Sopenharmony_ci{ 32498c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 32508c2ecf20Sopenharmony_ci struct sctp_association *asoc; 32518c2ecf20Sopenharmony_ci sctp_assoc_t assoc_id; 32528c2ecf20Sopenharmony_ci int val; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci if (optlen == sizeof(int)) { 32558c2ecf20Sopenharmony_ci pr_warn_ratelimited(DEPRECATED 32568c2ecf20Sopenharmony_ci "%s (pid %d) " 32578c2ecf20Sopenharmony_ci "Use of int in maxseg socket option.\n" 32588c2ecf20Sopenharmony_ci "Use struct sctp_assoc_value instead\n", 32598c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current)); 32608c2ecf20Sopenharmony_ci assoc_id = SCTP_FUTURE_ASSOC; 32618c2ecf20Sopenharmony_ci val = *(int *)params; 32628c2ecf20Sopenharmony_ci } else if (optlen == sizeof(struct sctp_assoc_value)) { 32638c2ecf20Sopenharmony_ci assoc_id = params->assoc_id; 32648c2ecf20Sopenharmony_ci val = params->assoc_value; 32658c2ecf20Sopenharmony_ci } else { 32668c2ecf20Sopenharmony_ci return -EINVAL; 32678c2ecf20Sopenharmony_ci } 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, assoc_id); 32708c2ecf20Sopenharmony_ci if (!asoc && assoc_id != SCTP_FUTURE_ASSOC && 32718c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 32728c2ecf20Sopenharmony_ci return -EINVAL; 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci if (val) { 32758c2ecf20Sopenharmony_ci int min_len, max_len; 32768c2ecf20Sopenharmony_ci __u16 datasize = asoc ? sctp_datachk_len(&asoc->stream) : 32778c2ecf20Sopenharmony_ci sizeof(struct sctp_data_chunk); 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci min_len = sctp_min_frag_point(sp, datasize); 32808c2ecf20Sopenharmony_ci max_len = SCTP_MAX_CHUNK_LEN - datasize; 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci if (val < min_len || val > max_len) 32838c2ecf20Sopenharmony_ci return -EINVAL; 32848c2ecf20Sopenharmony_ci } 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci if (asoc) { 32878c2ecf20Sopenharmony_ci asoc->user_frag = val; 32888c2ecf20Sopenharmony_ci sctp_assoc_update_frag_point(asoc); 32898c2ecf20Sopenharmony_ci } else { 32908c2ecf20Sopenharmony_ci sp->user_frag = val; 32918c2ecf20Sopenharmony_ci } 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci return 0; 32948c2ecf20Sopenharmony_ci} 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci/* 32988c2ecf20Sopenharmony_ci * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) 32998c2ecf20Sopenharmony_ci * 33008c2ecf20Sopenharmony_ci * Requests that the peer mark the enclosed address as the association 33018c2ecf20Sopenharmony_ci * primary. The enclosed address must be one of the association's 33028c2ecf20Sopenharmony_ci * locally bound addresses. The following structure is used to make a 33038c2ecf20Sopenharmony_ci * set primary request: 33048c2ecf20Sopenharmony_ci */ 33058c2ecf20Sopenharmony_cistatic int sctp_setsockopt_peer_primary_addr(struct sock *sk, 33068c2ecf20Sopenharmony_ci struct sctp_setpeerprim *prim, 33078c2ecf20Sopenharmony_ci unsigned int optlen) 33088c2ecf20Sopenharmony_ci{ 33098c2ecf20Sopenharmony_ci struct sctp_sock *sp; 33108c2ecf20Sopenharmony_ci struct sctp_association *asoc = NULL; 33118c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 33128c2ecf20Sopenharmony_ci struct sctp_af *af; 33138c2ecf20Sopenharmony_ci int err; 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci sp = sctp_sk(sk); 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci if (!sp->ep->asconf_enable) 33188c2ecf20Sopenharmony_ci return -EPERM; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_setpeerprim)) 33218c2ecf20Sopenharmony_ci return -EINVAL; 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, prim->sspp_assoc_id); 33248c2ecf20Sopenharmony_ci if (!asoc) 33258c2ecf20Sopenharmony_ci return -EINVAL; 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci if (!asoc->peer.asconf_capable) 33288c2ecf20Sopenharmony_ci return -EPERM; 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci if (asoc->peer.addip_disabled_mask & SCTP_PARAM_SET_PRIMARY) 33318c2ecf20Sopenharmony_ci return -EPERM; 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_ci if (!sctp_state(asoc, ESTABLISHED)) 33348c2ecf20Sopenharmony_ci return -ENOTCONN; 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci af = sctp_get_af_specific(prim->sspp_addr.ss_family); 33378c2ecf20Sopenharmony_ci if (!af) 33388c2ecf20Sopenharmony_ci return -EINVAL; 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci if (!af->addr_valid((union sctp_addr *)&prim->sspp_addr, sp, NULL)) 33418c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim->sspp_addr)) 33448c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_ci /* Allow security module to validate address. */ 33478c2ecf20Sopenharmony_ci err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR, 33488c2ecf20Sopenharmony_ci (struct sockaddr *)&prim->sspp_addr, 33498c2ecf20Sopenharmony_ci af->sockaddr_len); 33508c2ecf20Sopenharmony_ci if (err) 33518c2ecf20Sopenharmony_ci return err; 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_ci /* Create an ASCONF chunk with SET_PRIMARY parameter */ 33548c2ecf20Sopenharmony_ci chunk = sctp_make_asconf_set_prim(asoc, 33558c2ecf20Sopenharmony_ci (union sctp_addr *)&prim->sspp_addr); 33568c2ecf20Sopenharmony_ci if (!chunk) 33578c2ecf20Sopenharmony_ci return -ENOMEM; 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci err = sctp_send_asconf(asoc, chunk); 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci pr_debug("%s: we set peer primary addr primitively\n", __func__); 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci return err; 33648c2ecf20Sopenharmony_ci} 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_cistatic int sctp_setsockopt_adaptation_layer(struct sock *sk, 33678c2ecf20Sopenharmony_ci struct sctp_setadaptation *adapt, 33688c2ecf20Sopenharmony_ci unsigned int optlen) 33698c2ecf20Sopenharmony_ci{ 33708c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_setadaptation)) 33718c2ecf20Sopenharmony_ci return -EINVAL; 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci sctp_sk(sk)->adaptation_ind = adapt->ssb_adaptation_ind; 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci return 0; 33768c2ecf20Sopenharmony_ci} 33778c2ecf20Sopenharmony_ci 33788c2ecf20Sopenharmony_ci/* 33798c2ecf20Sopenharmony_ci * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 33808c2ecf20Sopenharmony_ci * 33818c2ecf20Sopenharmony_ci * The context field in the sctp_sndrcvinfo structure is normally only 33828c2ecf20Sopenharmony_ci * used when a failed message is retrieved holding the value that was 33838c2ecf20Sopenharmony_ci * sent down on the actual send call. This option allows the setting of 33848c2ecf20Sopenharmony_ci * a default context on an association basis that will be received on 33858c2ecf20Sopenharmony_ci * reading messages from the peer. This is especially helpful in the 33868c2ecf20Sopenharmony_ci * one-2-many model for an application to keep some reference to an 33878c2ecf20Sopenharmony_ci * internal state machine that is processing messages on the 33888c2ecf20Sopenharmony_ci * association. Note that the setting of this value only effects 33898c2ecf20Sopenharmony_ci * received messages from the peer and does not effect the value that is 33908c2ecf20Sopenharmony_ci * saved with outbound messages. 33918c2ecf20Sopenharmony_ci */ 33928c2ecf20Sopenharmony_cistatic int sctp_setsockopt_context(struct sock *sk, 33938c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 33948c2ecf20Sopenharmony_ci unsigned int optlen) 33958c2ecf20Sopenharmony_ci{ 33968c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 33978c2ecf20Sopenharmony_ci struct sctp_association *asoc; 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_assoc_value)) 34008c2ecf20Sopenharmony_ci return -EINVAL; 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 34038c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id > SCTP_ALL_ASSOC && 34048c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 34058c2ecf20Sopenharmony_ci return -EINVAL; 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_ci if (asoc) { 34088c2ecf20Sopenharmony_ci asoc->default_rcv_context = params->assoc_value; 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci return 0; 34118c2ecf20Sopenharmony_ci } 34128c2ecf20Sopenharmony_ci 34138c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 34148c2ecf20Sopenharmony_ci params->assoc_id = SCTP_FUTURE_ASSOC; 34158c2ecf20Sopenharmony_ci 34168c2ecf20Sopenharmony_ci if (params->assoc_id == SCTP_FUTURE_ASSOC || 34178c2ecf20Sopenharmony_ci params->assoc_id == SCTP_ALL_ASSOC) 34188c2ecf20Sopenharmony_ci sp->default_rcv_context = params->assoc_value; 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci if (params->assoc_id == SCTP_CURRENT_ASSOC || 34218c2ecf20Sopenharmony_ci params->assoc_id == SCTP_ALL_ASSOC) 34228c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sp->ep->asocs, asocs) 34238c2ecf20Sopenharmony_ci asoc->default_rcv_context = params->assoc_value; 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci return 0; 34268c2ecf20Sopenharmony_ci} 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci/* 34298c2ecf20Sopenharmony_ci * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 34308c2ecf20Sopenharmony_ci * 34318c2ecf20Sopenharmony_ci * This options will at a minimum specify if the implementation is doing 34328c2ecf20Sopenharmony_ci * fragmented interleave. Fragmented interleave, for a one to many 34338c2ecf20Sopenharmony_ci * socket, is when subsequent calls to receive a message may return 34348c2ecf20Sopenharmony_ci * parts of messages from different associations. Some implementations 34358c2ecf20Sopenharmony_ci * may allow you to turn this value on or off. If so, when turned off, 34368c2ecf20Sopenharmony_ci * no fragment interleave will occur (which will cause a head of line 34378c2ecf20Sopenharmony_ci * blocking amongst multiple associations sharing the same one to many 34388c2ecf20Sopenharmony_ci * socket). When this option is turned on, then each receive call may 34398c2ecf20Sopenharmony_ci * come from a different association (thus the user must receive data 34408c2ecf20Sopenharmony_ci * with the extended calls (e.g. sctp_recvmsg) to keep track of which 34418c2ecf20Sopenharmony_ci * association each receive belongs to. 34428c2ecf20Sopenharmony_ci * 34438c2ecf20Sopenharmony_ci * This option takes a boolean value. A non-zero value indicates that 34448c2ecf20Sopenharmony_ci * fragmented interleave is on. A value of zero indicates that 34458c2ecf20Sopenharmony_ci * fragmented interleave is off. 34468c2ecf20Sopenharmony_ci * 34478c2ecf20Sopenharmony_ci * Note that it is important that an implementation that allows this 34488c2ecf20Sopenharmony_ci * option to be turned on, have it off by default. Otherwise an unaware 34498c2ecf20Sopenharmony_ci * application using the one to many model may become confused and act 34508c2ecf20Sopenharmony_ci * incorrectly. 34518c2ecf20Sopenharmony_ci */ 34528c2ecf20Sopenharmony_cistatic int sctp_setsockopt_fragment_interleave(struct sock *sk, int *val, 34538c2ecf20Sopenharmony_ci unsigned int optlen) 34548c2ecf20Sopenharmony_ci{ 34558c2ecf20Sopenharmony_ci if (optlen != sizeof(int)) 34568c2ecf20Sopenharmony_ci return -EINVAL; 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci sctp_sk(sk)->frag_interleave = !!*val; 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci if (!sctp_sk(sk)->frag_interleave) 34618c2ecf20Sopenharmony_ci sctp_sk(sk)->ep->intl_enable = 0; 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ci return 0; 34648c2ecf20Sopenharmony_ci} 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci/* 34678c2ecf20Sopenharmony_ci * 8.1.21. Set or Get the SCTP Partial Delivery Point 34688c2ecf20Sopenharmony_ci * (SCTP_PARTIAL_DELIVERY_POINT) 34698c2ecf20Sopenharmony_ci * 34708c2ecf20Sopenharmony_ci * This option will set or get the SCTP partial delivery point. This 34718c2ecf20Sopenharmony_ci * point is the size of a message where the partial delivery API will be 34728c2ecf20Sopenharmony_ci * invoked to help free up rwnd space for the peer. Setting this to a 34738c2ecf20Sopenharmony_ci * lower value will cause partial deliveries to happen more often. The 34748c2ecf20Sopenharmony_ci * calls argument is an integer that sets or gets the partial delivery 34758c2ecf20Sopenharmony_ci * point. Note also that the call will fail if the user attempts to set 34768c2ecf20Sopenharmony_ci * this value larger than the socket receive buffer size. 34778c2ecf20Sopenharmony_ci * 34788c2ecf20Sopenharmony_ci * Note that any single message having a length smaller than or equal to 34798c2ecf20Sopenharmony_ci * the SCTP partial delivery point will be delivered in one single read 34808c2ecf20Sopenharmony_ci * call as long as the user provided buffer is large enough to hold the 34818c2ecf20Sopenharmony_ci * message. 34828c2ecf20Sopenharmony_ci */ 34838c2ecf20Sopenharmony_cistatic int sctp_setsockopt_partial_delivery_point(struct sock *sk, u32 *val, 34848c2ecf20Sopenharmony_ci unsigned int optlen) 34858c2ecf20Sopenharmony_ci{ 34868c2ecf20Sopenharmony_ci if (optlen != sizeof(u32)) 34878c2ecf20Sopenharmony_ci return -EINVAL; 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_ci /* Note: We double the receive buffer from what the user sets 34908c2ecf20Sopenharmony_ci * it to be, also initial rwnd is based on rcvbuf/2. 34918c2ecf20Sopenharmony_ci */ 34928c2ecf20Sopenharmony_ci if (*val > (sk->sk_rcvbuf >> 1)) 34938c2ecf20Sopenharmony_ci return -EINVAL; 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_ci sctp_sk(sk)->pd_point = *val; 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci return 0; /* is this the right error code? */ 34988c2ecf20Sopenharmony_ci} 34998c2ecf20Sopenharmony_ci 35008c2ecf20Sopenharmony_ci/* 35018c2ecf20Sopenharmony_ci * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 35028c2ecf20Sopenharmony_ci * 35038c2ecf20Sopenharmony_ci * This option will allow a user to change the maximum burst of packets 35048c2ecf20Sopenharmony_ci * that can be emitted by this association. Note that the default value 35058c2ecf20Sopenharmony_ci * is 4, and some implementations may restrict this setting so that it 35068c2ecf20Sopenharmony_ci * can only be lowered. 35078c2ecf20Sopenharmony_ci * 35088c2ecf20Sopenharmony_ci * NOTE: This text doesn't seem right. Do this on a socket basis with 35098c2ecf20Sopenharmony_ci * future associations inheriting the socket value. 35108c2ecf20Sopenharmony_ci */ 35118c2ecf20Sopenharmony_cistatic int sctp_setsockopt_maxburst(struct sock *sk, 35128c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 35138c2ecf20Sopenharmony_ci unsigned int optlen) 35148c2ecf20Sopenharmony_ci{ 35158c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 35168c2ecf20Sopenharmony_ci struct sctp_association *asoc; 35178c2ecf20Sopenharmony_ci sctp_assoc_t assoc_id; 35188c2ecf20Sopenharmony_ci u32 assoc_value; 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_ci if (optlen == sizeof(int)) { 35218c2ecf20Sopenharmony_ci pr_warn_ratelimited(DEPRECATED 35228c2ecf20Sopenharmony_ci "%s (pid %d) " 35238c2ecf20Sopenharmony_ci "Use of int in max_burst socket option deprecated.\n" 35248c2ecf20Sopenharmony_ci "Use struct sctp_assoc_value instead\n", 35258c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current)); 35268c2ecf20Sopenharmony_ci assoc_id = SCTP_FUTURE_ASSOC; 35278c2ecf20Sopenharmony_ci assoc_value = *((int *)params); 35288c2ecf20Sopenharmony_ci } else if (optlen == sizeof(struct sctp_assoc_value)) { 35298c2ecf20Sopenharmony_ci assoc_id = params->assoc_id; 35308c2ecf20Sopenharmony_ci assoc_value = params->assoc_value; 35318c2ecf20Sopenharmony_ci } else 35328c2ecf20Sopenharmony_ci return -EINVAL; 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, assoc_id); 35358c2ecf20Sopenharmony_ci if (!asoc && assoc_id > SCTP_ALL_ASSOC && sctp_style(sk, UDP)) 35368c2ecf20Sopenharmony_ci return -EINVAL; 35378c2ecf20Sopenharmony_ci 35388c2ecf20Sopenharmony_ci if (asoc) { 35398c2ecf20Sopenharmony_ci asoc->max_burst = assoc_value; 35408c2ecf20Sopenharmony_ci 35418c2ecf20Sopenharmony_ci return 0; 35428c2ecf20Sopenharmony_ci } 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 35458c2ecf20Sopenharmony_ci assoc_id = SCTP_FUTURE_ASSOC; 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci if (assoc_id == SCTP_FUTURE_ASSOC || assoc_id == SCTP_ALL_ASSOC) 35488c2ecf20Sopenharmony_ci sp->max_burst = assoc_value; 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci if (assoc_id == SCTP_CURRENT_ASSOC || assoc_id == SCTP_ALL_ASSOC) 35518c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sp->ep->asocs, asocs) 35528c2ecf20Sopenharmony_ci asoc->max_burst = assoc_value; 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci return 0; 35558c2ecf20Sopenharmony_ci} 35568c2ecf20Sopenharmony_ci 35578c2ecf20Sopenharmony_ci/* 35588c2ecf20Sopenharmony_ci * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) 35598c2ecf20Sopenharmony_ci * 35608c2ecf20Sopenharmony_ci * This set option adds a chunk type that the user is requesting to be 35618c2ecf20Sopenharmony_ci * received only in an authenticated way. Changes to the list of chunks 35628c2ecf20Sopenharmony_ci * will only effect future associations on the socket. 35638c2ecf20Sopenharmony_ci */ 35648c2ecf20Sopenharmony_cistatic int sctp_setsockopt_auth_chunk(struct sock *sk, 35658c2ecf20Sopenharmony_ci struct sctp_authchunk *val, 35668c2ecf20Sopenharmony_ci unsigned int optlen) 35678c2ecf20Sopenharmony_ci{ 35688c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci if (!ep->auth_enable) 35718c2ecf20Sopenharmony_ci return -EACCES; 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_authchunk)) 35748c2ecf20Sopenharmony_ci return -EINVAL; 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci switch (val->sauth_chunk) { 35778c2ecf20Sopenharmony_ci case SCTP_CID_INIT: 35788c2ecf20Sopenharmony_ci case SCTP_CID_INIT_ACK: 35798c2ecf20Sopenharmony_ci case SCTP_CID_SHUTDOWN_COMPLETE: 35808c2ecf20Sopenharmony_ci case SCTP_CID_AUTH: 35818c2ecf20Sopenharmony_ci return -EINVAL; 35828c2ecf20Sopenharmony_ci } 35838c2ecf20Sopenharmony_ci 35848c2ecf20Sopenharmony_ci /* add this chunk id to the endpoint */ 35858c2ecf20Sopenharmony_ci return sctp_auth_ep_add_chunkid(ep, val->sauth_chunk); 35868c2ecf20Sopenharmony_ci} 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci/* 35898c2ecf20Sopenharmony_ci * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) 35908c2ecf20Sopenharmony_ci * 35918c2ecf20Sopenharmony_ci * This option gets or sets the list of HMAC algorithms that the local 35928c2ecf20Sopenharmony_ci * endpoint requires the peer to use. 35938c2ecf20Sopenharmony_ci */ 35948c2ecf20Sopenharmony_cistatic int sctp_setsockopt_hmac_ident(struct sock *sk, 35958c2ecf20Sopenharmony_ci struct sctp_hmacalgo *hmacs, 35968c2ecf20Sopenharmony_ci unsigned int optlen) 35978c2ecf20Sopenharmony_ci{ 35988c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 35998c2ecf20Sopenharmony_ci u32 idents; 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_ci if (!ep->auth_enable) 36028c2ecf20Sopenharmony_ci return -EACCES; 36038c2ecf20Sopenharmony_ci 36048c2ecf20Sopenharmony_ci if (optlen < sizeof(struct sctp_hmacalgo)) 36058c2ecf20Sopenharmony_ci return -EINVAL; 36068c2ecf20Sopenharmony_ci optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) + 36078c2ecf20Sopenharmony_ci SCTP_AUTH_NUM_HMACS * sizeof(u16)); 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ci idents = hmacs->shmac_num_idents; 36108c2ecf20Sopenharmony_ci if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || 36118c2ecf20Sopenharmony_ci (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) 36128c2ecf20Sopenharmony_ci return -EINVAL; 36138c2ecf20Sopenharmony_ci 36148c2ecf20Sopenharmony_ci return sctp_auth_ep_set_hmacs(ep, hmacs); 36158c2ecf20Sopenharmony_ci} 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci/* 36188c2ecf20Sopenharmony_ci * 7.1.20. Set a shared key (SCTP_AUTH_KEY) 36198c2ecf20Sopenharmony_ci * 36208c2ecf20Sopenharmony_ci * This option will set a shared secret key which is used to build an 36218c2ecf20Sopenharmony_ci * association shared key. 36228c2ecf20Sopenharmony_ci */ 36238c2ecf20Sopenharmony_cistatic int sctp_setsockopt_auth_key(struct sock *sk, 36248c2ecf20Sopenharmony_ci struct sctp_authkey *authkey, 36258c2ecf20Sopenharmony_ci unsigned int optlen) 36268c2ecf20Sopenharmony_ci{ 36278c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 36288c2ecf20Sopenharmony_ci struct sctp_association *asoc; 36298c2ecf20Sopenharmony_ci int ret = -EINVAL; 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci if (optlen <= sizeof(struct sctp_authkey)) 36328c2ecf20Sopenharmony_ci return -EINVAL; 36338c2ecf20Sopenharmony_ci /* authkey->sca_keylength is u16, so optlen can't be bigger than 36348c2ecf20Sopenharmony_ci * this. 36358c2ecf20Sopenharmony_ci */ 36368c2ecf20Sopenharmony_ci optlen = min_t(unsigned int, optlen, USHRT_MAX + sizeof(*authkey)); 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_ci if (authkey->sca_keylength > optlen - sizeof(*authkey)) 36398c2ecf20Sopenharmony_ci goto out; 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); 36428c2ecf20Sopenharmony_ci if (!asoc && authkey->sca_assoc_id > SCTP_ALL_ASSOC && 36438c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 36448c2ecf20Sopenharmony_ci goto out; 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci if (asoc) { 36478c2ecf20Sopenharmony_ci ret = sctp_auth_set_key(ep, asoc, authkey); 36488c2ecf20Sopenharmony_ci goto out; 36498c2ecf20Sopenharmony_ci } 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 36528c2ecf20Sopenharmony_ci authkey->sca_assoc_id = SCTP_FUTURE_ASSOC; 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ci if (authkey->sca_assoc_id == SCTP_FUTURE_ASSOC || 36558c2ecf20Sopenharmony_ci authkey->sca_assoc_id == SCTP_ALL_ASSOC) { 36568c2ecf20Sopenharmony_ci ret = sctp_auth_set_key(ep, asoc, authkey); 36578c2ecf20Sopenharmony_ci if (ret) 36588c2ecf20Sopenharmony_ci goto out; 36598c2ecf20Sopenharmony_ci } 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci ret = 0; 36628c2ecf20Sopenharmony_ci 36638c2ecf20Sopenharmony_ci if (authkey->sca_assoc_id == SCTP_CURRENT_ASSOC || 36648c2ecf20Sopenharmony_ci authkey->sca_assoc_id == SCTP_ALL_ASSOC) { 36658c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &ep->asocs, asocs) { 36668c2ecf20Sopenharmony_ci int res = sctp_auth_set_key(ep, asoc, authkey); 36678c2ecf20Sopenharmony_ci 36688c2ecf20Sopenharmony_ci if (res && !ret) 36698c2ecf20Sopenharmony_ci ret = res; 36708c2ecf20Sopenharmony_ci } 36718c2ecf20Sopenharmony_ci } 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ciout: 36748c2ecf20Sopenharmony_ci memzero_explicit(authkey, optlen); 36758c2ecf20Sopenharmony_ci return ret; 36768c2ecf20Sopenharmony_ci} 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci/* 36798c2ecf20Sopenharmony_ci * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) 36808c2ecf20Sopenharmony_ci * 36818c2ecf20Sopenharmony_ci * This option will get or set the active shared key to be used to build 36828c2ecf20Sopenharmony_ci * the association shared key. 36838c2ecf20Sopenharmony_ci */ 36848c2ecf20Sopenharmony_cistatic int sctp_setsockopt_active_key(struct sock *sk, 36858c2ecf20Sopenharmony_ci struct sctp_authkeyid *val, 36868c2ecf20Sopenharmony_ci unsigned int optlen) 36878c2ecf20Sopenharmony_ci{ 36888c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 36898c2ecf20Sopenharmony_ci struct sctp_association *asoc; 36908c2ecf20Sopenharmony_ci int ret = 0; 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_authkeyid)) 36938c2ecf20Sopenharmony_ci return -EINVAL; 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, val->scact_assoc_id); 36968c2ecf20Sopenharmony_ci if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC && 36978c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 36988c2ecf20Sopenharmony_ci return -EINVAL; 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_ci if (asoc) 37018c2ecf20Sopenharmony_ci return sctp_auth_set_active_key(ep, asoc, val->scact_keynumber); 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 37048c2ecf20Sopenharmony_ci val->scact_assoc_id = SCTP_FUTURE_ASSOC; 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci if (val->scact_assoc_id == SCTP_FUTURE_ASSOC || 37078c2ecf20Sopenharmony_ci val->scact_assoc_id == SCTP_ALL_ASSOC) { 37088c2ecf20Sopenharmony_ci ret = sctp_auth_set_active_key(ep, asoc, val->scact_keynumber); 37098c2ecf20Sopenharmony_ci if (ret) 37108c2ecf20Sopenharmony_ci return ret; 37118c2ecf20Sopenharmony_ci } 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci if (val->scact_assoc_id == SCTP_CURRENT_ASSOC || 37148c2ecf20Sopenharmony_ci val->scact_assoc_id == SCTP_ALL_ASSOC) { 37158c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &ep->asocs, asocs) { 37168c2ecf20Sopenharmony_ci int res = sctp_auth_set_active_key(ep, asoc, 37178c2ecf20Sopenharmony_ci val->scact_keynumber); 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci if (res && !ret) 37208c2ecf20Sopenharmony_ci ret = res; 37218c2ecf20Sopenharmony_ci } 37228c2ecf20Sopenharmony_ci } 37238c2ecf20Sopenharmony_ci 37248c2ecf20Sopenharmony_ci return ret; 37258c2ecf20Sopenharmony_ci} 37268c2ecf20Sopenharmony_ci 37278c2ecf20Sopenharmony_ci/* 37288c2ecf20Sopenharmony_ci * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY) 37298c2ecf20Sopenharmony_ci * 37308c2ecf20Sopenharmony_ci * This set option will delete a shared secret key from use. 37318c2ecf20Sopenharmony_ci */ 37328c2ecf20Sopenharmony_cistatic int sctp_setsockopt_del_key(struct sock *sk, 37338c2ecf20Sopenharmony_ci struct sctp_authkeyid *val, 37348c2ecf20Sopenharmony_ci unsigned int optlen) 37358c2ecf20Sopenharmony_ci{ 37368c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 37378c2ecf20Sopenharmony_ci struct sctp_association *asoc; 37388c2ecf20Sopenharmony_ci int ret = 0; 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_authkeyid)) 37418c2ecf20Sopenharmony_ci return -EINVAL; 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, val->scact_assoc_id); 37448c2ecf20Sopenharmony_ci if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC && 37458c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 37468c2ecf20Sopenharmony_ci return -EINVAL; 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci if (asoc) 37498c2ecf20Sopenharmony_ci return sctp_auth_del_key_id(ep, asoc, val->scact_keynumber); 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 37528c2ecf20Sopenharmony_ci val->scact_assoc_id = SCTP_FUTURE_ASSOC; 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci if (val->scact_assoc_id == SCTP_FUTURE_ASSOC || 37558c2ecf20Sopenharmony_ci val->scact_assoc_id == SCTP_ALL_ASSOC) { 37568c2ecf20Sopenharmony_ci ret = sctp_auth_del_key_id(ep, asoc, val->scact_keynumber); 37578c2ecf20Sopenharmony_ci if (ret) 37588c2ecf20Sopenharmony_ci return ret; 37598c2ecf20Sopenharmony_ci } 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ci if (val->scact_assoc_id == SCTP_CURRENT_ASSOC || 37628c2ecf20Sopenharmony_ci val->scact_assoc_id == SCTP_ALL_ASSOC) { 37638c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &ep->asocs, asocs) { 37648c2ecf20Sopenharmony_ci int res = sctp_auth_del_key_id(ep, asoc, 37658c2ecf20Sopenharmony_ci val->scact_keynumber); 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci if (res && !ret) 37688c2ecf20Sopenharmony_ci ret = res; 37698c2ecf20Sopenharmony_ci } 37708c2ecf20Sopenharmony_ci } 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci return ret; 37738c2ecf20Sopenharmony_ci} 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_ci/* 37768c2ecf20Sopenharmony_ci * 8.3.4 Deactivate a Shared Key (SCTP_AUTH_DEACTIVATE_KEY) 37778c2ecf20Sopenharmony_ci * 37788c2ecf20Sopenharmony_ci * This set option will deactivate a shared secret key. 37798c2ecf20Sopenharmony_ci */ 37808c2ecf20Sopenharmony_cistatic int sctp_setsockopt_deactivate_key(struct sock *sk, 37818c2ecf20Sopenharmony_ci struct sctp_authkeyid *val, 37828c2ecf20Sopenharmony_ci unsigned int optlen) 37838c2ecf20Sopenharmony_ci{ 37848c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 37858c2ecf20Sopenharmony_ci struct sctp_association *asoc; 37868c2ecf20Sopenharmony_ci int ret = 0; 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_ci if (optlen != sizeof(struct sctp_authkeyid)) 37898c2ecf20Sopenharmony_ci return -EINVAL; 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, val->scact_assoc_id); 37928c2ecf20Sopenharmony_ci if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC && 37938c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 37948c2ecf20Sopenharmony_ci return -EINVAL; 37958c2ecf20Sopenharmony_ci 37968c2ecf20Sopenharmony_ci if (asoc) 37978c2ecf20Sopenharmony_ci return sctp_auth_deact_key_id(ep, asoc, val->scact_keynumber); 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 38008c2ecf20Sopenharmony_ci val->scact_assoc_id = SCTP_FUTURE_ASSOC; 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci if (val->scact_assoc_id == SCTP_FUTURE_ASSOC || 38038c2ecf20Sopenharmony_ci val->scact_assoc_id == SCTP_ALL_ASSOC) { 38048c2ecf20Sopenharmony_ci ret = sctp_auth_deact_key_id(ep, asoc, val->scact_keynumber); 38058c2ecf20Sopenharmony_ci if (ret) 38068c2ecf20Sopenharmony_ci return ret; 38078c2ecf20Sopenharmony_ci } 38088c2ecf20Sopenharmony_ci 38098c2ecf20Sopenharmony_ci if (val->scact_assoc_id == SCTP_CURRENT_ASSOC || 38108c2ecf20Sopenharmony_ci val->scact_assoc_id == SCTP_ALL_ASSOC) { 38118c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &ep->asocs, asocs) { 38128c2ecf20Sopenharmony_ci int res = sctp_auth_deact_key_id(ep, asoc, 38138c2ecf20Sopenharmony_ci val->scact_keynumber); 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci if (res && !ret) 38168c2ecf20Sopenharmony_ci ret = res; 38178c2ecf20Sopenharmony_ci } 38188c2ecf20Sopenharmony_ci } 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_ci return ret; 38218c2ecf20Sopenharmony_ci} 38228c2ecf20Sopenharmony_ci 38238c2ecf20Sopenharmony_ci/* 38248c2ecf20Sopenharmony_ci * 8.1.23 SCTP_AUTO_ASCONF 38258c2ecf20Sopenharmony_ci * 38268c2ecf20Sopenharmony_ci * This option will enable or disable the use of the automatic generation of 38278c2ecf20Sopenharmony_ci * ASCONF chunks to add and delete addresses to an existing association. Note 38288c2ecf20Sopenharmony_ci * that this option has two caveats namely: a) it only affects sockets that 38298c2ecf20Sopenharmony_ci * are bound to all addresses available to the SCTP stack, and b) the system 38308c2ecf20Sopenharmony_ci * administrator may have an overriding control that turns the ASCONF feature 38318c2ecf20Sopenharmony_ci * off no matter what setting the socket option may have. 38328c2ecf20Sopenharmony_ci * This option expects an integer boolean flag, where a non-zero value turns on 38338c2ecf20Sopenharmony_ci * the option, and a zero value turns off the option. 38348c2ecf20Sopenharmony_ci * Note. In this implementation, socket operation overrides default parameter 38358c2ecf20Sopenharmony_ci * being set by sysctl as well as FreeBSD implementation 38368c2ecf20Sopenharmony_ci */ 38378c2ecf20Sopenharmony_cistatic int sctp_setsockopt_auto_asconf(struct sock *sk, int *val, 38388c2ecf20Sopenharmony_ci unsigned int optlen) 38398c2ecf20Sopenharmony_ci{ 38408c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_ci if (optlen < sizeof(int)) 38438c2ecf20Sopenharmony_ci return -EINVAL; 38448c2ecf20Sopenharmony_ci if (!sctp_is_ep_boundall(sk) && *val) 38458c2ecf20Sopenharmony_ci return -EINVAL; 38468c2ecf20Sopenharmony_ci if ((*val && sp->do_auto_asconf) || (!*val && !sp->do_auto_asconf)) 38478c2ecf20Sopenharmony_ci return 0; 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock); 38508c2ecf20Sopenharmony_ci if (*val == 0 && sp->do_auto_asconf) { 38518c2ecf20Sopenharmony_ci list_del(&sp->auto_asconf_list); 38528c2ecf20Sopenharmony_ci sp->do_auto_asconf = 0; 38538c2ecf20Sopenharmony_ci } else if (*val && !sp->do_auto_asconf) { 38548c2ecf20Sopenharmony_ci list_add_tail(&sp->auto_asconf_list, 38558c2ecf20Sopenharmony_ci &sock_net(sk)->sctp.auto_asconf_splist); 38568c2ecf20Sopenharmony_ci sp->do_auto_asconf = 1; 38578c2ecf20Sopenharmony_ci } 38588c2ecf20Sopenharmony_ci spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock); 38598c2ecf20Sopenharmony_ci return 0; 38608c2ecf20Sopenharmony_ci} 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_ci/* 38638c2ecf20Sopenharmony_ci * SCTP_PEER_ADDR_THLDS 38648c2ecf20Sopenharmony_ci * 38658c2ecf20Sopenharmony_ci * This option allows us to alter the partially failed threshold for one or all 38668c2ecf20Sopenharmony_ci * transports in an association. See Section 6.1 of: 38678c2ecf20Sopenharmony_ci * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 38688c2ecf20Sopenharmony_ci */ 38698c2ecf20Sopenharmony_cistatic int sctp_setsockopt_paddr_thresholds(struct sock *sk, 38708c2ecf20Sopenharmony_ci struct sctp_paddrthlds_v2 *val, 38718c2ecf20Sopenharmony_ci unsigned int optlen, bool v2) 38728c2ecf20Sopenharmony_ci{ 38738c2ecf20Sopenharmony_ci struct sctp_transport *trans; 38748c2ecf20Sopenharmony_ci struct sctp_association *asoc; 38758c2ecf20Sopenharmony_ci int len; 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci len = v2 ? sizeof(*val) : sizeof(struct sctp_paddrthlds); 38788c2ecf20Sopenharmony_ci if (optlen < len) 38798c2ecf20Sopenharmony_ci return -EINVAL; 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci if (v2 && val->spt_pathpfthld > val->spt_pathcpthld) 38828c2ecf20Sopenharmony_ci return -EINVAL; 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci if (!sctp_is_any(sk, (const union sctp_addr *)&val->spt_address)) { 38858c2ecf20Sopenharmony_ci trans = sctp_addr_id2transport(sk, &val->spt_address, 38868c2ecf20Sopenharmony_ci val->spt_assoc_id); 38878c2ecf20Sopenharmony_ci if (!trans) 38888c2ecf20Sopenharmony_ci return -ENOENT; 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_ci if (val->spt_pathmaxrxt) 38918c2ecf20Sopenharmony_ci trans->pathmaxrxt = val->spt_pathmaxrxt; 38928c2ecf20Sopenharmony_ci if (v2) 38938c2ecf20Sopenharmony_ci trans->ps_retrans = val->spt_pathcpthld; 38948c2ecf20Sopenharmony_ci trans->pf_retrans = val->spt_pathpfthld; 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_ci return 0; 38978c2ecf20Sopenharmony_ci } 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, val->spt_assoc_id); 39008c2ecf20Sopenharmony_ci if (!asoc && val->spt_assoc_id != SCTP_FUTURE_ASSOC && 39018c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 39028c2ecf20Sopenharmony_ci return -EINVAL; 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_ci if (asoc) { 39058c2ecf20Sopenharmony_ci list_for_each_entry(trans, &asoc->peer.transport_addr_list, 39068c2ecf20Sopenharmony_ci transports) { 39078c2ecf20Sopenharmony_ci if (val->spt_pathmaxrxt) 39088c2ecf20Sopenharmony_ci trans->pathmaxrxt = val->spt_pathmaxrxt; 39098c2ecf20Sopenharmony_ci if (v2) 39108c2ecf20Sopenharmony_ci trans->ps_retrans = val->spt_pathcpthld; 39118c2ecf20Sopenharmony_ci trans->pf_retrans = val->spt_pathpfthld; 39128c2ecf20Sopenharmony_ci } 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci if (val->spt_pathmaxrxt) 39158c2ecf20Sopenharmony_ci asoc->pathmaxrxt = val->spt_pathmaxrxt; 39168c2ecf20Sopenharmony_ci if (v2) 39178c2ecf20Sopenharmony_ci asoc->ps_retrans = val->spt_pathcpthld; 39188c2ecf20Sopenharmony_ci asoc->pf_retrans = val->spt_pathpfthld; 39198c2ecf20Sopenharmony_ci } else { 39208c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci if (val->spt_pathmaxrxt) 39238c2ecf20Sopenharmony_ci sp->pathmaxrxt = val->spt_pathmaxrxt; 39248c2ecf20Sopenharmony_ci if (v2) 39258c2ecf20Sopenharmony_ci sp->ps_retrans = val->spt_pathcpthld; 39268c2ecf20Sopenharmony_ci sp->pf_retrans = val->spt_pathpfthld; 39278c2ecf20Sopenharmony_ci } 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci return 0; 39308c2ecf20Sopenharmony_ci} 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_cistatic int sctp_setsockopt_recvrcvinfo(struct sock *sk, int *val, 39338c2ecf20Sopenharmony_ci unsigned int optlen) 39348c2ecf20Sopenharmony_ci{ 39358c2ecf20Sopenharmony_ci if (optlen < sizeof(int)) 39368c2ecf20Sopenharmony_ci return -EINVAL; 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci sctp_sk(sk)->recvrcvinfo = (*val == 0) ? 0 : 1; 39398c2ecf20Sopenharmony_ci 39408c2ecf20Sopenharmony_ci return 0; 39418c2ecf20Sopenharmony_ci} 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_cistatic int sctp_setsockopt_recvnxtinfo(struct sock *sk, int *val, 39448c2ecf20Sopenharmony_ci unsigned int optlen) 39458c2ecf20Sopenharmony_ci{ 39468c2ecf20Sopenharmony_ci if (optlen < sizeof(int)) 39478c2ecf20Sopenharmony_ci return -EINVAL; 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci sctp_sk(sk)->recvnxtinfo = (*val == 0) ? 0 : 1; 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci return 0; 39528c2ecf20Sopenharmony_ci} 39538c2ecf20Sopenharmony_ci 39548c2ecf20Sopenharmony_cistatic int sctp_setsockopt_pr_supported(struct sock *sk, 39558c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 39568c2ecf20Sopenharmony_ci unsigned int optlen) 39578c2ecf20Sopenharmony_ci{ 39588c2ecf20Sopenharmony_ci struct sctp_association *asoc; 39598c2ecf20Sopenharmony_ci 39608c2ecf20Sopenharmony_ci if (optlen != sizeof(*params)) 39618c2ecf20Sopenharmony_ci return -EINVAL; 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 39648c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC && 39658c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 39668c2ecf20Sopenharmony_ci return -EINVAL; 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci sctp_sk(sk)->ep->prsctp_enable = !!params->assoc_value; 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci return 0; 39718c2ecf20Sopenharmony_ci} 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_cistatic int sctp_setsockopt_default_prinfo(struct sock *sk, 39748c2ecf20Sopenharmony_ci struct sctp_default_prinfo *info, 39758c2ecf20Sopenharmony_ci unsigned int optlen) 39768c2ecf20Sopenharmony_ci{ 39778c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 39788c2ecf20Sopenharmony_ci struct sctp_association *asoc; 39798c2ecf20Sopenharmony_ci int retval = -EINVAL; 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci if (optlen != sizeof(*info)) 39828c2ecf20Sopenharmony_ci goto out; 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ci if (info->pr_policy & ~SCTP_PR_SCTP_MASK) 39858c2ecf20Sopenharmony_ci goto out; 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_ci if (info->pr_policy == SCTP_PR_SCTP_NONE) 39888c2ecf20Sopenharmony_ci info->pr_value = 0; 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, info->pr_assoc_id); 39918c2ecf20Sopenharmony_ci if (!asoc && info->pr_assoc_id > SCTP_ALL_ASSOC && 39928c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 39938c2ecf20Sopenharmony_ci goto out; 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci retval = 0; 39968c2ecf20Sopenharmony_ci 39978c2ecf20Sopenharmony_ci if (asoc) { 39988c2ecf20Sopenharmony_ci SCTP_PR_SET_POLICY(asoc->default_flags, info->pr_policy); 39998c2ecf20Sopenharmony_ci asoc->default_timetolive = info->pr_value; 40008c2ecf20Sopenharmony_ci goto out; 40018c2ecf20Sopenharmony_ci } 40028c2ecf20Sopenharmony_ci 40038c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 40048c2ecf20Sopenharmony_ci info->pr_assoc_id = SCTP_FUTURE_ASSOC; 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_ci if (info->pr_assoc_id == SCTP_FUTURE_ASSOC || 40078c2ecf20Sopenharmony_ci info->pr_assoc_id == SCTP_ALL_ASSOC) { 40088c2ecf20Sopenharmony_ci SCTP_PR_SET_POLICY(sp->default_flags, info->pr_policy); 40098c2ecf20Sopenharmony_ci sp->default_timetolive = info->pr_value; 40108c2ecf20Sopenharmony_ci } 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ci if (info->pr_assoc_id == SCTP_CURRENT_ASSOC || 40138c2ecf20Sopenharmony_ci info->pr_assoc_id == SCTP_ALL_ASSOC) { 40148c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 40158c2ecf20Sopenharmony_ci SCTP_PR_SET_POLICY(asoc->default_flags, 40168c2ecf20Sopenharmony_ci info->pr_policy); 40178c2ecf20Sopenharmony_ci asoc->default_timetolive = info->pr_value; 40188c2ecf20Sopenharmony_ci } 40198c2ecf20Sopenharmony_ci } 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ciout: 40228c2ecf20Sopenharmony_ci return retval; 40238c2ecf20Sopenharmony_ci} 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_cistatic int sctp_setsockopt_reconfig_supported(struct sock *sk, 40268c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 40278c2ecf20Sopenharmony_ci unsigned int optlen) 40288c2ecf20Sopenharmony_ci{ 40298c2ecf20Sopenharmony_ci struct sctp_association *asoc; 40308c2ecf20Sopenharmony_ci int retval = -EINVAL; 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_ci if (optlen != sizeof(*params)) 40338c2ecf20Sopenharmony_ci goto out; 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 40368c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC && 40378c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 40388c2ecf20Sopenharmony_ci goto out; 40398c2ecf20Sopenharmony_ci 40408c2ecf20Sopenharmony_ci sctp_sk(sk)->ep->reconf_enable = !!params->assoc_value; 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_ci retval = 0; 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ciout: 40458c2ecf20Sopenharmony_ci return retval; 40468c2ecf20Sopenharmony_ci} 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_cistatic int sctp_setsockopt_enable_strreset(struct sock *sk, 40498c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 40508c2ecf20Sopenharmony_ci unsigned int optlen) 40518c2ecf20Sopenharmony_ci{ 40528c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 40538c2ecf20Sopenharmony_ci struct sctp_association *asoc; 40548c2ecf20Sopenharmony_ci int retval = -EINVAL; 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_ci if (optlen != sizeof(*params)) 40578c2ecf20Sopenharmony_ci goto out; 40588c2ecf20Sopenharmony_ci 40598c2ecf20Sopenharmony_ci if (params->assoc_value & (~SCTP_ENABLE_STRRESET_MASK)) 40608c2ecf20Sopenharmony_ci goto out; 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 40638c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id > SCTP_ALL_ASSOC && 40648c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 40658c2ecf20Sopenharmony_ci goto out; 40668c2ecf20Sopenharmony_ci 40678c2ecf20Sopenharmony_ci retval = 0; 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_ci if (asoc) { 40708c2ecf20Sopenharmony_ci asoc->strreset_enable = params->assoc_value; 40718c2ecf20Sopenharmony_ci goto out; 40728c2ecf20Sopenharmony_ci } 40738c2ecf20Sopenharmony_ci 40748c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 40758c2ecf20Sopenharmony_ci params->assoc_id = SCTP_FUTURE_ASSOC; 40768c2ecf20Sopenharmony_ci 40778c2ecf20Sopenharmony_ci if (params->assoc_id == SCTP_FUTURE_ASSOC || 40788c2ecf20Sopenharmony_ci params->assoc_id == SCTP_ALL_ASSOC) 40798c2ecf20Sopenharmony_ci ep->strreset_enable = params->assoc_value; 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_ci if (params->assoc_id == SCTP_CURRENT_ASSOC || 40828c2ecf20Sopenharmony_ci params->assoc_id == SCTP_ALL_ASSOC) 40838c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &ep->asocs, asocs) 40848c2ecf20Sopenharmony_ci asoc->strreset_enable = params->assoc_value; 40858c2ecf20Sopenharmony_ci 40868c2ecf20Sopenharmony_ciout: 40878c2ecf20Sopenharmony_ci return retval; 40888c2ecf20Sopenharmony_ci} 40898c2ecf20Sopenharmony_ci 40908c2ecf20Sopenharmony_cistatic int sctp_setsockopt_reset_streams(struct sock *sk, 40918c2ecf20Sopenharmony_ci struct sctp_reset_streams *params, 40928c2ecf20Sopenharmony_ci unsigned int optlen) 40938c2ecf20Sopenharmony_ci{ 40948c2ecf20Sopenharmony_ci struct sctp_association *asoc; 40958c2ecf20Sopenharmony_ci 40968c2ecf20Sopenharmony_ci if (optlen < sizeof(*params)) 40978c2ecf20Sopenharmony_ci return -EINVAL; 40988c2ecf20Sopenharmony_ci /* srs_number_streams is u16, so optlen can't be bigger than this. */ 40998c2ecf20Sopenharmony_ci optlen = min_t(unsigned int, optlen, USHRT_MAX + 41008c2ecf20Sopenharmony_ci sizeof(__u16) * sizeof(*params)); 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_ci if (params->srs_number_streams * sizeof(__u16) > 41038c2ecf20Sopenharmony_ci optlen - sizeof(*params)) 41048c2ecf20Sopenharmony_ci return -EINVAL; 41058c2ecf20Sopenharmony_ci 41068c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->srs_assoc_id); 41078c2ecf20Sopenharmony_ci if (!asoc) 41088c2ecf20Sopenharmony_ci return -EINVAL; 41098c2ecf20Sopenharmony_ci 41108c2ecf20Sopenharmony_ci return sctp_send_reset_streams(asoc, params); 41118c2ecf20Sopenharmony_ci} 41128c2ecf20Sopenharmony_ci 41138c2ecf20Sopenharmony_cistatic int sctp_setsockopt_reset_assoc(struct sock *sk, sctp_assoc_t *associd, 41148c2ecf20Sopenharmony_ci unsigned int optlen) 41158c2ecf20Sopenharmony_ci{ 41168c2ecf20Sopenharmony_ci struct sctp_association *asoc; 41178c2ecf20Sopenharmony_ci 41188c2ecf20Sopenharmony_ci if (optlen != sizeof(*associd)) 41198c2ecf20Sopenharmony_ci return -EINVAL; 41208c2ecf20Sopenharmony_ci 41218c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, *associd); 41228c2ecf20Sopenharmony_ci if (!asoc) 41238c2ecf20Sopenharmony_ci return -EINVAL; 41248c2ecf20Sopenharmony_ci 41258c2ecf20Sopenharmony_ci return sctp_send_reset_assoc(asoc); 41268c2ecf20Sopenharmony_ci} 41278c2ecf20Sopenharmony_ci 41288c2ecf20Sopenharmony_cistatic int sctp_setsockopt_add_streams(struct sock *sk, 41298c2ecf20Sopenharmony_ci struct sctp_add_streams *params, 41308c2ecf20Sopenharmony_ci unsigned int optlen) 41318c2ecf20Sopenharmony_ci{ 41328c2ecf20Sopenharmony_ci struct sctp_association *asoc; 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci if (optlen != sizeof(*params)) 41358c2ecf20Sopenharmony_ci return -EINVAL; 41368c2ecf20Sopenharmony_ci 41378c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->sas_assoc_id); 41388c2ecf20Sopenharmony_ci if (!asoc) 41398c2ecf20Sopenharmony_ci return -EINVAL; 41408c2ecf20Sopenharmony_ci 41418c2ecf20Sopenharmony_ci return sctp_send_add_streams(asoc, params); 41428c2ecf20Sopenharmony_ci} 41438c2ecf20Sopenharmony_ci 41448c2ecf20Sopenharmony_cistatic int sctp_setsockopt_scheduler(struct sock *sk, 41458c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 41468c2ecf20Sopenharmony_ci unsigned int optlen) 41478c2ecf20Sopenharmony_ci{ 41488c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 41498c2ecf20Sopenharmony_ci struct sctp_association *asoc; 41508c2ecf20Sopenharmony_ci int retval = 0; 41518c2ecf20Sopenharmony_ci 41528c2ecf20Sopenharmony_ci if (optlen < sizeof(*params)) 41538c2ecf20Sopenharmony_ci return -EINVAL; 41548c2ecf20Sopenharmony_ci 41558c2ecf20Sopenharmony_ci if (params->assoc_value > SCTP_SS_MAX) 41568c2ecf20Sopenharmony_ci return -EINVAL; 41578c2ecf20Sopenharmony_ci 41588c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 41598c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id > SCTP_ALL_ASSOC && 41608c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 41618c2ecf20Sopenharmony_ci return -EINVAL; 41628c2ecf20Sopenharmony_ci 41638c2ecf20Sopenharmony_ci if (asoc) 41648c2ecf20Sopenharmony_ci return sctp_sched_set_sched(asoc, params->assoc_value); 41658c2ecf20Sopenharmony_ci 41668c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 41678c2ecf20Sopenharmony_ci params->assoc_id = SCTP_FUTURE_ASSOC; 41688c2ecf20Sopenharmony_ci 41698c2ecf20Sopenharmony_ci if (params->assoc_id == SCTP_FUTURE_ASSOC || 41708c2ecf20Sopenharmony_ci params->assoc_id == SCTP_ALL_ASSOC) 41718c2ecf20Sopenharmony_ci sp->default_ss = params->assoc_value; 41728c2ecf20Sopenharmony_ci 41738c2ecf20Sopenharmony_ci if (params->assoc_id == SCTP_CURRENT_ASSOC || 41748c2ecf20Sopenharmony_ci params->assoc_id == SCTP_ALL_ASSOC) { 41758c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 41768c2ecf20Sopenharmony_ci int ret = sctp_sched_set_sched(asoc, 41778c2ecf20Sopenharmony_ci params->assoc_value); 41788c2ecf20Sopenharmony_ci 41798c2ecf20Sopenharmony_ci if (ret && !retval) 41808c2ecf20Sopenharmony_ci retval = ret; 41818c2ecf20Sopenharmony_ci } 41828c2ecf20Sopenharmony_ci } 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ci return retval; 41858c2ecf20Sopenharmony_ci} 41868c2ecf20Sopenharmony_ci 41878c2ecf20Sopenharmony_cistatic int sctp_setsockopt_scheduler_value(struct sock *sk, 41888c2ecf20Sopenharmony_ci struct sctp_stream_value *params, 41898c2ecf20Sopenharmony_ci unsigned int optlen) 41908c2ecf20Sopenharmony_ci{ 41918c2ecf20Sopenharmony_ci struct sctp_association *asoc; 41928c2ecf20Sopenharmony_ci int retval = -EINVAL; 41938c2ecf20Sopenharmony_ci 41948c2ecf20Sopenharmony_ci if (optlen < sizeof(*params)) 41958c2ecf20Sopenharmony_ci goto out; 41968c2ecf20Sopenharmony_ci 41978c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 41988c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id != SCTP_CURRENT_ASSOC && 41998c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 42008c2ecf20Sopenharmony_ci goto out; 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci if (asoc) { 42038c2ecf20Sopenharmony_ci retval = sctp_sched_set_value(asoc, params->stream_id, 42048c2ecf20Sopenharmony_ci params->stream_value, GFP_KERNEL); 42058c2ecf20Sopenharmony_ci goto out; 42068c2ecf20Sopenharmony_ci } 42078c2ecf20Sopenharmony_ci 42088c2ecf20Sopenharmony_ci retval = 0; 42098c2ecf20Sopenharmony_ci 42108c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sctp_sk(sk)->ep->asocs, asocs) { 42118c2ecf20Sopenharmony_ci int ret = sctp_sched_set_value(asoc, params->stream_id, 42128c2ecf20Sopenharmony_ci params->stream_value, 42138c2ecf20Sopenharmony_ci GFP_KERNEL); 42148c2ecf20Sopenharmony_ci if (ret && !retval) /* try to return the 1st error. */ 42158c2ecf20Sopenharmony_ci retval = ret; 42168c2ecf20Sopenharmony_ci } 42178c2ecf20Sopenharmony_ci 42188c2ecf20Sopenharmony_ciout: 42198c2ecf20Sopenharmony_ci return retval; 42208c2ecf20Sopenharmony_ci} 42218c2ecf20Sopenharmony_ci 42228c2ecf20Sopenharmony_cistatic int sctp_setsockopt_interleaving_supported(struct sock *sk, 42238c2ecf20Sopenharmony_ci struct sctp_assoc_value *p, 42248c2ecf20Sopenharmony_ci unsigned int optlen) 42258c2ecf20Sopenharmony_ci{ 42268c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 42278c2ecf20Sopenharmony_ci struct sctp_association *asoc; 42288c2ecf20Sopenharmony_ci 42298c2ecf20Sopenharmony_ci if (optlen < sizeof(*p)) 42308c2ecf20Sopenharmony_ci return -EINVAL; 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, p->assoc_id); 42338c2ecf20Sopenharmony_ci if (!asoc && p->assoc_id != SCTP_FUTURE_ASSOC && sctp_style(sk, UDP)) 42348c2ecf20Sopenharmony_ci return -EINVAL; 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_ci if (!sock_net(sk)->sctp.intl_enable || !sp->frag_interleave) { 42378c2ecf20Sopenharmony_ci return -EPERM; 42388c2ecf20Sopenharmony_ci } 42398c2ecf20Sopenharmony_ci 42408c2ecf20Sopenharmony_ci sp->ep->intl_enable = !!p->assoc_value; 42418c2ecf20Sopenharmony_ci return 0; 42428c2ecf20Sopenharmony_ci} 42438c2ecf20Sopenharmony_ci 42448c2ecf20Sopenharmony_cistatic int sctp_setsockopt_reuse_port(struct sock *sk, int *val, 42458c2ecf20Sopenharmony_ci unsigned int optlen) 42468c2ecf20Sopenharmony_ci{ 42478c2ecf20Sopenharmony_ci if (!sctp_style(sk, TCP)) 42488c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci if (sctp_sk(sk)->ep->base.bind_addr.port) 42518c2ecf20Sopenharmony_ci return -EFAULT; 42528c2ecf20Sopenharmony_ci 42538c2ecf20Sopenharmony_ci if (optlen < sizeof(int)) 42548c2ecf20Sopenharmony_ci return -EINVAL; 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_ci sctp_sk(sk)->reuse = !!*val; 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci return 0; 42598c2ecf20Sopenharmony_ci} 42608c2ecf20Sopenharmony_ci 42618c2ecf20Sopenharmony_cistatic int sctp_assoc_ulpevent_type_set(struct sctp_event *param, 42628c2ecf20Sopenharmony_ci struct sctp_association *asoc) 42638c2ecf20Sopenharmony_ci{ 42648c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 42658c2ecf20Sopenharmony_ci 42668c2ecf20Sopenharmony_ci sctp_ulpevent_type_set(&asoc->subscribe, param->se_type, param->se_on); 42678c2ecf20Sopenharmony_ci 42688c2ecf20Sopenharmony_ci if (param->se_type == SCTP_SENDER_DRY_EVENT && param->se_on) { 42698c2ecf20Sopenharmony_ci if (sctp_outq_is_empty(&asoc->outqueue)) { 42708c2ecf20Sopenharmony_ci event = sctp_ulpevent_make_sender_dry_event(asoc, 42718c2ecf20Sopenharmony_ci GFP_USER | __GFP_NOWARN); 42728c2ecf20Sopenharmony_ci if (!event) 42738c2ecf20Sopenharmony_ci return -ENOMEM; 42748c2ecf20Sopenharmony_ci 42758c2ecf20Sopenharmony_ci asoc->stream.si->enqueue_event(&asoc->ulpq, event); 42768c2ecf20Sopenharmony_ci } 42778c2ecf20Sopenharmony_ci } 42788c2ecf20Sopenharmony_ci 42798c2ecf20Sopenharmony_ci return 0; 42808c2ecf20Sopenharmony_ci} 42818c2ecf20Sopenharmony_ci 42828c2ecf20Sopenharmony_cistatic int sctp_setsockopt_event(struct sock *sk, struct sctp_event *param, 42838c2ecf20Sopenharmony_ci unsigned int optlen) 42848c2ecf20Sopenharmony_ci{ 42858c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 42868c2ecf20Sopenharmony_ci struct sctp_association *asoc; 42878c2ecf20Sopenharmony_ci int retval = 0; 42888c2ecf20Sopenharmony_ci 42898c2ecf20Sopenharmony_ci if (optlen < sizeof(*param)) 42908c2ecf20Sopenharmony_ci return -EINVAL; 42918c2ecf20Sopenharmony_ci 42928c2ecf20Sopenharmony_ci if (param->se_type < SCTP_SN_TYPE_BASE || 42938c2ecf20Sopenharmony_ci param->se_type > SCTP_SN_TYPE_MAX) 42948c2ecf20Sopenharmony_ci return -EINVAL; 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, param->se_assoc_id); 42978c2ecf20Sopenharmony_ci if (!asoc && param->se_assoc_id > SCTP_ALL_ASSOC && 42988c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 42998c2ecf20Sopenharmony_ci return -EINVAL; 43008c2ecf20Sopenharmony_ci 43018c2ecf20Sopenharmony_ci if (asoc) 43028c2ecf20Sopenharmony_ci return sctp_assoc_ulpevent_type_set(param, asoc); 43038c2ecf20Sopenharmony_ci 43048c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 43058c2ecf20Sopenharmony_ci param->se_assoc_id = SCTP_FUTURE_ASSOC; 43068c2ecf20Sopenharmony_ci 43078c2ecf20Sopenharmony_ci if (param->se_assoc_id == SCTP_FUTURE_ASSOC || 43088c2ecf20Sopenharmony_ci param->se_assoc_id == SCTP_ALL_ASSOC) 43098c2ecf20Sopenharmony_ci sctp_ulpevent_type_set(&sp->subscribe, 43108c2ecf20Sopenharmony_ci param->se_type, param->se_on); 43118c2ecf20Sopenharmony_ci 43128c2ecf20Sopenharmony_ci if (param->se_assoc_id == SCTP_CURRENT_ASSOC || 43138c2ecf20Sopenharmony_ci param->se_assoc_id == SCTP_ALL_ASSOC) { 43148c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 43158c2ecf20Sopenharmony_ci int ret = sctp_assoc_ulpevent_type_set(param, asoc); 43168c2ecf20Sopenharmony_ci 43178c2ecf20Sopenharmony_ci if (ret && !retval) 43188c2ecf20Sopenharmony_ci retval = ret; 43198c2ecf20Sopenharmony_ci } 43208c2ecf20Sopenharmony_ci } 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_ci return retval; 43238c2ecf20Sopenharmony_ci} 43248c2ecf20Sopenharmony_ci 43258c2ecf20Sopenharmony_cistatic int sctp_setsockopt_asconf_supported(struct sock *sk, 43268c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 43278c2ecf20Sopenharmony_ci unsigned int optlen) 43288c2ecf20Sopenharmony_ci{ 43298c2ecf20Sopenharmony_ci struct sctp_association *asoc; 43308c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 43318c2ecf20Sopenharmony_ci int retval = -EINVAL; 43328c2ecf20Sopenharmony_ci 43338c2ecf20Sopenharmony_ci if (optlen != sizeof(*params)) 43348c2ecf20Sopenharmony_ci goto out; 43358c2ecf20Sopenharmony_ci 43368c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 43378c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC && 43388c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 43398c2ecf20Sopenharmony_ci goto out; 43408c2ecf20Sopenharmony_ci 43418c2ecf20Sopenharmony_ci ep = sctp_sk(sk)->ep; 43428c2ecf20Sopenharmony_ci ep->asconf_enable = !!params->assoc_value; 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_ci if (ep->asconf_enable && ep->auth_enable) { 43458c2ecf20Sopenharmony_ci sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF); 43468c2ecf20Sopenharmony_ci sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK); 43478c2ecf20Sopenharmony_ci } 43488c2ecf20Sopenharmony_ci 43498c2ecf20Sopenharmony_ci retval = 0; 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_ciout: 43528c2ecf20Sopenharmony_ci return retval; 43538c2ecf20Sopenharmony_ci} 43548c2ecf20Sopenharmony_ci 43558c2ecf20Sopenharmony_cistatic int sctp_setsockopt_auth_supported(struct sock *sk, 43568c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 43578c2ecf20Sopenharmony_ci unsigned int optlen) 43588c2ecf20Sopenharmony_ci{ 43598c2ecf20Sopenharmony_ci struct sctp_association *asoc; 43608c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 43618c2ecf20Sopenharmony_ci int retval = -EINVAL; 43628c2ecf20Sopenharmony_ci 43638c2ecf20Sopenharmony_ci if (optlen != sizeof(*params)) 43648c2ecf20Sopenharmony_ci goto out; 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 43678c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC && 43688c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 43698c2ecf20Sopenharmony_ci goto out; 43708c2ecf20Sopenharmony_ci 43718c2ecf20Sopenharmony_ci ep = sctp_sk(sk)->ep; 43728c2ecf20Sopenharmony_ci if (params->assoc_value) { 43738c2ecf20Sopenharmony_ci retval = sctp_auth_init(ep, GFP_KERNEL); 43748c2ecf20Sopenharmony_ci if (retval) 43758c2ecf20Sopenharmony_ci goto out; 43768c2ecf20Sopenharmony_ci if (ep->asconf_enable) { 43778c2ecf20Sopenharmony_ci sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF); 43788c2ecf20Sopenharmony_ci sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK); 43798c2ecf20Sopenharmony_ci } 43808c2ecf20Sopenharmony_ci } 43818c2ecf20Sopenharmony_ci 43828c2ecf20Sopenharmony_ci ep->auth_enable = !!params->assoc_value; 43838c2ecf20Sopenharmony_ci retval = 0; 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ciout: 43868c2ecf20Sopenharmony_ci return retval; 43878c2ecf20Sopenharmony_ci} 43888c2ecf20Sopenharmony_ci 43898c2ecf20Sopenharmony_cistatic int sctp_setsockopt_ecn_supported(struct sock *sk, 43908c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 43918c2ecf20Sopenharmony_ci unsigned int optlen) 43928c2ecf20Sopenharmony_ci{ 43938c2ecf20Sopenharmony_ci struct sctp_association *asoc; 43948c2ecf20Sopenharmony_ci int retval = -EINVAL; 43958c2ecf20Sopenharmony_ci 43968c2ecf20Sopenharmony_ci if (optlen != sizeof(*params)) 43978c2ecf20Sopenharmony_ci goto out; 43988c2ecf20Sopenharmony_ci 43998c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 44008c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC && 44018c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 44028c2ecf20Sopenharmony_ci goto out; 44038c2ecf20Sopenharmony_ci 44048c2ecf20Sopenharmony_ci sctp_sk(sk)->ep->ecn_enable = !!params->assoc_value; 44058c2ecf20Sopenharmony_ci retval = 0; 44068c2ecf20Sopenharmony_ci 44078c2ecf20Sopenharmony_ciout: 44088c2ecf20Sopenharmony_ci return retval; 44098c2ecf20Sopenharmony_ci} 44108c2ecf20Sopenharmony_ci 44118c2ecf20Sopenharmony_cistatic int sctp_setsockopt_pf_expose(struct sock *sk, 44128c2ecf20Sopenharmony_ci struct sctp_assoc_value *params, 44138c2ecf20Sopenharmony_ci unsigned int optlen) 44148c2ecf20Sopenharmony_ci{ 44158c2ecf20Sopenharmony_ci struct sctp_association *asoc; 44168c2ecf20Sopenharmony_ci int retval = -EINVAL; 44178c2ecf20Sopenharmony_ci 44188c2ecf20Sopenharmony_ci if (optlen != sizeof(*params)) 44198c2ecf20Sopenharmony_ci goto out; 44208c2ecf20Sopenharmony_ci 44218c2ecf20Sopenharmony_ci if (params->assoc_value > SCTP_PF_EXPOSE_MAX) 44228c2ecf20Sopenharmony_ci goto out; 44238c2ecf20Sopenharmony_ci 44248c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params->assoc_id); 44258c2ecf20Sopenharmony_ci if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC && 44268c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 44278c2ecf20Sopenharmony_ci goto out; 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci if (asoc) 44308c2ecf20Sopenharmony_ci asoc->pf_expose = params->assoc_value; 44318c2ecf20Sopenharmony_ci else 44328c2ecf20Sopenharmony_ci sctp_sk(sk)->pf_expose = params->assoc_value; 44338c2ecf20Sopenharmony_ci retval = 0; 44348c2ecf20Sopenharmony_ci 44358c2ecf20Sopenharmony_ciout: 44368c2ecf20Sopenharmony_ci return retval; 44378c2ecf20Sopenharmony_ci} 44388c2ecf20Sopenharmony_ci 44398c2ecf20Sopenharmony_ci/* API 6.2 setsockopt(), getsockopt() 44408c2ecf20Sopenharmony_ci * 44418c2ecf20Sopenharmony_ci * Applications use setsockopt() and getsockopt() to set or retrieve 44428c2ecf20Sopenharmony_ci * socket options. Socket options are used to change the default 44438c2ecf20Sopenharmony_ci * behavior of sockets calls. They are described in Section 7. 44448c2ecf20Sopenharmony_ci * 44458c2ecf20Sopenharmony_ci * The syntax is: 44468c2ecf20Sopenharmony_ci * 44478c2ecf20Sopenharmony_ci * ret = getsockopt(int sd, int level, int optname, void __user *optval, 44488c2ecf20Sopenharmony_ci * int __user *optlen); 44498c2ecf20Sopenharmony_ci * ret = setsockopt(int sd, int level, int optname, const void __user *optval, 44508c2ecf20Sopenharmony_ci * int optlen); 44518c2ecf20Sopenharmony_ci * 44528c2ecf20Sopenharmony_ci * sd - the socket descript. 44538c2ecf20Sopenharmony_ci * level - set to IPPROTO_SCTP for all SCTP options. 44548c2ecf20Sopenharmony_ci * optname - the option name. 44558c2ecf20Sopenharmony_ci * optval - the buffer to store the value of the option. 44568c2ecf20Sopenharmony_ci * optlen - the size of the buffer. 44578c2ecf20Sopenharmony_ci */ 44588c2ecf20Sopenharmony_cistatic int sctp_setsockopt(struct sock *sk, int level, int optname, 44598c2ecf20Sopenharmony_ci sockptr_t optval, unsigned int optlen) 44608c2ecf20Sopenharmony_ci{ 44618c2ecf20Sopenharmony_ci void *kopt = NULL; 44628c2ecf20Sopenharmony_ci int retval = 0; 44638c2ecf20Sopenharmony_ci 44648c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 44658c2ecf20Sopenharmony_ci 44668c2ecf20Sopenharmony_ci /* I can hardly begin to describe how wrong this is. This is 44678c2ecf20Sopenharmony_ci * so broken as to be worse than useless. The API draft 44688c2ecf20Sopenharmony_ci * REALLY is NOT helpful here... I am not convinced that the 44698c2ecf20Sopenharmony_ci * semantics of setsockopt() with a level OTHER THAN SOL_SCTP 44708c2ecf20Sopenharmony_ci * are at all well-founded. 44718c2ecf20Sopenharmony_ci */ 44728c2ecf20Sopenharmony_ci if (level != SOL_SCTP) { 44738c2ecf20Sopenharmony_ci struct sctp_af *af = sctp_sk(sk)->pf->af; 44748c2ecf20Sopenharmony_ci 44758c2ecf20Sopenharmony_ci return af->setsockopt(sk, level, optname, optval, optlen); 44768c2ecf20Sopenharmony_ci } 44778c2ecf20Sopenharmony_ci 44788c2ecf20Sopenharmony_ci if (optlen > 0) { 44798c2ecf20Sopenharmony_ci /* Trim it to the biggest size sctp sockopt may need if necessary */ 44808c2ecf20Sopenharmony_ci optlen = min_t(unsigned int, optlen, 44818c2ecf20Sopenharmony_ci PAGE_ALIGN(USHRT_MAX + 44828c2ecf20Sopenharmony_ci sizeof(__u16) * sizeof(struct sctp_reset_streams))); 44838c2ecf20Sopenharmony_ci kopt = memdup_sockptr(optval, optlen); 44848c2ecf20Sopenharmony_ci if (IS_ERR(kopt)) 44858c2ecf20Sopenharmony_ci return PTR_ERR(kopt); 44868c2ecf20Sopenharmony_ci } 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_ci lock_sock(sk); 44898c2ecf20Sopenharmony_ci 44908c2ecf20Sopenharmony_ci switch (optname) { 44918c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_BINDX_ADD: 44928c2ecf20Sopenharmony_ci /* 'optlen' is the size of the addresses buffer. */ 44938c2ecf20Sopenharmony_ci retval = sctp_setsockopt_bindx(sk, kopt, optlen, 44948c2ecf20Sopenharmony_ci SCTP_BINDX_ADD_ADDR); 44958c2ecf20Sopenharmony_ci break; 44968c2ecf20Sopenharmony_ci 44978c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_BINDX_REM: 44988c2ecf20Sopenharmony_ci /* 'optlen' is the size of the addresses buffer. */ 44998c2ecf20Sopenharmony_ci retval = sctp_setsockopt_bindx(sk, kopt, optlen, 45008c2ecf20Sopenharmony_ci SCTP_BINDX_REM_ADDR); 45018c2ecf20Sopenharmony_ci break; 45028c2ecf20Sopenharmony_ci 45038c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_CONNECTX_OLD: 45048c2ecf20Sopenharmony_ci /* 'optlen' is the size of the addresses buffer. */ 45058c2ecf20Sopenharmony_ci retval = sctp_setsockopt_connectx_old(sk, kopt, optlen); 45068c2ecf20Sopenharmony_ci break; 45078c2ecf20Sopenharmony_ci 45088c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_CONNECTX: 45098c2ecf20Sopenharmony_ci /* 'optlen' is the size of the addresses buffer. */ 45108c2ecf20Sopenharmony_ci retval = sctp_setsockopt_connectx(sk, kopt, optlen); 45118c2ecf20Sopenharmony_ci break; 45128c2ecf20Sopenharmony_ci 45138c2ecf20Sopenharmony_ci case SCTP_DISABLE_FRAGMENTS: 45148c2ecf20Sopenharmony_ci retval = sctp_setsockopt_disable_fragments(sk, kopt, optlen); 45158c2ecf20Sopenharmony_ci break; 45168c2ecf20Sopenharmony_ci 45178c2ecf20Sopenharmony_ci case SCTP_EVENTS: 45188c2ecf20Sopenharmony_ci retval = sctp_setsockopt_events(sk, kopt, optlen); 45198c2ecf20Sopenharmony_ci break; 45208c2ecf20Sopenharmony_ci 45218c2ecf20Sopenharmony_ci case SCTP_AUTOCLOSE: 45228c2ecf20Sopenharmony_ci retval = sctp_setsockopt_autoclose(sk, kopt, optlen); 45238c2ecf20Sopenharmony_ci break; 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_ci case SCTP_PEER_ADDR_PARAMS: 45268c2ecf20Sopenharmony_ci retval = sctp_setsockopt_peer_addr_params(sk, kopt, optlen); 45278c2ecf20Sopenharmony_ci break; 45288c2ecf20Sopenharmony_ci 45298c2ecf20Sopenharmony_ci case SCTP_DELAYED_SACK: 45308c2ecf20Sopenharmony_ci retval = sctp_setsockopt_delayed_ack(sk, kopt, optlen); 45318c2ecf20Sopenharmony_ci break; 45328c2ecf20Sopenharmony_ci case SCTP_PARTIAL_DELIVERY_POINT: 45338c2ecf20Sopenharmony_ci retval = sctp_setsockopt_partial_delivery_point(sk, kopt, optlen); 45348c2ecf20Sopenharmony_ci break; 45358c2ecf20Sopenharmony_ci 45368c2ecf20Sopenharmony_ci case SCTP_INITMSG: 45378c2ecf20Sopenharmony_ci retval = sctp_setsockopt_initmsg(sk, kopt, optlen); 45388c2ecf20Sopenharmony_ci break; 45398c2ecf20Sopenharmony_ci case SCTP_DEFAULT_SEND_PARAM: 45408c2ecf20Sopenharmony_ci retval = sctp_setsockopt_default_send_param(sk, kopt, optlen); 45418c2ecf20Sopenharmony_ci break; 45428c2ecf20Sopenharmony_ci case SCTP_DEFAULT_SNDINFO: 45438c2ecf20Sopenharmony_ci retval = sctp_setsockopt_default_sndinfo(sk, kopt, optlen); 45448c2ecf20Sopenharmony_ci break; 45458c2ecf20Sopenharmony_ci case SCTP_PRIMARY_ADDR: 45468c2ecf20Sopenharmony_ci retval = sctp_setsockopt_primary_addr(sk, kopt, optlen); 45478c2ecf20Sopenharmony_ci break; 45488c2ecf20Sopenharmony_ci case SCTP_SET_PEER_PRIMARY_ADDR: 45498c2ecf20Sopenharmony_ci retval = sctp_setsockopt_peer_primary_addr(sk, kopt, optlen); 45508c2ecf20Sopenharmony_ci break; 45518c2ecf20Sopenharmony_ci case SCTP_NODELAY: 45528c2ecf20Sopenharmony_ci retval = sctp_setsockopt_nodelay(sk, kopt, optlen); 45538c2ecf20Sopenharmony_ci break; 45548c2ecf20Sopenharmony_ci case SCTP_RTOINFO: 45558c2ecf20Sopenharmony_ci retval = sctp_setsockopt_rtoinfo(sk, kopt, optlen); 45568c2ecf20Sopenharmony_ci break; 45578c2ecf20Sopenharmony_ci case SCTP_ASSOCINFO: 45588c2ecf20Sopenharmony_ci retval = sctp_setsockopt_associnfo(sk, kopt, optlen); 45598c2ecf20Sopenharmony_ci break; 45608c2ecf20Sopenharmony_ci case SCTP_I_WANT_MAPPED_V4_ADDR: 45618c2ecf20Sopenharmony_ci retval = sctp_setsockopt_mappedv4(sk, kopt, optlen); 45628c2ecf20Sopenharmony_ci break; 45638c2ecf20Sopenharmony_ci case SCTP_MAXSEG: 45648c2ecf20Sopenharmony_ci retval = sctp_setsockopt_maxseg(sk, kopt, optlen); 45658c2ecf20Sopenharmony_ci break; 45668c2ecf20Sopenharmony_ci case SCTP_ADAPTATION_LAYER: 45678c2ecf20Sopenharmony_ci retval = sctp_setsockopt_adaptation_layer(sk, kopt, optlen); 45688c2ecf20Sopenharmony_ci break; 45698c2ecf20Sopenharmony_ci case SCTP_CONTEXT: 45708c2ecf20Sopenharmony_ci retval = sctp_setsockopt_context(sk, kopt, optlen); 45718c2ecf20Sopenharmony_ci break; 45728c2ecf20Sopenharmony_ci case SCTP_FRAGMENT_INTERLEAVE: 45738c2ecf20Sopenharmony_ci retval = sctp_setsockopt_fragment_interleave(sk, kopt, optlen); 45748c2ecf20Sopenharmony_ci break; 45758c2ecf20Sopenharmony_ci case SCTP_MAX_BURST: 45768c2ecf20Sopenharmony_ci retval = sctp_setsockopt_maxburst(sk, kopt, optlen); 45778c2ecf20Sopenharmony_ci break; 45788c2ecf20Sopenharmony_ci case SCTP_AUTH_CHUNK: 45798c2ecf20Sopenharmony_ci retval = sctp_setsockopt_auth_chunk(sk, kopt, optlen); 45808c2ecf20Sopenharmony_ci break; 45818c2ecf20Sopenharmony_ci case SCTP_HMAC_IDENT: 45828c2ecf20Sopenharmony_ci retval = sctp_setsockopt_hmac_ident(sk, kopt, optlen); 45838c2ecf20Sopenharmony_ci break; 45848c2ecf20Sopenharmony_ci case SCTP_AUTH_KEY: 45858c2ecf20Sopenharmony_ci retval = sctp_setsockopt_auth_key(sk, kopt, optlen); 45868c2ecf20Sopenharmony_ci break; 45878c2ecf20Sopenharmony_ci case SCTP_AUTH_ACTIVE_KEY: 45888c2ecf20Sopenharmony_ci retval = sctp_setsockopt_active_key(sk, kopt, optlen); 45898c2ecf20Sopenharmony_ci break; 45908c2ecf20Sopenharmony_ci case SCTP_AUTH_DELETE_KEY: 45918c2ecf20Sopenharmony_ci retval = sctp_setsockopt_del_key(sk, kopt, optlen); 45928c2ecf20Sopenharmony_ci break; 45938c2ecf20Sopenharmony_ci case SCTP_AUTH_DEACTIVATE_KEY: 45948c2ecf20Sopenharmony_ci retval = sctp_setsockopt_deactivate_key(sk, kopt, optlen); 45958c2ecf20Sopenharmony_ci break; 45968c2ecf20Sopenharmony_ci case SCTP_AUTO_ASCONF: 45978c2ecf20Sopenharmony_ci retval = sctp_setsockopt_auto_asconf(sk, kopt, optlen); 45988c2ecf20Sopenharmony_ci break; 45998c2ecf20Sopenharmony_ci case SCTP_PEER_ADDR_THLDS: 46008c2ecf20Sopenharmony_ci retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen, 46018c2ecf20Sopenharmony_ci false); 46028c2ecf20Sopenharmony_ci break; 46038c2ecf20Sopenharmony_ci case SCTP_PEER_ADDR_THLDS_V2: 46048c2ecf20Sopenharmony_ci retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen, 46058c2ecf20Sopenharmony_ci true); 46068c2ecf20Sopenharmony_ci break; 46078c2ecf20Sopenharmony_ci case SCTP_RECVRCVINFO: 46088c2ecf20Sopenharmony_ci retval = sctp_setsockopt_recvrcvinfo(sk, kopt, optlen); 46098c2ecf20Sopenharmony_ci break; 46108c2ecf20Sopenharmony_ci case SCTP_RECVNXTINFO: 46118c2ecf20Sopenharmony_ci retval = sctp_setsockopt_recvnxtinfo(sk, kopt, optlen); 46128c2ecf20Sopenharmony_ci break; 46138c2ecf20Sopenharmony_ci case SCTP_PR_SUPPORTED: 46148c2ecf20Sopenharmony_ci retval = sctp_setsockopt_pr_supported(sk, kopt, optlen); 46158c2ecf20Sopenharmony_ci break; 46168c2ecf20Sopenharmony_ci case SCTP_DEFAULT_PRINFO: 46178c2ecf20Sopenharmony_ci retval = sctp_setsockopt_default_prinfo(sk, kopt, optlen); 46188c2ecf20Sopenharmony_ci break; 46198c2ecf20Sopenharmony_ci case SCTP_RECONFIG_SUPPORTED: 46208c2ecf20Sopenharmony_ci retval = sctp_setsockopt_reconfig_supported(sk, kopt, optlen); 46218c2ecf20Sopenharmony_ci break; 46228c2ecf20Sopenharmony_ci case SCTP_ENABLE_STREAM_RESET: 46238c2ecf20Sopenharmony_ci retval = sctp_setsockopt_enable_strreset(sk, kopt, optlen); 46248c2ecf20Sopenharmony_ci break; 46258c2ecf20Sopenharmony_ci case SCTP_RESET_STREAMS: 46268c2ecf20Sopenharmony_ci retval = sctp_setsockopt_reset_streams(sk, kopt, optlen); 46278c2ecf20Sopenharmony_ci break; 46288c2ecf20Sopenharmony_ci case SCTP_RESET_ASSOC: 46298c2ecf20Sopenharmony_ci retval = sctp_setsockopt_reset_assoc(sk, kopt, optlen); 46308c2ecf20Sopenharmony_ci break; 46318c2ecf20Sopenharmony_ci case SCTP_ADD_STREAMS: 46328c2ecf20Sopenharmony_ci retval = sctp_setsockopt_add_streams(sk, kopt, optlen); 46338c2ecf20Sopenharmony_ci break; 46348c2ecf20Sopenharmony_ci case SCTP_STREAM_SCHEDULER: 46358c2ecf20Sopenharmony_ci retval = sctp_setsockopt_scheduler(sk, kopt, optlen); 46368c2ecf20Sopenharmony_ci break; 46378c2ecf20Sopenharmony_ci case SCTP_STREAM_SCHEDULER_VALUE: 46388c2ecf20Sopenharmony_ci retval = sctp_setsockopt_scheduler_value(sk, kopt, optlen); 46398c2ecf20Sopenharmony_ci break; 46408c2ecf20Sopenharmony_ci case SCTP_INTERLEAVING_SUPPORTED: 46418c2ecf20Sopenharmony_ci retval = sctp_setsockopt_interleaving_supported(sk, kopt, 46428c2ecf20Sopenharmony_ci optlen); 46438c2ecf20Sopenharmony_ci break; 46448c2ecf20Sopenharmony_ci case SCTP_REUSE_PORT: 46458c2ecf20Sopenharmony_ci retval = sctp_setsockopt_reuse_port(sk, kopt, optlen); 46468c2ecf20Sopenharmony_ci break; 46478c2ecf20Sopenharmony_ci case SCTP_EVENT: 46488c2ecf20Sopenharmony_ci retval = sctp_setsockopt_event(sk, kopt, optlen); 46498c2ecf20Sopenharmony_ci break; 46508c2ecf20Sopenharmony_ci case SCTP_ASCONF_SUPPORTED: 46518c2ecf20Sopenharmony_ci retval = sctp_setsockopt_asconf_supported(sk, kopt, optlen); 46528c2ecf20Sopenharmony_ci break; 46538c2ecf20Sopenharmony_ci case SCTP_AUTH_SUPPORTED: 46548c2ecf20Sopenharmony_ci retval = sctp_setsockopt_auth_supported(sk, kopt, optlen); 46558c2ecf20Sopenharmony_ci break; 46568c2ecf20Sopenharmony_ci case SCTP_ECN_SUPPORTED: 46578c2ecf20Sopenharmony_ci retval = sctp_setsockopt_ecn_supported(sk, kopt, optlen); 46588c2ecf20Sopenharmony_ci break; 46598c2ecf20Sopenharmony_ci case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: 46608c2ecf20Sopenharmony_ci retval = sctp_setsockopt_pf_expose(sk, kopt, optlen); 46618c2ecf20Sopenharmony_ci break; 46628c2ecf20Sopenharmony_ci default: 46638c2ecf20Sopenharmony_ci retval = -ENOPROTOOPT; 46648c2ecf20Sopenharmony_ci break; 46658c2ecf20Sopenharmony_ci } 46668c2ecf20Sopenharmony_ci 46678c2ecf20Sopenharmony_ci release_sock(sk); 46688c2ecf20Sopenharmony_ci kfree(kopt); 46698c2ecf20Sopenharmony_ci return retval; 46708c2ecf20Sopenharmony_ci} 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ci/* API 3.1.6 connect() - UDP Style Syntax 46738c2ecf20Sopenharmony_ci * 46748c2ecf20Sopenharmony_ci * An application may use the connect() call in the UDP model to initiate an 46758c2ecf20Sopenharmony_ci * association without sending data. 46768c2ecf20Sopenharmony_ci * 46778c2ecf20Sopenharmony_ci * The syntax is: 46788c2ecf20Sopenharmony_ci * 46798c2ecf20Sopenharmony_ci * ret = connect(int sd, const struct sockaddr *nam, socklen_t len); 46808c2ecf20Sopenharmony_ci * 46818c2ecf20Sopenharmony_ci * sd: the socket descriptor to have a new association added to. 46828c2ecf20Sopenharmony_ci * 46838c2ecf20Sopenharmony_ci * nam: the address structure (either struct sockaddr_in or struct 46848c2ecf20Sopenharmony_ci * sockaddr_in6 defined in RFC2553 [7]). 46858c2ecf20Sopenharmony_ci * 46868c2ecf20Sopenharmony_ci * len: the size of the address. 46878c2ecf20Sopenharmony_ci */ 46888c2ecf20Sopenharmony_cistatic int sctp_connect(struct sock *sk, struct sockaddr *addr, 46898c2ecf20Sopenharmony_ci int addr_len, int flags) 46908c2ecf20Sopenharmony_ci{ 46918c2ecf20Sopenharmony_ci struct sctp_af *af; 46928c2ecf20Sopenharmony_ci int err = -EINVAL; 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci lock_sock(sk); 46958c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk, 46968c2ecf20Sopenharmony_ci addr, addr_len); 46978c2ecf20Sopenharmony_ci 46988c2ecf20Sopenharmony_ci /* Validate addr_len before calling common connect/connectx routine. */ 46998c2ecf20Sopenharmony_ci af = sctp_get_af_specific(addr->sa_family); 47008c2ecf20Sopenharmony_ci if (af && addr_len >= af->sockaddr_len) 47018c2ecf20Sopenharmony_ci err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL); 47028c2ecf20Sopenharmony_ci 47038c2ecf20Sopenharmony_ci release_sock(sk); 47048c2ecf20Sopenharmony_ci return err; 47058c2ecf20Sopenharmony_ci} 47068c2ecf20Sopenharmony_ci 47078c2ecf20Sopenharmony_ciint sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr, 47088c2ecf20Sopenharmony_ci int addr_len, int flags) 47098c2ecf20Sopenharmony_ci{ 47108c2ecf20Sopenharmony_ci if (addr_len < sizeof(uaddr->sa_family)) 47118c2ecf20Sopenharmony_ci return -EINVAL; 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_ci if (uaddr->sa_family == AF_UNSPEC) 47148c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 47158c2ecf20Sopenharmony_ci 47168c2ecf20Sopenharmony_ci return sctp_connect(sock->sk, uaddr, addr_len, flags); 47178c2ecf20Sopenharmony_ci} 47188c2ecf20Sopenharmony_ci 47198c2ecf20Sopenharmony_ci/* FIXME: Write comments. */ 47208c2ecf20Sopenharmony_cistatic int sctp_disconnect(struct sock *sk, int flags) 47218c2ecf20Sopenharmony_ci{ 47228c2ecf20Sopenharmony_ci return -EOPNOTSUPP; /* STUB */ 47238c2ecf20Sopenharmony_ci} 47248c2ecf20Sopenharmony_ci 47258c2ecf20Sopenharmony_ci/* 4.1.4 accept() - TCP Style Syntax 47268c2ecf20Sopenharmony_ci * 47278c2ecf20Sopenharmony_ci * Applications use accept() call to remove an established SCTP 47288c2ecf20Sopenharmony_ci * association from the accept queue of the endpoint. A new socket 47298c2ecf20Sopenharmony_ci * descriptor will be returned from accept() to represent the newly 47308c2ecf20Sopenharmony_ci * formed association. 47318c2ecf20Sopenharmony_ci */ 47328c2ecf20Sopenharmony_cistatic struct sock *sctp_accept(struct sock *sk, int flags, int *err, bool kern) 47338c2ecf20Sopenharmony_ci{ 47348c2ecf20Sopenharmony_ci struct sctp_sock *sp; 47358c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 47368c2ecf20Sopenharmony_ci struct sock *newsk = NULL; 47378c2ecf20Sopenharmony_ci struct sctp_association *asoc; 47388c2ecf20Sopenharmony_ci long timeo; 47398c2ecf20Sopenharmony_ci int error = 0; 47408c2ecf20Sopenharmony_ci 47418c2ecf20Sopenharmony_ci lock_sock(sk); 47428c2ecf20Sopenharmony_ci 47438c2ecf20Sopenharmony_ci sp = sctp_sk(sk); 47448c2ecf20Sopenharmony_ci ep = sp->ep; 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci if (!sctp_style(sk, TCP)) { 47478c2ecf20Sopenharmony_ci error = -EOPNOTSUPP; 47488c2ecf20Sopenharmony_ci goto out; 47498c2ecf20Sopenharmony_ci } 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_ci if (!sctp_sstate(sk, LISTENING)) { 47528c2ecf20Sopenharmony_ci error = -EINVAL; 47538c2ecf20Sopenharmony_ci goto out; 47548c2ecf20Sopenharmony_ci } 47558c2ecf20Sopenharmony_ci 47568c2ecf20Sopenharmony_ci timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 47578c2ecf20Sopenharmony_ci 47588c2ecf20Sopenharmony_ci error = sctp_wait_for_accept(sk, timeo); 47598c2ecf20Sopenharmony_ci if (error) 47608c2ecf20Sopenharmony_ci goto out; 47618c2ecf20Sopenharmony_ci 47628c2ecf20Sopenharmony_ci /* We treat the list of associations on the endpoint as the accept 47638c2ecf20Sopenharmony_ci * queue and pick the first association on the list. 47648c2ecf20Sopenharmony_ci */ 47658c2ecf20Sopenharmony_ci asoc = list_entry(ep->asocs.next, struct sctp_association, asocs); 47668c2ecf20Sopenharmony_ci 47678c2ecf20Sopenharmony_ci newsk = sp->pf->create_accept_sk(sk, asoc, kern); 47688c2ecf20Sopenharmony_ci if (!newsk) { 47698c2ecf20Sopenharmony_ci error = -ENOMEM; 47708c2ecf20Sopenharmony_ci goto out; 47718c2ecf20Sopenharmony_ci } 47728c2ecf20Sopenharmony_ci 47738c2ecf20Sopenharmony_ci /* Populate the fields of the newsk from the oldsk and migrate the 47748c2ecf20Sopenharmony_ci * asoc to the newsk. 47758c2ecf20Sopenharmony_ci */ 47768c2ecf20Sopenharmony_ci error = sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); 47778c2ecf20Sopenharmony_ci if (error) { 47788c2ecf20Sopenharmony_ci sk_common_release(newsk); 47798c2ecf20Sopenharmony_ci newsk = NULL; 47808c2ecf20Sopenharmony_ci } 47818c2ecf20Sopenharmony_ci 47828c2ecf20Sopenharmony_ciout: 47838c2ecf20Sopenharmony_ci release_sock(sk); 47848c2ecf20Sopenharmony_ci *err = error; 47858c2ecf20Sopenharmony_ci return newsk; 47868c2ecf20Sopenharmony_ci} 47878c2ecf20Sopenharmony_ci 47888c2ecf20Sopenharmony_ci/* The SCTP ioctl handler. */ 47898c2ecf20Sopenharmony_cistatic int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) 47908c2ecf20Sopenharmony_ci{ 47918c2ecf20Sopenharmony_ci int rc = -ENOTCONN; 47928c2ecf20Sopenharmony_ci 47938c2ecf20Sopenharmony_ci lock_sock(sk); 47948c2ecf20Sopenharmony_ci 47958c2ecf20Sopenharmony_ci /* 47968c2ecf20Sopenharmony_ci * SEQPACKET-style sockets in LISTENING state are valid, for 47978c2ecf20Sopenharmony_ci * SCTP, so only discard TCP-style sockets in LISTENING state. 47988c2ecf20Sopenharmony_ci */ 47998c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 48008c2ecf20Sopenharmony_ci goto out; 48018c2ecf20Sopenharmony_ci 48028c2ecf20Sopenharmony_ci switch (cmd) { 48038c2ecf20Sopenharmony_ci case SIOCINQ: { 48048c2ecf20Sopenharmony_ci struct sk_buff *skb; 48058c2ecf20Sopenharmony_ci unsigned int amount = 0; 48068c2ecf20Sopenharmony_ci 48078c2ecf20Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 48088c2ecf20Sopenharmony_ci if (skb != NULL) { 48098c2ecf20Sopenharmony_ci /* 48108c2ecf20Sopenharmony_ci * We will only return the amount of this packet since 48118c2ecf20Sopenharmony_ci * that is all that will be read. 48128c2ecf20Sopenharmony_ci */ 48138c2ecf20Sopenharmony_ci amount = skb->len; 48148c2ecf20Sopenharmony_ci } 48158c2ecf20Sopenharmony_ci rc = put_user(amount, (int __user *)arg); 48168c2ecf20Sopenharmony_ci break; 48178c2ecf20Sopenharmony_ci } 48188c2ecf20Sopenharmony_ci default: 48198c2ecf20Sopenharmony_ci rc = -ENOIOCTLCMD; 48208c2ecf20Sopenharmony_ci break; 48218c2ecf20Sopenharmony_ci } 48228c2ecf20Sopenharmony_ciout: 48238c2ecf20Sopenharmony_ci release_sock(sk); 48248c2ecf20Sopenharmony_ci return rc; 48258c2ecf20Sopenharmony_ci} 48268c2ecf20Sopenharmony_ci 48278c2ecf20Sopenharmony_ci/* This is the function which gets called during socket creation to 48288c2ecf20Sopenharmony_ci * initialized the SCTP-specific portion of the sock. 48298c2ecf20Sopenharmony_ci * The sock structure should already be zero-filled memory. 48308c2ecf20Sopenharmony_ci */ 48318c2ecf20Sopenharmony_cistatic int sctp_init_sock(struct sock *sk) 48328c2ecf20Sopenharmony_ci{ 48338c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 48348c2ecf20Sopenharmony_ci struct sctp_sock *sp; 48358c2ecf20Sopenharmony_ci 48368c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p\n", __func__, sk); 48378c2ecf20Sopenharmony_ci 48388c2ecf20Sopenharmony_ci sp = sctp_sk(sk); 48398c2ecf20Sopenharmony_ci 48408c2ecf20Sopenharmony_ci /* Initialize the SCTP per socket area. */ 48418c2ecf20Sopenharmony_ci switch (sk->sk_type) { 48428c2ecf20Sopenharmony_ci case SOCK_SEQPACKET: 48438c2ecf20Sopenharmony_ci sp->type = SCTP_SOCKET_UDP; 48448c2ecf20Sopenharmony_ci break; 48458c2ecf20Sopenharmony_ci case SOCK_STREAM: 48468c2ecf20Sopenharmony_ci sp->type = SCTP_SOCKET_TCP; 48478c2ecf20Sopenharmony_ci break; 48488c2ecf20Sopenharmony_ci default: 48498c2ecf20Sopenharmony_ci return -ESOCKTNOSUPPORT; 48508c2ecf20Sopenharmony_ci } 48518c2ecf20Sopenharmony_ci 48528c2ecf20Sopenharmony_ci sk->sk_gso_type = SKB_GSO_SCTP; 48538c2ecf20Sopenharmony_ci 48548c2ecf20Sopenharmony_ci /* Initialize default send parameters. These parameters can be 48558c2ecf20Sopenharmony_ci * modified with the SCTP_DEFAULT_SEND_PARAM socket option. 48568c2ecf20Sopenharmony_ci */ 48578c2ecf20Sopenharmony_ci sp->default_stream = 0; 48588c2ecf20Sopenharmony_ci sp->default_ppid = 0; 48598c2ecf20Sopenharmony_ci sp->default_flags = 0; 48608c2ecf20Sopenharmony_ci sp->default_context = 0; 48618c2ecf20Sopenharmony_ci sp->default_timetolive = 0; 48628c2ecf20Sopenharmony_ci 48638c2ecf20Sopenharmony_ci sp->default_rcv_context = 0; 48648c2ecf20Sopenharmony_ci sp->max_burst = net->sctp.max_burst; 48658c2ecf20Sopenharmony_ci 48668c2ecf20Sopenharmony_ci sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg; 48678c2ecf20Sopenharmony_ci 48688c2ecf20Sopenharmony_ci /* Initialize default setup parameters. These parameters 48698c2ecf20Sopenharmony_ci * can be modified with the SCTP_INITMSG socket option or 48708c2ecf20Sopenharmony_ci * overridden by the SCTP_INIT CMSG. 48718c2ecf20Sopenharmony_ci */ 48728c2ecf20Sopenharmony_ci sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; 48738c2ecf20Sopenharmony_ci sp->initmsg.sinit_max_instreams = sctp_max_instreams; 48748c2ecf20Sopenharmony_ci sp->initmsg.sinit_max_attempts = net->sctp.max_retrans_init; 48758c2ecf20Sopenharmony_ci sp->initmsg.sinit_max_init_timeo = net->sctp.rto_max; 48768c2ecf20Sopenharmony_ci 48778c2ecf20Sopenharmony_ci /* Initialize default RTO related parameters. These parameters can 48788c2ecf20Sopenharmony_ci * be modified for with the SCTP_RTOINFO socket option. 48798c2ecf20Sopenharmony_ci */ 48808c2ecf20Sopenharmony_ci sp->rtoinfo.srto_initial = net->sctp.rto_initial; 48818c2ecf20Sopenharmony_ci sp->rtoinfo.srto_max = net->sctp.rto_max; 48828c2ecf20Sopenharmony_ci sp->rtoinfo.srto_min = net->sctp.rto_min; 48838c2ecf20Sopenharmony_ci 48848c2ecf20Sopenharmony_ci /* Initialize default association related parameters. These parameters 48858c2ecf20Sopenharmony_ci * can be modified with the SCTP_ASSOCINFO socket option. 48868c2ecf20Sopenharmony_ci */ 48878c2ecf20Sopenharmony_ci sp->assocparams.sasoc_asocmaxrxt = net->sctp.max_retrans_association; 48888c2ecf20Sopenharmony_ci sp->assocparams.sasoc_number_peer_destinations = 0; 48898c2ecf20Sopenharmony_ci sp->assocparams.sasoc_peer_rwnd = 0; 48908c2ecf20Sopenharmony_ci sp->assocparams.sasoc_local_rwnd = 0; 48918c2ecf20Sopenharmony_ci sp->assocparams.sasoc_cookie_life = net->sctp.valid_cookie_life; 48928c2ecf20Sopenharmony_ci 48938c2ecf20Sopenharmony_ci /* Initialize default event subscriptions. By default, all the 48948c2ecf20Sopenharmony_ci * options are off. 48958c2ecf20Sopenharmony_ci */ 48968c2ecf20Sopenharmony_ci sp->subscribe = 0; 48978c2ecf20Sopenharmony_ci 48988c2ecf20Sopenharmony_ci /* Default Peer Address Parameters. These defaults can 48998c2ecf20Sopenharmony_ci * be modified via SCTP_PEER_ADDR_PARAMS 49008c2ecf20Sopenharmony_ci */ 49018c2ecf20Sopenharmony_ci sp->hbinterval = net->sctp.hb_interval; 49028c2ecf20Sopenharmony_ci sp->pathmaxrxt = net->sctp.max_retrans_path; 49038c2ecf20Sopenharmony_ci sp->pf_retrans = net->sctp.pf_retrans; 49048c2ecf20Sopenharmony_ci sp->ps_retrans = net->sctp.ps_retrans; 49058c2ecf20Sopenharmony_ci sp->pf_expose = net->sctp.pf_expose; 49068c2ecf20Sopenharmony_ci sp->pathmtu = 0; /* allow default discovery */ 49078c2ecf20Sopenharmony_ci sp->sackdelay = net->sctp.sack_timeout; 49088c2ecf20Sopenharmony_ci sp->sackfreq = 2; 49098c2ecf20Sopenharmony_ci sp->param_flags = SPP_HB_ENABLE | 49108c2ecf20Sopenharmony_ci SPP_PMTUD_ENABLE | 49118c2ecf20Sopenharmony_ci SPP_SACKDELAY_ENABLE; 49128c2ecf20Sopenharmony_ci sp->default_ss = SCTP_SS_DEFAULT; 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci /* If enabled no SCTP message fragmentation will be performed. 49158c2ecf20Sopenharmony_ci * Configure through SCTP_DISABLE_FRAGMENTS socket option. 49168c2ecf20Sopenharmony_ci */ 49178c2ecf20Sopenharmony_ci sp->disable_fragments = 0; 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci /* Enable Nagle algorithm by default. */ 49208c2ecf20Sopenharmony_ci sp->nodelay = 0; 49218c2ecf20Sopenharmony_ci 49228c2ecf20Sopenharmony_ci sp->recvrcvinfo = 0; 49238c2ecf20Sopenharmony_ci sp->recvnxtinfo = 0; 49248c2ecf20Sopenharmony_ci 49258c2ecf20Sopenharmony_ci /* Enable by default. */ 49268c2ecf20Sopenharmony_ci sp->v4mapped = 1; 49278c2ecf20Sopenharmony_ci 49288c2ecf20Sopenharmony_ci /* Auto-close idle associations after the configured 49298c2ecf20Sopenharmony_ci * number of seconds. A value of 0 disables this 49308c2ecf20Sopenharmony_ci * feature. Configure through the SCTP_AUTOCLOSE socket option, 49318c2ecf20Sopenharmony_ci * for UDP-style sockets only. 49328c2ecf20Sopenharmony_ci */ 49338c2ecf20Sopenharmony_ci sp->autoclose = 0; 49348c2ecf20Sopenharmony_ci 49358c2ecf20Sopenharmony_ci /* User specified fragmentation limit. */ 49368c2ecf20Sopenharmony_ci sp->user_frag = 0; 49378c2ecf20Sopenharmony_ci 49388c2ecf20Sopenharmony_ci sp->adaptation_ind = 0; 49398c2ecf20Sopenharmony_ci 49408c2ecf20Sopenharmony_ci sp->pf = sctp_get_pf_specific(sk->sk_family); 49418c2ecf20Sopenharmony_ci 49428c2ecf20Sopenharmony_ci /* Control variables for partial data delivery. */ 49438c2ecf20Sopenharmony_ci atomic_set(&sp->pd_mode, 0); 49448c2ecf20Sopenharmony_ci skb_queue_head_init(&sp->pd_lobby); 49458c2ecf20Sopenharmony_ci sp->frag_interleave = 0; 49468c2ecf20Sopenharmony_ci 49478c2ecf20Sopenharmony_ci /* Create a per socket endpoint structure. Even if we 49488c2ecf20Sopenharmony_ci * change the data structure relationships, this may still 49498c2ecf20Sopenharmony_ci * be useful for storing pre-connect address information. 49508c2ecf20Sopenharmony_ci */ 49518c2ecf20Sopenharmony_ci sp->ep = sctp_endpoint_new(sk, GFP_KERNEL); 49528c2ecf20Sopenharmony_ci if (!sp->ep) 49538c2ecf20Sopenharmony_ci return -ENOMEM; 49548c2ecf20Sopenharmony_ci 49558c2ecf20Sopenharmony_ci sp->hmac = NULL; 49568c2ecf20Sopenharmony_ci 49578c2ecf20Sopenharmony_ci sk->sk_destruct = sctp_destruct_sock; 49588c2ecf20Sopenharmony_ci 49598c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_INC(sock); 49608c2ecf20Sopenharmony_ci 49618c2ecf20Sopenharmony_ci local_bh_disable(); 49628c2ecf20Sopenharmony_ci sk_sockets_allocated_inc(sk); 49638c2ecf20Sopenharmony_ci sock_prot_inuse_add(net, sk->sk_prot, 1); 49648c2ecf20Sopenharmony_ci 49658c2ecf20Sopenharmony_ci local_bh_enable(); 49668c2ecf20Sopenharmony_ci 49678c2ecf20Sopenharmony_ci return 0; 49688c2ecf20Sopenharmony_ci} 49698c2ecf20Sopenharmony_ci 49708c2ecf20Sopenharmony_ci/* Cleanup any SCTP per socket resources. Must be called with 49718c2ecf20Sopenharmony_ci * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true 49728c2ecf20Sopenharmony_ci */ 49738c2ecf20Sopenharmony_cistatic void sctp_destroy_sock(struct sock *sk) 49748c2ecf20Sopenharmony_ci{ 49758c2ecf20Sopenharmony_ci struct sctp_sock *sp; 49768c2ecf20Sopenharmony_ci 49778c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p\n", __func__, sk); 49788c2ecf20Sopenharmony_ci 49798c2ecf20Sopenharmony_ci /* Release our hold on the endpoint. */ 49808c2ecf20Sopenharmony_ci sp = sctp_sk(sk); 49818c2ecf20Sopenharmony_ci /* This could happen during socket init, thus we bail out 49828c2ecf20Sopenharmony_ci * early, since the rest of the below is not setup either. 49838c2ecf20Sopenharmony_ci */ 49848c2ecf20Sopenharmony_ci if (sp->ep == NULL) 49858c2ecf20Sopenharmony_ci return; 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci if (sp->do_auto_asconf) { 49888c2ecf20Sopenharmony_ci sp->do_auto_asconf = 0; 49898c2ecf20Sopenharmony_ci list_del(&sp->auto_asconf_list); 49908c2ecf20Sopenharmony_ci } 49918c2ecf20Sopenharmony_ci sctp_endpoint_free(sp->ep); 49928c2ecf20Sopenharmony_ci local_bh_disable(); 49938c2ecf20Sopenharmony_ci sk_sockets_allocated_dec(sk); 49948c2ecf20Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 49958c2ecf20Sopenharmony_ci local_bh_enable(); 49968c2ecf20Sopenharmony_ci} 49978c2ecf20Sopenharmony_ci 49988c2ecf20Sopenharmony_ci/* Triggered when there are no references on the socket anymore */ 49998c2ecf20Sopenharmony_cistatic void sctp_destruct_common(struct sock *sk) 50008c2ecf20Sopenharmony_ci{ 50018c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 50028c2ecf20Sopenharmony_ci 50038c2ecf20Sopenharmony_ci /* Free up the HMAC transform. */ 50048c2ecf20Sopenharmony_ci crypto_free_shash(sp->hmac); 50058c2ecf20Sopenharmony_ci} 50068c2ecf20Sopenharmony_ci 50078c2ecf20Sopenharmony_cistatic void sctp_destruct_sock(struct sock *sk) 50088c2ecf20Sopenharmony_ci{ 50098c2ecf20Sopenharmony_ci sctp_destruct_common(sk); 50108c2ecf20Sopenharmony_ci inet_sock_destruct(sk); 50118c2ecf20Sopenharmony_ci} 50128c2ecf20Sopenharmony_ci 50138c2ecf20Sopenharmony_ci/* API 4.1.7 shutdown() - TCP Style Syntax 50148c2ecf20Sopenharmony_ci * int shutdown(int socket, int how); 50158c2ecf20Sopenharmony_ci * 50168c2ecf20Sopenharmony_ci * sd - the socket descriptor of the association to be closed. 50178c2ecf20Sopenharmony_ci * how - Specifies the type of shutdown. The values are 50188c2ecf20Sopenharmony_ci * as follows: 50198c2ecf20Sopenharmony_ci * SHUT_RD 50208c2ecf20Sopenharmony_ci * Disables further receive operations. No SCTP 50218c2ecf20Sopenharmony_ci * protocol action is taken. 50228c2ecf20Sopenharmony_ci * SHUT_WR 50238c2ecf20Sopenharmony_ci * Disables further send operations, and initiates 50248c2ecf20Sopenharmony_ci * the SCTP shutdown sequence. 50258c2ecf20Sopenharmony_ci * SHUT_RDWR 50268c2ecf20Sopenharmony_ci * Disables further send and receive operations 50278c2ecf20Sopenharmony_ci * and initiates the SCTP shutdown sequence. 50288c2ecf20Sopenharmony_ci */ 50298c2ecf20Sopenharmony_cistatic void sctp_shutdown(struct sock *sk, int how) 50308c2ecf20Sopenharmony_ci{ 50318c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 50328c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 50338c2ecf20Sopenharmony_ci 50348c2ecf20Sopenharmony_ci if (!sctp_style(sk, TCP)) 50358c2ecf20Sopenharmony_ci return; 50368c2ecf20Sopenharmony_ci 50378c2ecf20Sopenharmony_ci ep = sctp_sk(sk)->ep; 50388c2ecf20Sopenharmony_ci if (how & SEND_SHUTDOWN && !list_empty(&ep->asocs)) { 50398c2ecf20Sopenharmony_ci struct sctp_association *asoc; 50408c2ecf20Sopenharmony_ci 50418c2ecf20Sopenharmony_ci inet_sk_set_state(sk, SCTP_SS_CLOSING); 50428c2ecf20Sopenharmony_ci asoc = list_entry(ep->asocs.next, 50438c2ecf20Sopenharmony_ci struct sctp_association, asocs); 50448c2ecf20Sopenharmony_ci sctp_primitive_SHUTDOWN(net, asoc, NULL); 50458c2ecf20Sopenharmony_ci } 50468c2ecf20Sopenharmony_ci} 50478c2ecf20Sopenharmony_ci 50488c2ecf20Sopenharmony_ciint sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, 50498c2ecf20Sopenharmony_ci struct sctp_info *info) 50508c2ecf20Sopenharmony_ci{ 50518c2ecf20Sopenharmony_ci struct sctp_transport *prim; 50528c2ecf20Sopenharmony_ci struct list_head *pos; 50538c2ecf20Sopenharmony_ci int mask; 50548c2ecf20Sopenharmony_ci 50558c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 50568c2ecf20Sopenharmony_ci if (!asoc) { 50578c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 50588c2ecf20Sopenharmony_ci 50598c2ecf20Sopenharmony_ci info->sctpi_s_autoclose = sp->autoclose; 50608c2ecf20Sopenharmony_ci info->sctpi_s_adaptation_ind = sp->adaptation_ind; 50618c2ecf20Sopenharmony_ci info->sctpi_s_pd_point = sp->pd_point; 50628c2ecf20Sopenharmony_ci info->sctpi_s_nodelay = sp->nodelay; 50638c2ecf20Sopenharmony_ci info->sctpi_s_disable_fragments = sp->disable_fragments; 50648c2ecf20Sopenharmony_ci info->sctpi_s_v4mapped = sp->v4mapped; 50658c2ecf20Sopenharmony_ci info->sctpi_s_frag_interleave = sp->frag_interleave; 50668c2ecf20Sopenharmony_ci info->sctpi_s_type = sp->type; 50678c2ecf20Sopenharmony_ci 50688c2ecf20Sopenharmony_ci return 0; 50698c2ecf20Sopenharmony_ci } 50708c2ecf20Sopenharmony_ci 50718c2ecf20Sopenharmony_ci info->sctpi_tag = asoc->c.my_vtag; 50728c2ecf20Sopenharmony_ci info->sctpi_state = asoc->state; 50738c2ecf20Sopenharmony_ci info->sctpi_rwnd = asoc->a_rwnd; 50748c2ecf20Sopenharmony_ci info->sctpi_unackdata = asoc->unack_data; 50758c2ecf20Sopenharmony_ci info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 50768c2ecf20Sopenharmony_ci info->sctpi_instrms = asoc->stream.incnt; 50778c2ecf20Sopenharmony_ci info->sctpi_outstrms = asoc->stream.outcnt; 50788c2ecf20Sopenharmony_ci list_for_each(pos, &asoc->base.inqueue.in_chunk_list) 50798c2ecf20Sopenharmony_ci info->sctpi_inqueue++; 50808c2ecf20Sopenharmony_ci list_for_each(pos, &asoc->outqueue.out_chunk_list) 50818c2ecf20Sopenharmony_ci info->sctpi_outqueue++; 50828c2ecf20Sopenharmony_ci info->sctpi_overall_error = asoc->overall_error_count; 50838c2ecf20Sopenharmony_ci info->sctpi_max_burst = asoc->max_burst; 50848c2ecf20Sopenharmony_ci info->sctpi_maxseg = asoc->frag_point; 50858c2ecf20Sopenharmony_ci info->sctpi_peer_rwnd = asoc->peer.rwnd; 50868c2ecf20Sopenharmony_ci info->sctpi_peer_tag = asoc->c.peer_vtag; 50878c2ecf20Sopenharmony_ci 50888c2ecf20Sopenharmony_ci mask = asoc->peer.ecn_capable << 1; 50898c2ecf20Sopenharmony_ci mask = (mask | asoc->peer.ipv4_address) << 1; 50908c2ecf20Sopenharmony_ci mask = (mask | asoc->peer.ipv6_address) << 1; 50918c2ecf20Sopenharmony_ci mask = (mask | asoc->peer.hostname_address) << 1; 50928c2ecf20Sopenharmony_ci mask = (mask | asoc->peer.asconf_capable) << 1; 50938c2ecf20Sopenharmony_ci mask = (mask | asoc->peer.prsctp_capable) << 1; 50948c2ecf20Sopenharmony_ci mask = (mask | asoc->peer.auth_capable); 50958c2ecf20Sopenharmony_ci info->sctpi_peer_capable = mask; 50968c2ecf20Sopenharmony_ci mask = asoc->peer.sack_needed << 1; 50978c2ecf20Sopenharmony_ci mask = (mask | asoc->peer.sack_generation) << 1; 50988c2ecf20Sopenharmony_ci mask = (mask | asoc->peer.zero_window_announced); 50998c2ecf20Sopenharmony_ci info->sctpi_peer_sack = mask; 51008c2ecf20Sopenharmony_ci 51018c2ecf20Sopenharmony_ci info->sctpi_isacks = asoc->stats.isacks; 51028c2ecf20Sopenharmony_ci info->sctpi_osacks = asoc->stats.osacks; 51038c2ecf20Sopenharmony_ci info->sctpi_opackets = asoc->stats.opackets; 51048c2ecf20Sopenharmony_ci info->sctpi_ipackets = asoc->stats.ipackets; 51058c2ecf20Sopenharmony_ci info->sctpi_rtxchunks = asoc->stats.rtxchunks; 51068c2ecf20Sopenharmony_ci info->sctpi_outofseqtsns = asoc->stats.outofseqtsns; 51078c2ecf20Sopenharmony_ci info->sctpi_idupchunks = asoc->stats.idupchunks; 51088c2ecf20Sopenharmony_ci info->sctpi_gapcnt = asoc->stats.gapcnt; 51098c2ecf20Sopenharmony_ci info->sctpi_ouodchunks = asoc->stats.ouodchunks; 51108c2ecf20Sopenharmony_ci info->sctpi_iuodchunks = asoc->stats.iuodchunks; 51118c2ecf20Sopenharmony_ci info->sctpi_oodchunks = asoc->stats.oodchunks; 51128c2ecf20Sopenharmony_ci info->sctpi_iodchunks = asoc->stats.iodchunks; 51138c2ecf20Sopenharmony_ci info->sctpi_octrlchunks = asoc->stats.octrlchunks; 51148c2ecf20Sopenharmony_ci info->sctpi_ictrlchunks = asoc->stats.ictrlchunks; 51158c2ecf20Sopenharmony_ci 51168c2ecf20Sopenharmony_ci prim = asoc->peer.primary_path; 51178c2ecf20Sopenharmony_ci memcpy(&info->sctpi_p_address, &prim->ipaddr, sizeof(prim->ipaddr)); 51188c2ecf20Sopenharmony_ci info->sctpi_p_state = prim->state; 51198c2ecf20Sopenharmony_ci info->sctpi_p_cwnd = prim->cwnd; 51208c2ecf20Sopenharmony_ci info->sctpi_p_srtt = prim->srtt; 51218c2ecf20Sopenharmony_ci info->sctpi_p_rto = jiffies_to_msecs(prim->rto); 51228c2ecf20Sopenharmony_ci info->sctpi_p_hbinterval = prim->hbinterval; 51238c2ecf20Sopenharmony_ci info->sctpi_p_pathmaxrxt = prim->pathmaxrxt; 51248c2ecf20Sopenharmony_ci info->sctpi_p_sackdelay = jiffies_to_msecs(prim->sackdelay); 51258c2ecf20Sopenharmony_ci info->sctpi_p_ssthresh = prim->ssthresh; 51268c2ecf20Sopenharmony_ci info->sctpi_p_partial_bytes_acked = prim->partial_bytes_acked; 51278c2ecf20Sopenharmony_ci info->sctpi_p_flight_size = prim->flight_size; 51288c2ecf20Sopenharmony_ci info->sctpi_p_error = prim->error_count; 51298c2ecf20Sopenharmony_ci 51308c2ecf20Sopenharmony_ci return 0; 51318c2ecf20Sopenharmony_ci} 51328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sctp_get_sctp_info); 51338c2ecf20Sopenharmony_ci 51348c2ecf20Sopenharmony_ci/* use callback to avoid exporting the core structure */ 51358c2ecf20Sopenharmony_civoid sctp_transport_walk_start(struct rhashtable_iter *iter) __acquires(RCU) 51368c2ecf20Sopenharmony_ci{ 51378c2ecf20Sopenharmony_ci rhltable_walk_enter(&sctp_transport_hashtable, iter); 51388c2ecf20Sopenharmony_ci 51398c2ecf20Sopenharmony_ci rhashtable_walk_start(iter); 51408c2ecf20Sopenharmony_ci} 51418c2ecf20Sopenharmony_ci 51428c2ecf20Sopenharmony_civoid sctp_transport_walk_stop(struct rhashtable_iter *iter) __releases(RCU) 51438c2ecf20Sopenharmony_ci{ 51448c2ecf20Sopenharmony_ci rhashtable_walk_stop(iter); 51458c2ecf20Sopenharmony_ci rhashtable_walk_exit(iter); 51468c2ecf20Sopenharmony_ci} 51478c2ecf20Sopenharmony_ci 51488c2ecf20Sopenharmony_cistruct sctp_transport *sctp_transport_get_next(struct net *net, 51498c2ecf20Sopenharmony_ci struct rhashtable_iter *iter) 51508c2ecf20Sopenharmony_ci{ 51518c2ecf20Sopenharmony_ci struct sctp_transport *t; 51528c2ecf20Sopenharmony_ci 51538c2ecf20Sopenharmony_ci t = rhashtable_walk_next(iter); 51548c2ecf20Sopenharmony_ci for (; t; t = rhashtable_walk_next(iter)) { 51558c2ecf20Sopenharmony_ci if (IS_ERR(t)) { 51568c2ecf20Sopenharmony_ci if (PTR_ERR(t) == -EAGAIN) 51578c2ecf20Sopenharmony_ci continue; 51588c2ecf20Sopenharmony_ci break; 51598c2ecf20Sopenharmony_ci } 51608c2ecf20Sopenharmony_ci 51618c2ecf20Sopenharmony_ci if (!sctp_transport_hold(t)) 51628c2ecf20Sopenharmony_ci continue; 51638c2ecf20Sopenharmony_ci 51648c2ecf20Sopenharmony_ci if (net_eq(t->asoc->base.net, net) && 51658c2ecf20Sopenharmony_ci t->asoc->peer.primary_path == t) 51668c2ecf20Sopenharmony_ci break; 51678c2ecf20Sopenharmony_ci 51688c2ecf20Sopenharmony_ci sctp_transport_put(t); 51698c2ecf20Sopenharmony_ci } 51708c2ecf20Sopenharmony_ci 51718c2ecf20Sopenharmony_ci return t; 51728c2ecf20Sopenharmony_ci} 51738c2ecf20Sopenharmony_ci 51748c2ecf20Sopenharmony_cistruct sctp_transport *sctp_transport_get_idx(struct net *net, 51758c2ecf20Sopenharmony_ci struct rhashtable_iter *iter, 51768c2ecf20Sopenharmony_ci int pos) 51778c2ecf20Sopenharmony_ci{ 51788c2ecf20Sopenharmony_ci struct sctp_transport *t; 51798c2ecf20Sopenharmony_ci 51808c2ecf20Sopenharmony_ci if (!pos) 51818c2ecf20Sopenharmony_ci return SEQ_START_TOKEN; 51828c2ecf20Sopenharmony_ci 51838c2ecf20Sopenharmony_ci while ((t = sctp_transport_get_next(net, iter)) && !IS_ERR(t)) { 51848c2ecf20Sopenharmony_ci if (!--pos) 51858c2ecf20Sopenharmony_ci break; 51868c2ecf20Sopenharmony_ci sctp_transport_put(t); 51878c2ecf20Sopenharmony_ci } 51888c2ecf20Sopenharmony_ci 51898c2ecf20Sopenharmony_ci return t; 51908c2ecf20Sopenharmony_ci} 51918c2ecf20Sopenharmony_ci 51928c2ecf20Sopenharmony_ciint sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), 51938c2ecf20Sopenharmony_ci void *p) { 51948c2ecf20Sopenharmony_ci int err = 0; 51958c2ecf20Sopenharmony_ci int hash = 0; 51968c2ecf20Sopenharmony_ci struct sctp_ep_common *epb; 51978c2ecf20Sopenharmony_ci struct sctp_hashbucket *head; 51988c2ecf20Sopenharmony_ci 51998c2ecf20Sopenharmony_ci for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize; 52008c2ecf20Sopenharmony_ci hash++, head++) { 52018c2ecf20Sopenharmony_ci read_lock_bh(&head->lock); 52028c2ecf20Sopenharmony_ci sctp_for_each_hentry(epb, &head->chain) { 52038c2ecf20Sopenharmony_ci err = cb(sctp_ep(epb), p); 52048c2ecf20Sopenharmony_ci if (err) 52058c2ecf20Sopenharmony_ci break; 52068c2ecf20Sopenharmony_ci } 52078c2ecf20Sopenharmony_ci read_unlock_bh(&head->lock); 52088c2ecf20Sopenharmony_ci } 52098c2ecf20Sopenharmony_ci 52108c2ecf20Sopenharmony_ci return err; 52118c2ecf20Sopenharmony_ci} 52128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sctp_for_each_endpoint); 52138c2ecf20Sopenharmony_ci 52148c2ecf20Sopenharmony_ciint sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *), 52158c2ecf20Sopenharmony_ci struct net *net, 52168c2ecf20Sopenharmony_ci const union sctp_addr *laddr, 52178c2ecf20Sopenharmony_ci const union sctp_addr *paddr, void *p) 52188c2ecf20Sopenharmony_ci{ 52198c2ecf20Sopenharmony_ci struct sctp_transport *transport; 52208c2ecf20Sopenharmony_ci int err; 52218c2ecf20Sopenharmony_ci 52228c2ecf20Sopenharmony_ci rcu_read_lock(); 52238c2ecf20Sopenharmony_ci transport = sctp_addrs_lookup_transport(net, laddr, paddr); 52248c2ecf20Sopenharmony_ci rcu_read_unlock(); 52258c2ecf20Sopenharmony_ci if (!transport) 52268c2ecf20Sopenharmony_ci return -ENOENT; 52278c2ecf20Sopenharmony_ci 52288c2ecf20Sopenharmony_ci err = cb(transport, p); 52298c2ecf20Sopenharmony_ci sctp_transport_put(transport); 52308c2ecf20Sopenharmony_ci 52318c2ecf20Sopenharmony_ci return err; 52328c2ecf20Sopenharmony_ci} 52338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sctp_transport_lookup_process); 52348c2ecf20Sopenharmony_ci 52358c2ecf20Sopenharmony_ciint sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done, 52368c2ecf20Sopenharmony_ci struct net *net, int *pos, void *p) 52378c2ecf20Sopenharmony_ci{ 52388c2ecf20Sopenharmony_ci struct rhashtable_iter hti; 52398c2ecf20Sopenharmony_ci struct sctp_transport *tsp; 52408c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 52418c2ecf20Sopenharmony_ci int ret; 52428c2ecf20Sopenharmony_ci 52438c2ecf20Sopenharmony_ciagain: 52448c2ecf20Sopenharmony_ci ret = 0; 52458c2ecf20Sopenharmony_ci sctp_transport_walk_start(&hti); 52468c2ecf20Sopenharmony_ci 52478c2ecf20Sopenharmony_ci tsp = sctp_transport_get_idx(net, &hti, *pos + 1); 52488c2ecf20Sopenharmony_ci for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) { 52498c2ecf20Sopenharmony_ci ep = tsp->asoc->ep; 52508c2ecf20Sopenharmony_ci if (sctp_endpoint_hold(ep)) { /* asoc can be peeled off */ 52518c2ecf20Sopenharmony_ci ret = cb(ep, tsp, p); 52528c2ecf20Sopenharmony_ci if (ret) 52538c2ecf20Sopenharmony_ci break; 52548c2ecf20Sopenharmony_ci sctp_endpoint_put(ep); 52558c2ecf20Sopenharmony_ci } 52568c2ecf20Sopenharmony_ci (*pos)++; 52578c2ecf20Sopenharmony_ci sctp_transport_put(tsp); 52588c2ecf20Sopenharmony_ci } 52598c2ecf20Sopenharmony_ci sctp_transport_walk_stop(&hti); 52608c2ecf20Sopenharmony_ci 52618c2ecf20Sopenharmony_ci if (ret) { 52628c2ecf20Sopenharmony_ci if (cb_done && !cb_done(ep, tsp, p)) { 52638c2ecf20Sopenharmony_ci (*pos)++; 52648c2ecf20Sopenharmony_ci sctp_endpoint_put(ep); 52658c2ecf20Sopenharmony_ci sctp_transport_put(tsp); 52668c2ecf20Sopenharmony_ci goto again; 52678c2ecf20Sopenharmony_ci } 52688c2ecf20Sopenharmony_ci sctp_endpoint_put(ep); 52698c2ecf20Sopenharmony_ci sctp_transport_put(tsp); 52708c2ecf20Sopenharmony_ci } 52718c2ecf20Sopenharmony_ci 52728c2ecf20Sopenharmony_ci return ret; 52738c2ecf20Sopenharmony_ci} 52748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sctp_transport_traverse_process); 52758c2ecf20Sopenharmony_ci 52768c2ecf20Sopenharmony_ci/* 7.2.1 Association Status (SCTP_STATUS) 52778c2ecf20Sopenharmony_ci 52788c2ecf20Sopenharmony_ci * Applications can retrieve current status information about an 52798c2ecf20Sopenharmony_ci * association, including association state, peer receiver window size, 52808c2ecf20Sopenharmony_ci * number of unacked data chunks, and number of data chunks pending 52818c2ecf20Sopenharmony_ci * receipt. This information is read-only. 52828c2ecf20Sopenharmony_ci */ 52838c2ecf20Sopenharmony_cistatic int sctp_getsockopt_sctp_status(struct sock *sk, int len, 52848c2ecf20Sopenharmony_ci char __user *optval, 52858c2ecf20Sopenharmony_ci int __user *optlen) 52868c2ecf20Sopenharmony_ci{ 52878c2ecf20Sopenharmony_ci struct sctp_status status; 52888c2ecf20Sopenharmony_ci struct sctp_association *asoc = NULL; 52898c2ecf20Sopenharmony_ci struct sctp_transport *transport; 52908c2ecf20Sopenharmony_ci sctp_assoc_t associd; 52918c2ecf20Sopenharmony_ci int retval = 0; 52928c2ecf20Sopenharmony_ci 52938c2ecf20Sopenharmony_ci if (len < sizeof(status)) { 52948c2ecf20Sopenharmony_ci retval = -EINVAL; 52958c2ecf20Sopenharmony_ci goto out; 52968c2ecf20Sopenharmony_ci } 52978c2ecf20Sopenharmony_ci 52988c2ecf20Sopenharmony_ci len = sizeof(status); 52998c2ecf20Sopenharmony_ci if (copy_from_user(&status, optval, len)) { 53008c2ecf20Sopenharmony_ci retval = -EFAULT; 53018c2ecf20Sopenharmony_ci goto out; 53028c2ecf20Sopenharmony_ci } 53038c2ecf20Sopenharmony_ci 53048c2ecf20Sopenharmony_ci associd = status.sstat_assoc_id; 53058c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, associd); 53068c2ecf20Sopenharmony_ci if (!asoc) { 53078c2ecf20Sopenharmony_ci retval = -EINVAL; 53088c2ecf20Sopenharmony_ci goto out; 53098c2ecf20Sopenharmony_ci } 53108c2ecf20Sopenharmony_ci 53118c2ecf20Sopenharmony_ci transport = asoc->peer.primary_path; 53128c2ecf20Sopenharmony_ci 53138c2ecf20Sopenharmony_ci status.sstat_assoc_id = sctp_assoc2id(asoc); 53148c2ecf20Sopenharmony_ci status.sstat_state = sctp_assoc_to_state(asoc); 53158c2ecf20Sopenharmony_ci status.sstat_rwnd = asoc->peer.rwnd; 53168c2ecf20Sopenharmony_ci status.sstat_unackdata = asoc->unack_data; 53178c2ecf20Sopenharmony_ci 53188c2ecf20Sopenharmony_ci status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 53198c2ecf20Sopenharmony_ci status.sstat_instrms = asoc->stream.incnt; 53208c2ecf20Sopenharmony_ci status.sstat_outstrms = asoc->stream.outcnt; 53218c2ecf20Sopenharmony_ci status.sstat_fragmentation_point = asoc->frag_point; 53228c2ecf20Sopenharmony_ci status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 53238c2ecf20Sopenharmony_ci memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, 53248c2ecf20Sopenharmony_ci transport->af_specific->sockaddr_len); 53258c2ecf20Sopenharmony_ci /* Map ipv4 address into v4-mapped-on-v6 address. */ 53268c2ecf20Sopenharmony_ci sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), 53278c2ecf20Sopenharmony_ci (union sctp_addr *)&status.sstat_primary.spinfo_address); 53288c2ecf20Sopenharmony_ci status.sstat_primary.spinfo_state = transport->state; 53298c2ecf20Sopenharmony_ci status.sstat_primary.spinfo_cwnd = transport->cwnd; 53308c2ecf20Sopenharmony_ci status.sstat_primary.spinfo_srtt = transport->srtt; 53318c2ecf20Sopenharmony_ci status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto); 53328c2ecf20Sopenharmony_ci status.sstat_primary.spinfo_mtu = transport->pathmtu; 53338c2ecf20Sopenharmony_ci 53348c2ecf20Sopenharmony_ci if (status.sstat_primary.spinfo_state == SCTP_UNKNOWN) 53358c2ecf20Sopenharmony_ci status.sstat_primary.spinfo_state = SCTP_ACTIVE; 53368c2ecf20Sopenharmony_ci 53378c2ecf20Sopenharmony_ci if (put_user(len, optlen)) { 53388c2ecf20Sopenharmony_ci retval = -EFAULT; 53398c2ecf20Sopenharmony_ci goto out; 53408c2ecf20Sopenharmony_ci } 53418c2ecf20Sopenharmony_ci 53428c2ecf20Sopenharmony_ci pr_debug("%s: len:%d, state:%d, rwnd:%d, assoc_id:%d\n", 53438c2ecf20Sopenharmony_ci __func__, len, status.sstat_state, status.sstat_rwnd, 53448c2ecf20Sopenharmony_ci status.sstat_assoc_id); 53458c2ecf20Sopenharmony_ci 53468c2ecf20Sopenharmony_ci if (copy_to_user(optval, &status, len)) { 53478c2ecf20Sopenharmony_ci retval = -EFAULT; 53488c2ecf20Sopenharmony_ci goto out; 53498c2ecf20Sopenharmony_ci } 53508c2ecf20Sopenharmony_ci 53518c2ecf20Sopenharmony_ciout: 53528c2ecf20Sopenharmony_ci return retval; 53538c2ecf20Sopenharmony_ci} 53548c2ecf20Sopenharmony_ci 53558c2ecf20Sopenharmony_ci 53568c2ecf20Sopenharmony_ci/* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO) 53578c2ecf20Sopenharmony_ci * 53588c2ecf20Sopenharmony_ci * Applications can retrieve information about a specific peer address 53598c2ecf20Sopenharmony_ci * of an association, including its reachability state, congestion 53608c2ecf20Sopenharmony_ci * window, and retransmission timer values. This information is 53618c2ecf20Sopenharmony_ci * read-only. 53628c2ecf20Sopenharmony_ci */ 53638c2ecf20Sopenharmony_cistatic int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, 53648c2ecf20Sopenharmony_ci char __user *optval, 53658c2ecf20Sopenharmony_ci int __user *optlen) 53668c2ecf20Sopenharmony_ci{ 53678c2ecf20Sopenharmony_ci struct sctp_paddrinfo pinfo; 53688c2ecf20Sopenharmony_ci struct sctp_transport *transport; 53698c2ecf20Sopenharmony_ci int retval = 0; 53708c2ecf20Sopenharmony_ci 53718c2ecf20Sopenharmony_ci if (len < sizeof(pinfo)) { 53728c2ecf20Sopenharmony_ci retval = -EINVAL; 53738c2ecf20Sopenharmony_ci goto out; 53748c2ecf20Sopenharmony_ci } 53758c2ecf20Sopenharmony_ci 53768c2ecf20Sopenharmony_ci len = sizeof(pinfo); 53778c2ecf20Sopenharmony_ci if (copy_from_user(&pinfo, optval, len)) { 53788c2ecf20Sopenharmony_ci retval = -EFAULT; 53798c2ecf20Sopenharmony_ci goto out; 53808c2ecf20Sopenharmony_ci } 53818c2ecf20Sopenharmony_ci 53828c2ecf20Sopenharmony_ci transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address, 53838c2ecf20Sopenharmony_ci pinfo.spinfo_assoc_id); 53848c2ecf20Sopenharmony_ci if (!transport) { 53858c2ecf20Sopenharmony_ci retval = -EINVAL; 53868c2ecf20Sopenharmony_ci goto out; 53878c2ecf20Sopenharmony_ci } 53888c2ecf20Sopenharmony_ci 53898c2ecf20Sopenharmony_ci if (transport->state == SCTP_PF && 53908c2ecf20Sopenharmony_ci transport->asoc->pf_expose == SCTP_PF_EXPOSE_DISABLE) { 53918c2ecf20Sopenharmony_ci retval = -EACCES; 53928c2ecf20Sopenharmony_ci goto out; 53938c2ecf20Sopenharmony_ci } 53948c2ecf20Sopenharmony_ci 53958c2ecf20Sopenharmony_ci pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 53968c2ecf20Sopenharmony_ci pinfo.spinfo_state = transport->state; 53978c2ecf20Sopenharmony_ci pinfo.spinfo_cwnd = transport->cwnd; 53988c2ecf20Sopenharmony_ci pinfo.spinfo_srtt = transport->srtt; 53998c2ecf20Sopenharmony_ci pinfo.spinfo_rto = jiffies_to_msecs(transport->rto); 54008c2ecf20Sopenharmony_ci pinfo.spinfo_mtu = transport->pathmtu; 54018c2ecf20Sopenharmony_ci 54028c2ecf20Sopenharmony_ci if (pinfo.spinfo_state == SCTP_UNKNOWN) 54038c2ecf20Sopenharmony_ci pinfo.spinfo_state = SCTP_ACTIVE; 54048c2ecf20Sopenharmony_ci 54058c2ecf20Sopenharmony_ci if (put_user(len, optlen)) { 54068c2ecf20Sopenharmony_ci retval = -EFAULT; 54078c2ecf20Sopenharmony_ci goto out; 54088c2ecf20Sopenharmony_ci } 54098c2ecf20Sopenharmony_ci 54108c2ecf20Sopenharmony_ci if (copy_to_user(optval, &pinfo, len)) { 54118c2ecf20Sopenharmony_ci retval = -EFAULT; 54128c2ecf20Sopenharmony_ci goto out; 54138c2ecf20Sopenharmony_ci } 54148c2ecf20Sopenharmony_ci 54158c2ecf20Sopenharmony_ciout: 54168c2ecf20Sopenharmony_ci return retval; 54178c2ecf20Sopenharmony_ci} 54188c2ecf20Sopenharmony_ci 54198c2ecf20Sopenharmony_ci/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) 54208c2ecf20Sopenharmony_ci * 54218c2ecf20Sopenharmony_ci * This option is a on/off flag. If enabled no SCTP message 54228c2ecf20Sopenharmony_ci * fragmentation will be performed. Instead if a message being sent 54238c2ecf20Sopenharmony_ci * exceeds the current PMTU size, the message will NOT be sent and 54248c2ecf20Sopenharmony_ci * instead a error will be indicated to the user. 54258c2ecf20Sopenharmony_ci */ 54268c2ecf20Sopenharmony_cistatic int sctp_getsockopt_disable_fragments(struct sock *sk, int len, 54278c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 54288c2ecf20Sopenharmony_ci{ 54298c2ecf20Sopenharmony_ci int val; 54308c2ecf20Sopenharmony_ci 54318c2ecf20Sopenharmony_ci if (len < sizeof(int)) 54328c2ecf20Sopenharmony_ci return -EINVAL; 54338c2ecf20Sopenharmony_ci 54348c2ecf20Sopenharmony_ci len = sizeof(int); 54358c2ecf20Sopenharmony_ci val = (sctp_sk(sk)->disable_fragments == 1); 54368c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 54378c2ecf20Sopenharmony_ci return -EFAULT; 54388c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 54398c2ecf20Sopenharmony_ci return -EFAULT; 54408c2ecf20Sopenharmony_ci return 0; 54418c2ecf20Sopenharmony_ci} 54428c2ecf20Sopenharmony_ci 54438c2ecf20Sopenharmony_ci/* 7.1.15 Set notification and ancillary events (SCTP_EVENTS) 54448c2ecf20Sopenharmony_ci * 54458c2ecf20Sopenharmony_ci * This socket option is used to specify various notifications and 54468c2ecf20Sopenharmony_ci * ancillary data the user wishes to receive. 54478c2ecf20Sopenharmony_ci */ 54488c2ecf20Sopenharmony_cistatic int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, 54498c2ecf20Sopenharmony_ci int __user *optlen) 54508c2ecf20Sopenharmony_ci{ 54518c2ecf20Sopenharmony_ci struct sctp_event_subscribe subscribe; 54528c2ecf20Sopenharmony_ci __u8 *sn_type = (__u8 *)&subscribe; 54538c2ecf20Sopenharmony_ci int i; 54548c2ecf20Sopenharmony_ci 54558c2ecf20Sopenharmony_ci if (len == 0) 54568c2ecf20Sopenharmony_ci return -EINVAL; 54578c2ecf20Sopenharmony_ci if (len > sizeof(struct sctp_event_subscribe)) 54588c2ecf20Sopenharmony_ci len = sizeof(struct sctp_event_subscribe); 54598c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 54608c2ecf20Sopenharmony_ci return -EFAULT; 54618c2ecf20Sopenharmony_ci 54628c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 54638c2ecf20Sopenharmony_ci sn_type[i] = sctp_ulpevent_type_enabled(sctp_sk(sk)->subscribe, 54648c2ecf20Sopenharmony_ci SCTP_SN_TYPE_BASE + i); 54658c2ecf20Sopenharmony_ci 54668c2ecf20Sopenharmony_ci if (copy_to_user(optval, &subscribe, len)) 54678c2ecf20Sopenharmony_ci return -EFAULT; 54688c2ecf20Sopenharmony_ci 54698c2ecf20Sopenharmony_ci return 0; 54708c2ecf20Sopenharmony_ci} 54718c2ecf20Sopenharmony_ci 54728c2ecf20Sopenharmony_ci/* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) 54738c2ecf20Sopenharmony_ci * 54748c2ecf20Sopenharmony_ci * This socket option is applicable to the UDP-style socket only. When 54758c2ecf20Sopenharmony_ci * set it will cause associations that are idle for more than the 54768c2ecf20Sopenharmony_ci * specified number of seconds to automatically close. An association 54778c2ecf20Sopenharmony_ci * being idle is defined an association that has NOT sent or received 54788c2ecf20Sopenharmony_ci * user data. The special value of '0' indicates that no automatic 54798c2ecf20Sopenharmony_ci * close of any associations should be performed. The option expects an 54808c2ecf20Sopenharmony_ci * integer defining the number of seconds of idle time before an 54818c2ecf20Sopenharmony_ci * association is closed. 54828c2ecf20Sopenharmony_ci */ 54838c2ecf20Sopenharmony_cistatic int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optval, int __user *optlen) 54848c2ecf20Sopenharmony_ci{ 54858c2ecf20Sopenharmony_ci /* Applicable to UDP-style socket only */ 54868c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 54878c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 54888c2ecf20Sopenharmony_ci if (len < sizeof(int)) 54898c2ecf20Sopenharmony_ci return -EINVAL; 54908c2ecf20Sopenharmony_ci len = sizeof(int); 54918c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 54928c2ecf20Sopenharmony_ci return -EFAULT; 54938c2ecf20Sopenharmony_ci if (put_user(sctp_sk(sk)->autoclose, (int __user *)optval)) 54948c2ecf20Sopenharmony_ci return -EFAULT; 54958c2ecf20Sopenharmony_ci return 0; 54968c2ecf20Sopenharmony_ci} 54978c2ecf20Sopenharmony_ci 54988c2ecf20Sopenharmony_ci/* Helper routine to branch off an association to a new socket. */ 54998c2ecf20Sopenharmony_ciint sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) 55008c2ecf20Sopenharmony_ci{ 55018c2ecf20Sopenharmony_ci struct sctp_association *asoc = sctp_id2assoc(sk, id); 55028c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 55038c2ecf20Sopenharmony_ci struct socket *sock; 55048c2ecf20Sopenharmony_ci int err = 0; 55058c2ecf20Sopenharmony_ci 55068c2ecf20Sopenharmony_ci /* Do not peel off from one netns to another one. */ 55078c2ecf20Sopenharmony_ci if (!net_eq(current->nsproxy->net_ns, sock_net(sk))) 55088c2ecf20Sopenharmony_ci return -EINVAL; 55098c2ecf20Sopenharmony_ci 55108c2ecf20Sopenharmony_ci if (!asoc) 55118c2ecf20Sopenharmony_ci return -EINVAL; 55128c2ecf20Sopenharmony_ci 55138c2ecf20Sopenharmony_ci /* An association cannot be branched off from an already peeled-off 55148c2ecf20Sopenharmony_ci * socket, nor is this supported for tcp style sockets. 55158c2ecf20Sopenharmony_ci */ 55168c2ecf20Sopenharmony_ci if (!sctp_style(sk, UDP)) 55178c2ecf20Sopenharmony_ci return -EINVAL; 55188c2ecf20Sopenharmony_ci 55198c2ecf20Sopenharmony_ci /* Create a new socket. */ 55208c2ecf20Sopenharmony_ci err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); 55218c2ecf20Sopenharmony_ci if (err < 0) 55228c2ecf20Sopenharmony_ci return err; 55238c2ecf20Sopenharmony_ci 55248c2ecf20Sopenharmony_ci sctp_copy_sock(sock->sk, sk, asoc); 55258c2ecf20Sopenharmony_ci 55268c2ecf20Sopenharmony_ci /* Make peeled-off sockets more like 1-1 accepted sockets. 55278c2ecf20Sopenharmony_ci * Set the daddr and initialize id to something more random and also 55288c2ecf20Sopenharmony_ci * copy over any ip options. 55298c2ecf20Sopenharmony_ci */ 55308c2ecf20Sopenharmony_ci sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sock->sk); 55318c2ecf20Sopenharmony_ci sp->pf->copy_ip_options(sk, sock->sk); 55328c2ecf20Sopenharmony_ci 55338c2ecf20Sopenharmony_ci /* Populate the fields of the newsk from the oldsk and migrate the 55348c2ecf20Sopenharmony_ci * asoc to the newsk. 55358c2ecf20Sopenharmony_ci */ 55368c2ecf20Sopenharmony_ci err = sctp_sock_migrate(sk, sock->sk, asoc, 55378c2ecf20Sopenharmony_ci SCTP_SOCKET_UDP_HIGH_BANDWIDTH); 55388c2ecf20Sopenharmony_ci if (err) { 55398c2ecf20Sopenharmony_ci sock_release(sock); 55408c2ecf20Sopenharmony_ci sock = NULL; 55418c2ecf20Sopenharmony_ci } 55428c2ecf20Sopenharmony_ci 55438c2ecf20Sopenharmony_ci *sockp = sock; 55448c2ecf20Sopenharmony_ci 55458c2ecf20Sopenharmony_ci return err; 55468c2ecf20Sopenharmony_ci} 55478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sctp_do_peeloff); 55488c2ecf20Sopenharmony_ci 55498c2ecf20Sopenharmony_cistatic int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *peeloff, 55508c2ecf20Sopenharmony_ci struct file **newfile, unsigned flags) 55518c2ecf20Sopenharmony_ci{ 55528c2ecf20Sopenharmony_ci struct socket *newsock; 55538c2ecf20Sopenharmony_ci int retval; 55548c2ecf20Sopenharmony_ci 55558c2ecf20Sopenharmony_ci retval = sctp_do_peeloff(sk, peeloff->associd, &newsock); 55568c2ecf20Sopenharmony_ci if (retval < 0) 55578c2ecf20Sopenharmony_ci goto out; 55588c2ecf20Sopenharmony_ci 55598c2ecf20Sopenharmony_ci /* Map the socket to an unused fd that can be returned to the user. */ 55608c2ecf20Sopenharmony_ci retval = get_unused_fd_flags(flags & SOCK_CLOEXEC); 55618c2ecf20Sopenharmony_ci if (retval < 0) { 55628c2ecf20Sopenharmony_ci sock_release(newsock); 55638c2ecf20Sopenharmony_ci goto out; 55648c2ecf20Sopenharmony_ci } 55658c2ecf20Sopenharmony_ci 55668c2ecf20Sopenharmony_ci *newfile = sock_alloc_file(newsock, 0, NULL); 55678c2ecf20Sopenharmony_ci if (IS_ERR(*newfile)) { 55688c2ecf20Sopenharmony_ci put_unused_fd(retval); 55698c2ecf20Sopenharmony_ci retval = PTR_ERR(*newfile); 55708c2ecf20Sopenharmony_ci *newfile = NULL; 55718c2ecf20Sopenharmony_ci return retval; 55728c2ecf20Sopenharmony_ci } 55738c2ecf20Sopenharmony_ci 55748c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk, 55758c2ecf20Sopenharmony_ci retval); 55768c2ecf20Sopenharmony_ci 55778c2ecf20Sopenharmony_ci peeloff->sd = retval; 55788c2ecf20Sopenharmony_ci 55798c2ecf20Sopenharmony_ci if (flags & SOCK_NONBLOCK) 55808c2ecf20Sopenharmony_ci (*newfile)->f_flags |= O_NONBLOCK; 55818c2ecf20Sopenharmony_ciout: 55828c2ecf20Sopenharmony_ci return retval; 55838c2ecf20Sopenharmony_ci} 55848c2ecf20Sopenharmony_ci 55858c2ecf20Sopenharmony_cistatic int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) 55868c2ecf20Sopenharmony_ci{ 55878c2ecf20Sopenharmony_ci sctp_peeloff_arg_t peeloff; 55888c2ecf20Sopenharmony_ci struct file *newfile = NULL; 55898c2ecf20Sopenharmony_ci int retval = 0; 55908c2ecf20Sopenharmony_ci 55918c2ecf20Sopenharmony_ci if (len < sizeof(sctp_peeloff_arg_t)) 55928c2ecf20Sopenharmony_ci return -EINVAL; 55938c2ecf20Sopenharmony_ci len = sizeof(sctp_peeloff_arg_t); 55948c2ecf20Sopenharmony_ci if (copy_from_user(&peeloff, optval, len)) 55958c2ecf20Sopenharmony_ci return -EFAULT; 55968c2ecf20Sopenharmony_ci 55978c2ecf20Sopenharmony_ci retval = sctp_getsockopt_peeloff_common(sk, &peeloff, &newfile, 0); 55988c2ecf20Sopenharmony_ci if (retval < 0) 55998c2ecf20Sopenharmony_ci goto out; 56008c2ecf20Sopenharmony_ci 56018c2ecf20Sopenharmony_ci /* Return the fd mapped to the new socket. */ 56028c2ecf20Sopenharmony_ci if (put_user(len, optlen)) { 56038c2ecf20Sopenharmony_ci fput(newfile); 56048c2ecf20Sopenharmony_ci put_unused_fd(retval); 56058c2ecf20Sopenharmony_ci return -EFAULT; 56068c2ecf20Sopenharmony_ci } 56078c2ecf20Sopenharmony_ci 56088c2ecf20Sopenharmony_ci if (copy_to_user(optval, &peeloff, len)) { 56098c2ecf20Sopenharmony_ci fput(newfile); 56108c2ecf20Sopenharmony_ci put_unused_fd(retval); 56118c2ecf20Sopenharmony_ci return -EFAULT; 56128c2ecf20Sopenharmony_ci } 56138c2ecf20Sopenharmony_ci fd_install(retval, newfile); 56148c2ecf20Sopenharmony_ciout: 56158c2ecf20Sopenharmony_ci return retval; 56168c2ecf20Sopenharmony_ci} 56178c2ecf20Sopenharmony_ci 56188c2ecf20Sopenharmony_cistatic int sctp_getsockopt_peeloff_flags(struct sock *sk, int len, 56198c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 56208c2ecf20Sopenharmony_ci{ 56218c2ecf20Sopenharmony_ci sctp_peeloff_flags_arg_t peeloff; 56228c2ecf20Sopenharmony_ci struct file *newfile = NULL; 56238c2ecf20Sopenharmony_ci int retval = 0; 56248c2ecf20Sopenharmony_ci 56258c2ecf20Sopenharmony_ci if (len < sizeof(sctp_peeloff_flags_arg_t)) 56268c2ecf20Sopenharmony_ci return -EINVAL; 56278c2ecf20Sopenharmony_ci len = sizeof(sctp_peeloff_flags_arg_t); 56288c2ecf20Sopenharmony_ci if (copy_from_user(&peeloff, optval, len)) 56298c2ecf20Sopenharmony_ci return -EFAULT; 56308c2ecf20Sopenharmony_ci 56318c2ecf20Sopenharmony_ci retval = sctp_getsockopt_peeloff_common(sk, &peeloff.p_arg, 56328c2ecf20Sopenharmony_ci &newfile, peeloff.flags); 56338c2ecf20Sopenharmony_ci if (retval < 0) 56348c2ecf20Sopenharmony_ci goto out; 56358c2ecf20Sopenharmony_ci 56368c2ecf20Sopenharmony_ci /* Return the fd mapped to the new socket. */ 56378c2ecf20Sopenharmony_ci if (put_user(len, optlen)) { 56388c2ecf20Sopenharmony_ci fput(newfile); 56398c2ecf20Sopenharmony_ci put_unused_fd(retval); 56408c2ecf20Sopenharmony_ci return -EFAULT; 56418c2ecf20Sopenharmony_ci } 56428c2ecf20Sopenharmony_ci 56438c2ecf20Sopenharmony_ci if (copy_to_user(optval, &peeloff, len)) { 56448c2ecf20Sopenharmony_ci fput(newfile); 56458c2ecf20Sopenharmony_ci put_unused_fd(retval); 56468c2ecf20Sopenharmony_ci return -EFAULT; 56478c2ecf20Sopenharmony_ci } 56488c2ecf20Sopenharmony_ci fd_install(retval, newfile); 56498c2ecf20Sopenharmony_ciout: 56508c2ecf20Sopenharmony_ci return retval; 56518c2ecf20Sopenharmony_ci} 56528c2ecf20Sopenharmony_ci 56538c2ecf20Sopenharmony_ci/* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) 56548c2ecf20Sopenharmony_ci * 56558c2ecf20Sopenharmony_ci * Applications can enable or disable heartbeats for any peer address of 56568c2ecf20Sopenharmony_ci * an association, modify an address's heartbeat interval, force a 56578c2ecf20Sopenharmony_ci * heartbeat to be sent immediately, and adjust the address's maximum 56588c2ecf20Sopenharmony_ci * number of retransmissions sent before an address is considered 56598c2ecf20Sopenharmony_ci * unreachable. The following structure is used to access and modify an 56608c2ecf20Sopenharmony_ci * address's parameters: 56618c2ecf20Sopenharmony_ci * 56628c2ecf20Sopenharmony_ci * struct sctp_paddrparams { 56638c2ecf20Sopenharmony_ci * sctp_assoc_t spp_assoc_id; 56648c2ecf20Sopenharmony_ci * struct sockaddr_storage spp_address; 56658c2ecf20Sopenharmony_ci * uint32_t spp_hbinterval; 56668c2ecf20Sopenharmony_ci * uint16_t spp_pathmaxrxt; 56678c2ecf20Sopenharmony_ci * uint32_t spp_pathmtu; 56688c2ecf20Sopenharmony_ci * uint32_t spp_sackdelay; 56698c2ecf20Sopenharmony_ci * uint32_t spp_flags; 56708c2ecf20Sopenharmony_ci * }; 56718c2ecf20Sopenharmony_ci * 56728c2ecf20Sopenharmony_ci * spp_assoc_id - (one-to-many style socket) This is filled in the 56738c2ecf20Sopenharmony_ci * application, and identifies the association for 56748c2ecf20Sopenharmony_ci * this query. 56758c2ecf20Sopenharmony_ci * spp_address - This specifies which address is of interest. 56768c2ecf20Sopenharmony_ci * spp_hbinterval - This contains the value of the heartbeat interval, 56778c2ecf20Sopenharmony_ci * in milliseconds. If a value of zero 56788c2ecf20Sopenharmony_ci * is present in this field then no changes are to 56798c2ecf20Sopenharmony_ci * be made to this parameter. 56808c2ecf20Sopenharmony_ci * spp_pathmaxrxt - This contains the maximum number of 56818c2ecf20Sopenharmony_ci * retransmissions before this address shall be 56828c2ecf20Sopenharmony_ci * considered unreachable. If a value of zero 56838c2ecf20Sopenharmony_ci * is present in this field then no changes are to 56848c2ecf20Sopenharmony_ci * be made to this parameter. 56858c2ecf20Sopenharmony_ci * spp_pathmtu - When Path MTU discovery is disabled the value 56868c2ecf20Sopenharmony_ci * specified here will be the "fixed" path mtu. 56878c2ecf20Sopenharmony_ci * Note that if the spp_address field is empty 56888c2ecf20Sopenharmony_ci * then all associations on this address will 56898c2ecf20Sopenharmony_ci * have this fixed path mtu set upon them. 56908c2ecf20Sopenharmony_ci * 56918c2ecf20Sopenharmony_ci * spp_sackdelay - When delayed sack is enabled, this value specifies 56928c2ecf20Sopenharmony_ci * the number of milliseconds that sacks will be delayed 56938c2ecf20Sopenharmony_ci * for. This value will apply to all addresses of an 56948c2ecf20Sopenharmony_ci * association if the spp_address field is empty. Note 56958c2ecf20Sopenharmony_ci * also, that if delayed sack is enabled and this 56968c2ecf20Sopenharmony_ci * value is set to 0, no change is made to the last 56978c2ecf20Sopenharmony_ci * recorded delayed sack timer value. 56988c2ecf20Sopenharmony_ci * 56998c2ecf20Sopenharmony_ci * spp_flags - These flags are used to control various features 57008c2ecf20Sopenharmony_ci * on an association. The flag field may contain 57018c2ecf20Sopenharmony_ci * zero or more of the following options. 57028c2ecf20Sopenharmony_ci * 57038c2ecf20Sopenharmony_ci * SPP_HB_ENABLE - Enable heartbeats on the 57048c2ecf20Sopenharmony_ci * specified address. Note that if the address 57058c2ecf20Sopenharmony_ci * field is empty all addresses for the association 57068c2ecf20Sopenharmony_ci * have heartbeats enabled upon them. 57078c2ecf20Sopenharmony_ci * 57088c2ecf20Sopenharmony_ci * SPP_HB_DISABLE - Disable heartbeats on the 57098c2ecf20Sopenharmony_ci * speicifed address. Note that if the address 57108c2ecf20Sopenharmony_ci * field is empty all addresses for the association 57118c2ecf20Sopenharmony_ci * will have their heartbeats disabled. Note also 57128c2ecf20Sopenharmony_ci * that SPP_HB_ENABLE and SPP_HB_DISABLE are 57138c2ecf20Sopenharmony_ci * mutually exclusive, only one of these two should 57148c2ecf20Sopenharmony_ci * be specified. Enabling both fields will have 57158c2ecf20Sopenharmony_ci * undetermined results. 57168c2ecf20Sopenharmony_ci * 57178c2ecf20Sopenharmony_ci * SPP_HB_DEMAND - Request a user initiated heartbeat 57188c2ecf20Sopenharmony_ci * to be made immediately. 57198c2ecf20Sopenharmony_ci * 57208c2ecf20Sopenharmony_ci * SPP_PMTUD_ENABLE - This field will enable PMTU 57218c2ecf20Sopenharmony_ci * discovery upon the specified address. Note that 57228c2ecf20Sopenharmony_ci * if the address feild is empty then all addresses 57238c2ecf20Sopenharmony_ci * on the association are effected. 57248c2ecf20Sopenharmony_ci * 57258c2ecf20Sopenharmony_ci * SPP_PMTUD_DISABLE - This field will disable PMTU 57268c2ecf20Sopenharmony_ci * discovery upon the specified address. Note that 57278c2ecf20Sopenharmony_ci * if the address feild is empty then all addresses 57288c2ecf20Sopenharmony_ci * on the association are effected. Not also that 57298c2ecf20Sopenharmony_ci * SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually 57308c2ecf20Sopenharmony_ci * exclusive. Enabling both will have undetermined 57318c2ecf20Sopenharmony_ci * results. 57328c2ecf20Sopenharmony_ci * 57338c2ecf20Sopenharmony_ci * SPP_SACKDELAY_ENABLE - Setting this flag turns 57348c2ecf20Sopenharmony_ci * on delayed sack. The time specified in spp_sackdelay 57358c2ecf20Sopenharmony_ci * is used to specify the sack delay for this address. Note 57368c2ecf20Sopenharmony_ci * that if spp_address is empty then all addresses will 57378c2ecf20Sopenharmony_ci * enable delayed sack and take on the sack delay 57388c2ecf20Sopenharmony_ci * value specified in spp_sackdelay. 57398c2ecf20Sopenharmony_ci * SPP_SACKDELAY_DISABLE - Setting this flag turns 57408c2ecf20Sopenharmony_ci * off delayed sack. If the spp_address field is blank then 57418c2ecf20Sopenharmony_ci * delayed sack is disabled for the entire association. Note 57428c2ecf20Sopenharmony_ci * also that this field is mutually exclusive to 57438c2ecf20Sopenharmony_ci * SPP_SACKDELAY_ENABLE, setting both will have undefined 57448c2ecf20Sopenharmony_ci * results. 57458c2ecf20Sopenharmony_ci * 57468c2ecf20Sopenharmony_ci * SPP_IPV6_FLOWLABEL: Setting this flag enables the 57478c2ecf20Sopenharmony_ci * setting of the IPV6 flow label value. The value is 57488c2ecf20Sopenharmony_ci * contained in the spp_ipv6_flowlabel field. 57498c2ecf20Sopenharmony_ci * Upon retrieval, this flag will be set to indicate that 57508c2ecf20Sopenharmony_ci * the spp_ipv6_flowlabel field has a valid value returned. 57518c2ecf20Sopenharmony_ci * If a specific destination address is set (in the 57528c2ecf20Sopenharmony_ci * spp_address field), then the value returned is that of 57538c2ecf20Sopenharmony_ci * the address. If just an association is specified (and 57548c2ecf20Sopenharmony_ci * no address), then the association's default flow label 57558c2ecf20Sopenharmony_ci * is returned. If neither an association nor a destination 57568c2ecf20Sopenharmony_ci * is specified, then the socket's default flow label is 57578c2ecf20Sopenharmony_ci * returned. For non-IPv6 sockets, this flag will be left 57588c2ecf20Sopenharmony_ci * cleared. 57598c2ecf20Sopenharmony_ci * 57608c2ecf20Sopenharmony_ci * SPP_DSCP: Setting this flag enables the setting of the 57618c2ecf20Sopenharmony_ci * Differentiated Services Code Point (DSCP) value 57628c2ecf20Sopenharmony_ci * associated with either the association or a specific 57638c2ecf20Sopenharmony_ci * address. The value is obtained in the spp_dscp field. 57648c2ecf20Sopenharmony_ci * Upon retrieval, this flag will be set to indicate that 57658c2ecf20Sopenharmony_ci * the spp_dscp field has a valid value returned. If a 57668c2ecf20Sopenharmony_ci * specific destination address is set when called (in the 57678c2ecf20Sopenharmony_ci * spp_address field), then that specific destination 57688c2ecf20Sopenharmony_ci * address's DSCP value is returned. If just an association 57698c2ecf20Sopenharmony_ci * is specified, then the association's default DSCP is 57708c2ecf20Sopenharmony_ci * returned. If neither an association nor a destination is 57718c2ecf20Sopenharmony_ci * specified, then the socket's default DSCP is returned. 57728c2ecf20Sopenharmony_ci * 57738c2ecf20Sopenharmony_ci * spp_ipv6_flowlabel 57748c2ecf20Sopenharmony_ci * - This field is used in conjunction with the 57758c2ecf20Sopenharmony_ci * SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label. 57768c2ecf20Sopenharmony_ci * The 20 least significant bits are used for the flow 57778c2ecf20Sopenharmony_ci * label. This setting has precedence over any IPv6-layer 57788c2ecf20Sopenharmony_ci * setting. 57798c2ecf20Sopenharmony_ci * 57808c2ecf20Sopenharmony_ci * spp_dscp - This field is used in conjunction with the SPP_DSCP flag 57818c2ecf20Sopenharmony_ci * and contains the DSCP. The 6 most significant bits are 57828c2ecf20Sopenharmony_ci * used for the DSCP. This setting has precedence over any 57838c2ecf20Sopenharmony_ci * IPv4- or IPv6- layer setting. 57848c2ecf20Sopenharmony_ci */ 57858c2ecf20Sopenharmony_cistatic int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, 57868c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 57878c2ecf20Sopenharmony_ci{ 57888c2ecf20Sopenharmony_ci struct sctp_paddrparams params; 57898c2ecf20Sopenharmony_ci struct sctp_transport *trans = NULL; 57908c2ecf20Sopenharmony_ci struct sctp_association *asoc = NULL; 57918c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 57928c2ecf20Sopenharmony_ci 57938c2ecf20Sopenharmony_ci if (len >= sizeof(params)) 57948c2ecf20Sopenharmony_ci len = sizeof(params); 57958c2ecf20Sopenharmony_ci else if (len >= ALIGN(offsetof(struct sctp_paddrparams, 57968c2ecf20Sopenharmony_ci spp_ipv6_flowlabel), 4)) 57978c2ecf20Sopenharmony_ci len = ALIGN(offsetof(struct sctp_paddrparams, 57988c2ecf20Sopenharmony_ci spp_ipv6_flowlabel), 4); 57998c2ecf20Sopenharmony_ci else 58008c2ecf20Sopenharmony_ci return -EINVAL; 58018c2ecf20Sopenharmony_ci 58028c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 58038c2ecf20Sopenharmony_ci return -EFAULT; 58048c2ecf20Sopenharmony_ci 58058c2ecf20Sopenharmony_ci /* If an address other than INADDR_ANY is specified, and 58068c2ecf20Sopenharmony_ci * no transport is found, then the request is invalid. 58078c2ecf20Sopenharmony_ci */ 58088c2ecf20Sopenharmony_ci if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { 58098c2ecf20Sopenharmony_ci trans = sctp_addr_id2transport(sk, ¶ms.spp_address, 58108c2ecf20Sopenharmony_ci params.spp_assoc_id); 58118c2ecf20Sopenharmony_ci if (!trans) { 58128c2ecf20Sopenharmony_ci pr_debug("%s: failed no transport\n", __func__); 58138c2ecf20Sopenharmony_ci return -EINVAL; 58148c2ecf20Sopenharmony_ci } 58158c2ecf20Sopenharmony_ci } 58168c2ecf20Sopenharmony_ci 58178c2ecf20Sopenharmony_ci /* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the 58188c2ecf20Sopenharmony_ci * socket is a one to many style socket, and an association 58198c2ecf20Sopenharmony_ci * was not found, then the id was invalid. 58208c2ecf20Sopenharmony_ci */ 58218c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.spp_assoc_id); 58228c2ecf20Sopenharmony_ci if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC && 58238c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 58248c2ecf20Sopenharmony_ci pr_debug("%s: failed no association\n", __func__); 58258c2ecf20Sopenharmony_ci return -EINVAL; 58268c2ecf20Sopenharmony_ci } 58278c2ecf20Sopenharmony_ci 58288c2ecf20Sopenharmony_ci if (trans) { 58298c2ecf20Sopenharmony_ci /* Fetch transport values. */ 58308c2ecf20Sopenharmony_ci params.spp_hbinterval = jiffies_to_msecs(trans->hbinterval); 58318c2ecf20Sopenharmony_ci params.spp_pathmtu = trans->pathmtu; 58328c2ecf20Sopenharmony_ci params.spp_pathmaxrxt = trans->pathmaxrxt; 58338c2ecf20Sopenharmony_ci params.spp_sackdelay = jiffies_to_msecs(trans->sackdelay); 58348c2ecf20Sopenharmony_ci 58358c2ecf20Sopenharmony_ci /*draft-11 doesn't say what to return in spp_flags*/ 58368c2ecf20Sopenharmony_ci params.spp_flags = trans->param_flags; 58378c2ecf20Sopenharmony_ci if (trans->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 58388c2ecf20Sopenharmony_ci params.spp_ipv6_flowlabel = trans->flowlabel & 58398c2ecf20Sopenharmony_ci SCTP_FLOWLABEL_VAL_MASK; 58408c2ecf20Sopenharmony_ci params.spp_flags |= SPP_IPV6_FLOWLABEL; 58418c2ecf20Sopenharmony_ci } 58428c2ecf20Sopenharmony_ci if (trans->dscp & SCTP_DSCP_SET_MASK) { 58438c2ecf20Sopenharmony_ci params.spp_dscp = trans->dscp & SCTP_DSCP_VAL_MASK; 58448c2ecf20Sopenharmony_ci params.spp_flags |= SPP_DSCP; 58458c2ecf20Sopenharmony_ci } 58468c2ecf20Sopenharmony_ci } else if (asoc) { 58478c2ecf20Sopenharmony_ci /* Fetch association values. */ 58488c2ecf20Sopenharmony_ci params.spp_hbinterval = jiffies_to_msecs(asoc->hbinterval); 58498c2ecf20Sopenharmony_ci params.spp_pathmtu = asoc->pathmtu; 58508c2ecf20Sopenharmony_ci params.spp_pathmaxrxt = asoc->pathmaxrxt; 58518c2ecf20Sopenharmony_ci params.spp_sackdelay = jiffies_to_msecs(asoc->sackdelay); 58528c2ecf20Sopenharmony_ci 58538c2ecf20Sopenharmony_ci /*draft-11 doesn't say what to return in spp_flags*/ 58548c2ecf20Sopenharmony_ci params.spp_flags = asoc->param_flags; 58558c2ecf20Sopenharmony_ci if (asoc->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 58568c2ecf20Sopenharmony_ci params.spp_ipv6_flowlabel = asoc->flowlabel & 58578c2ecf20Sopenharmony_ci SCTP_FLOWLABEL_VAL_MASK; 58588c2ecf20Sopenharmony_ci params.spp_flags |= SPP_IPV6_FLOWLABEL; 58598c2ecf20Sopenharmony_ci } 58608c2ecf20Sopenharmony_ci if (asoc->dscp & SCTP_DSCP_SET_MASK) { 58618c2ecf20Sopenharmony_ci params.spp_dscp = asoc->dscp & SCTP_DSCP_VAL_MASK; 58628c2ecf20Sopenharmony_ci params.spp_flags |= SPP_DSCP; 58638c2ecf20Sopenharmony_ci } 58648c2ecf20Sopenharmony_ci } else { 58658c2ecf20Sopenharmony_ci /* Fetch socket values. */ 58668c2ecf20Sopenharmony_ci params.spp_hbinterval = sp->hbinterval; 58678c2ecf20Sopenharmony_ci params.spp_pathmtu = sp->pathmtu; 58688c2ecf20Sopenharmony_ci params.spp_sackdelay = sp->sackdelay; 58698c2ecf20Sopenharmony_ci params.spp_pathmaxrxt = sp->pathmaxrxt; 58708c2ecf20Sopenharmony_ci 58718c2ecf20Sopenharmony_ci /*draft-11 doesn't say what to return in spp_flags*/ 58728c2ecf20Sopenharmony_ci params.spp_flags = sp->param_flags; 58738c2ecf20Sopenharmony_ci if (sp->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 58748c2ecf20Sopenharmony_ci params.spp_ipv6_flowlabel = sp->flowlabel & 58758c2ecf20Sopenharmony_ci SCTP_FLOWLABEL_VAL_MASK; 58768c2ecf20Sopenharmony_ci params.spp_flags |= SPP_IPV6_FLOWLABEL; 58778c2ecf20Sopenharmony_ci } 58788c2ecf20Sopenharmony_ci if (sp->dscp & SCTP_DSCP_SET_MASK) { 58798c2ecf20Sopenharmony_ci params.spp_dscp = sp->dscp & SCTP_DSCP_VAL_MASK; 58808c2ecf20Sopenharmony_ci params.spp_flags |= SPP_DSCP; 58818c2ecf20Sopenharmony_ci } 58828c2ecf20Sopenharmony_ci } 58838c2ecf20Sopenharmony_ci 58848c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 58858c2ecf20Sopenharmony_ci return -EFAULT; 58868c2ecf20Sopenharmony_ci 58878c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 58888c2ecf20Sopenharmony_ci return -EFAULT; 58898c2ecf20Sopenharmony_ci 58908c2ecf20Sopenharmony_ci return 0; 58918c2ecf20Sopenharmony_ci} 58928c2ecf20Sopenharmony_ci 58938c2ecf20Sopenharmony_ci/* 58948c2ecf20Sopenharmony_ci * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 58958c2ecf20Sopenharmony_ci * 58968c2ecf20Sopenharmony_ci * This option will effect the way delayed acks are performed. This 58978c2ecf20Sopenharmony_ci * option allows you to get or set the delayed ack time, in 58988c2ecf20Sopenharmony_ci * milliseconds. It also allows changing the delayed ack frequency. 58998c2ecf20Sopenharmony_ci * Changing the frequency to 1 disables the delayed sack algorithm. If 59008c2ecf20Sopenharmony_ci * the assoc_id is 0, then this sets or gets the endpoints default 59018c2ecf20Sopenharmony_ci * values. If the assoc_id field is non-zero, then the set or get 59028c2ecf20Sopenharmony_ci * effects the specified association for the one to many model (the 59038c2ecf20Sopenharmony_ci * assoc_id field is ignored by the one to one model). Note that if 59048c2ecf20Sopenharmony_ci * sack_delay or sack_freq are 0 when setting this option, then the 59058c2ecf20Sopenharmony_ci * current values will remain unchanged. 59068c2ecf20Sopenharmony_ci * 59078c2ecf20Sopenharmony_ci * struct sctp_sack_info { 59088c2ecf20Sopenharmony_ci * sctp_assoc_t sack_assoc_id; 59098c2ecf20Sopenharmony_ci * uint32_t sack_delay; 59108c2ecf20Sopenharmony_ci * uint32_t sack_freq; 59118c2ecf20Sopenharmony_ci * }; 59128c2ecf20Sopenharmony_ci * 59138c2ecf20Sopenharmony_ci * sack_assoc_id - This parameter, indicates which association the user 59148c2ecf20Sopenharmony_ci * is performing an action upon. Note that if this field's value is 59158c2ecf20Sopenharmony_ci * zero then the endpoints default value is changed (effecting future 59168c2ecf20Sopenharmony_ci * associations only). 59178c2ecf20Sopenharmony_ci * 59188c2ecf20Sopenharmony_ci * sack_delay - This parameter contains the number of milliseconds that 59198c2ecf20Sopenharmony_ci * the user is requesting the delayed ACK timer be set to. Note that 59208c2ecf20Sopenharmony_ci * this value is defined in the standard to be between 200 and 500 59218c2ecf20Sopenharmony_ci * milliseconds. 59228c2ecf20Sopenharmony_ci * 59238c2ecf20Sopenharmony_ci * sack_freq - This parameter contains the number of packets that must 59248c2ecf20Sopenharmony_ci * be received before a sack is sent without waiting for the delay 59258c2ecf20Sopenharmony_ci * timer to expire. The default value for this is 2, setting this 59268c2ecf20Sopenharmony_ci * value to 1 will disable the delayed sack algorithm. 59278c2ecf20Sopenharmony_ci */ 59288c2ecf20Sopenharmony_cistatic int sctp_getsockopt_delayed_ack(struct sock *sk, int len, 59298c2ecf20Sopenharmony_ci char __user *optval, 59308c2ecf20Sopenharmony_ci int __user *optlen) 59318c2ecf20Sopenharmony_ci{ 59328c2ecf20Sopenharmony_ci struct sctp_sack_info params; 59338c2ecf20Sopenharmony_ci struct sctp_association *asoc = NULL; 59348c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 59358c2ecf20Sopenharmony_ci 59368c2ecf20Sopenharmony_ci if (len >= sizeof(struct sctp_sack_info)) { 59378c2ecf20Sopenharmony_ci len = sizeof(struct sctp_sack_info); 59388c2ecf20Sopenharmony_ci 59398c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 59408c2ecf20Sopenharmony_ci return -EFAULT; 59418c2ecf20Sopenharmony_ci } else if (len == sizeof(struct sctp_assoc_value)) { 59428c2ecf20Sopenharmony_ci pr_warn_ratelimited(DEPRECATED 59438c2ecf20Sopenharmony_ci "%s (pid %d) " 59448c2ecf20Sopenharmony_ci "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 59458c2ecf20Sopenharmony_ci "Use struct sctp_sack_info instead\n", 59468c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current)); 59478c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 59488c2ecf20Sopenharmony_ci return -EFAULT; 59498c2ecf20Sopenharmony_ci } else 59508c2ecf20Sopenharmony_ci return -EINVAL; 59518c2ecf20Sopenharmony_ci 59528c2ecf20Sopenharmony_ci /* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the 59538c2ecf20Sopenharmony_ci * socket is a one to many style socket, and an association 59548c2ecf20Sopenharmony_ci * was not found, then the id was invalid. 59558c2ecf20Sopenharmony_ci */ 59568c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.sack_assoc_id); 59578c2ecf20Sopenharmony_ci if (!asoc && params.sack_assoc_id != SCTP_FUTURE_ASSOC && 59588c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 59598c2ecf20Sopenharmony_ci return -EINVAL; 59608c2ecf20Sopenharmony_ci 59618c2ecf20Sopenharmony_ci if (asoc) { 59628c2ecf20Sopenharmony_ci /* Fetch association values. */ 59638c2ecf20Sopenharmony_ci if (asoc->param_flags & SPP_SACKDELAY_ENABLE) { 59648c2ecf20Sopenharmony_ci params.sack_delay = jiffies_to_msecs(asoc->sackdelay); 59658c2ecf20Sopenharmony_ci params.sack_freq = asoc->sackfreq; 59668c2ecf20Sopenharmony_ci 59678c2ecf20Sopenharmony_ci } else { 59688c2ecf20Sopenharmony_ci params.sack_delay = 0; 59698c2ecf20Sopenharmony_ci params.sack_freq = 1; 59708c2ecf20Sopenharmony_ci } 59718c2ecf20Sopenharmony_ci } else { 59728c2ecf20Sopenharmony_ci /* Fetch socket values. */ 59738c2ecf20Sopenharmony_ci if (sp->param_flags & SPP_SACKDELAY_ENABLE) { 59748c2ecf20Sopenharmony_ci params.sack_delay = sp->sackdelay; 59758c2ecf20Sopenharmony_ci params.sack_freq = sp->sackfreq; 59768c2ecf20Sopenharmony_ci } else { 59778c2ecf20Sopenharmony_ci params.sack_delay = 0; 59788c2ecf20Sopenharmony_ci params.sack_freq = 1; 59798c2ecf20Sopenharmony_ci } 59808c2ecf20Sopenharmony_ci } 59818c2ecf20Sopenharmony_ci 59828c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 59838c2ecf20Sopenharmony_ci return -EFAULT; 59848c2ecf20Sopenharmony_ci 59858c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 59868c2ecf20Sopenharmony_ci return -EFAULT; 59878c2ecf20Sopenharmony_ci 59888c2ecf20Sopenharmony_ci return 0; 59898c2ecf20Sopenharmony_ci} 59908c2ecf20Sopenharmony_ci 59918c2ecf20Sopenharmony_ci/* 7.1.3 Initialization Parameters (SCTP_INITMSG) 59928c2ecf20Sopenharmony_ci * 59938c2ecf20Sopenharmony_ci * Applications can specify protocol parameters for the default association 59948c2ecf20Sopenharmony_ci * initialization. The option name argument to setsockopt() and getsockopt() 59958c2ecf20Sopenharmony_ci * is SCTP_INITMSG. 59968c2ecf20Sopenharmony_ci * 59978c2ecf20Sopenharmony_ci * Setting initialization parameters is effective only on an unconnected 59988c2ecf20Sopenharmony_ci * socket (for UDP-style sockets only future associations are effected 59998c2ecf20Sopenharmony_ci * by the change). With TCP-style sockets, this option is inherited by 60008c2ecf20Sopenharmony_ci * sockets derived from a listener socket. 60018c2ecf20Sopenharmony_ci */ 60028c2ecf20Sopenharmony_cistatic int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen) 60038c2ecf20Sopenharmony_ci{ 60048c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_initmsg)) 60058c2ecf20Sopenharmony_ci return -EINVAL; 60068c2ecf20Sopenharmony_ci len = sizeof(struct sctp_initmsg); 60078c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 60088c2ecf20Sopenharmony_ci return -EFAULT; 60098c2ecf20Sopenharmony_ci if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len)) 60108c2ecf20Sopenharmony_ci return -EFAULT; 60118c2ecf20Sopenharmony_ci return 0; 60128c2ecf20Sopenharmony_ci} 60138c2ecf20Sopenharmony_ci 60148c2ecf20Sopenharmony_ci 60158c2ecf20Sopenharmony_cistatic int sctp_getsockopt_peer_addrs(struct sock *sk, int len, 60168c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 60178c2ecf20Sopenharmony_ci{ 60188c2ecf20Sopenharmony_ci struct sctp_association *asoc; 60198c2ecf20Sopenharmony_ci int cnt = 0; 60208c2ecf20Sopenharmony_ci struct sctp_getaddrs getaddrs; 60218c2ecf20Sopenharmony_ci struct sctp_transport *from; 60228c2ecf20Sopenharmony_ci void __user *to; 60238c2ecf20Sopenharmony_ci union sctp_addr temp; 60248c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 60258c2ecf20Sopenharmony_ci int addrlen; 60268c2ecf20Sopenharmony_ci size_t space_left; 60278c2ecf20Sopenharmony_ci int bytes_copied; 60288c2ecf20Sopenharmony_ci 60298c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_getaddrs)) 60308c2ecf20Sopenharmony_ci return -EINVAL; 60318c2ecf20Sopenharmony_ci 60328c2ecf20Sopenharmony_ci if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 60338c2ecf20Sopenharmony_ci return -EFAULT; 60348c2ecf20Sopenharmony_ci 60358c2ecf20Sopenharmony_ci /* For UDP-style sockets, id specifies the association to query. */ 60368c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 60378c2ecf20Sopenharmony_ci if (!asoc) 60388c2ecf20Sopenharmony_ci return -EINVAL; 60398c2ecf20Sopenharmony_ci 60408c2ecf20Sopenharmony_ci to = optval + offsetof(struct sctp_getaddrs, addrs); 60418c2ecf20Sopenharmony_ci space_left = len - offsetof(struct sctp_getaddrs, addrs); 60428c2ecf20Sopenharmony_ci 60438c2ecf20Sopenharmony_ci list_for_each_entry(from, &asoc->peer.transport_addr_list, 60448c2ecf20Sopenharmony_ci transports) { 60458c2ecf20Sopenharmony_ci memcpy(&temp, &from->ipaddr, sizeof(temp)); 60468c2ecf20Sopenharmony_ci addrlen = sctp_get_pf_specific(sk->sk_family) 60478c2ecf20Sopenharmony_ci ->addr_to_user(sp, &temp); 60488c2ecf20Sopenharmony_ci if (space_left < addrlen) 60498c2ecf20Sopenharmony_ci return -ENOMEM; 60508c2ecf20Sopenharmony_ci if (copy_to_user(to, &temp, addrlen)) 60518c2ecf20Sopenharmony_ci return -EFAULT; 60528c2ecf20Sopenharmony_ci to += addrlen; 60538c2ecf20Sopenharmony_ci cnt++; 60548c2ecf20Sopenharmony_ci space_left -= addrlen; 60558c2ecf20Sopenharmony_ci } 60568c2ecf20Sopenharmony_ci 60578c2ecf20Sopenharmony_ci if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) 60588c2ecf20Sopenharmony_ci return -EFAULT; 60598c2ecf20Sopenharmony_ci bytes_copied = ((char __user *)to) - optval; 60608c2ecf20Sopenharmony_ci if (put_user(bytes_copied, optlen)) 60618c2ecf20Sopenharmony_ci return -EFAULT; 60628c2ecf20Sopenharmony_ci 60638c2ecf20Sopenharmony_ci return 0; 60648c2ecf20Sopenharmony_ci} 60658c2ecf20Sopenharmony_ci 60668c2ecf20Sopenharmony_cistatic int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, 60678c2ecf20Sopenharmony_ci size_t space_left, int *bytes_copied) 60688c2ecf20Sopenharmony_ci{ 60698c2ecf20Sopenharmony_ci struct sctp_sockaddr_entry *addr; 60708c2ecf20Sopenharmony_ci union sctp_addr temp; 60718c2ecf20Sopenharmony_ci int cnt = 0; 60728c2ecf20Sopenharmony_ci int addrlen; 60738c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 60748c2ecf20Sopenharmony_ci 60758c2ecf20Sopenharmony_ci rcu_read_lock(); 60768c2ecf20Sopenharmony_ci list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) { 60778c2ecf20Sopenharmony_ci if (!addr->valid) 60788c2ecf20Sopenharmony_ci continue; 60798c2ecf20Sopenharmony_ci 60808c2ecf20Sopenharmony_ci if ((PF_INET == sk->sk_family) && 60818c2ecf20Sopenharmony_ci (AF_INET6 == addr->a.sa.sa_family)) 60828c2ecf20Sopenharmony_ci continue; 60838c2ecf20Sopenharmony_ci if ((PF_INET6 == sk->sk_family) && 60848c2ecf20Sopenharmony_ci inet_v6_ipv6only(sk) && 60858c2ecf20Sopenharmony_ci (AF_INET == addr->a.sa.sa_family)) 60868c2ecf20Sopenharmony_ci continue; 60878c2ecf20Sopenharmony_ci memcpy(&temp, &addr->a, sizeof(temp)); 60888c2ecf20Sopenharmony_ci if (!temp.v4.sin_port) 60898c2ecf20Sopenharmony_ci temp.v4.sin_port = htons(port); 60908c2ecf20Sopenharmony_ci 60918c2ecf20Sopenharmony_ci addrlen = sctp_get_pf_specific(sk->sk_family) 60928c2ecf20Sopenharmony_ci ->addr_to_user(sctp_sk(sk), &temp); 60938c2ecf20Sopenharmony_ci 60948c2ecf20Sopenharmony_ci if (space_left < addrlen) { 60958c2ecf20Sopenharmony_ci cnt = -ENOMEM; 60968c2ecf20Sopenharmony_ci break; 60978c2ecf20Sopenharmony_ci } 60988c2ecf20Sopenharmony_ci memcpy(to, &temp, addrlen); 60998c2ecf20Sopenharmony_ci 61008c2ecf20Sopenharmony_ci to += addrlen; 61018c2ecf20Sopenharmony_ci cnt++; 61028c2ecf20Sopenharmony_ci space_left -= addrlen; 61038c2ecf20Sopenharmony_ci *bytes_copied += addrlen; 61048c2ecf20Sopenharmony_ci } 61058c2ecf20Sopenharmony_ci rcu_read_unlock(); 61068c2ecf20Sopenharmony_ci 61078c2ecf20Sopenharmony_ci return cnt; 61088c2ecf20Sopenharmony_ci} 61098c2ecf20Sopenharmony_ci 61108c2ecf20Sopenharmony_ci 61118c2ecf20Sopenharmony_cistatic int sctp_getsockopt_local_addrs(struct sock *sk, int len, 61128c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 61138c2ecf20Sopenharmony_ci{ 61148c2ecf20Sopenharmony_ci struct sctp_bind_addr *bp; 61158c2ecf20Sopenharmony_ci struct sctp_association *asoc; 61168c2ecf20Sopenharmony_ci int cnt = 0; 61178c2ecf20Sopenharmony_ci struct sctp_getaddrs getaddrs; 61188c2ecf20Sopenharmony_ci struct sctp_sockaddr_entry *addr; 61198c2ecf20Sopenharmony_ci void __user *to; 61208c2ecf20Sopenharmony_ci union sctp_addr temp; 61218c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 61228c2ecf20Sopenharmony_ci int addrlen; 61238c2ecf20Sopenharmony_ci int err = 0; 61248c2ecf20Sopenharmony_ci size_t space_left; 61258c2ecf20Sopenharmony_ci int bytes_copied = 0; 61268c2ecf20Sopenharmony_ci void *addrs; 61278c2ecf20Sopenharmony_ci void *buf; 61288c2ecf20Sopenharmony_ci 61298c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_getaddrs)) 61308c2ecf20Sopenharmony_ci return -EINVAL; 61318c2ecf20Sopenharmony_ci 61328c2ecf20Sopenharmony_ci if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 61338c2ecf20Sopenharmony_ci return -EFAULT; 61348c2ecf20Sopenharmony_ci 61358c2ecf20Sopenharmony_ci /* 61368c2ecf20Sopenharmony_ci * For UDP-style sockets, id specifies the association to query. 61378c2ecf20Sopenharmony_ci * If the id field is set to the value '0' then the locally bound 61388c2ecf20Sopenharmony_ci * addresses are returned without regard to any particular 61398c2ecf20Sopenharmony_ci * association. 61408c2ecf20Sopenharmony_ci */ 61418c2ecf20Sopenharmony_ci if (0 == getaddrs.assoc_id) { 61428c2ecf20Sopenharmony_ci bp = &sctp_sk(sk)->ep->base.bind_addr; 61438c2ecf20Sopenharmony_ci } else { 61448c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 61458c2ecf20Sopenharmony_ci if (!asoc) 61468c2ecf20Sopenharmony_ci return -EINVAL; 61478c2ecf20Sopenharmony_ci bp = &asoc->base.bind_addr; 61488c2ecf20Sopenharmony_ci } 61498c2ecf20Sopenharmony_ci 61508c2ecf20Sopenharmony_ci to = optval + offsetof(struct sctp_getaddrs, addrs); 61518c2ecf20Sopenharmony_ci space_left = len - offsetof(struct sctp_getaddrs, addrs); 61528c2ecf20Sopenharmony_ci 61538c2ecf20Sopenharmony_ci addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN); 61548c2ecf20Sopenharmony_ci if (!addrs) 61558c2ecf20Sopenharmony_ci return -ENOMEM; 61568c2ecf20Sopenharmony_ci 61578c2ecf20Sopenharmony_ci /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid 61588c2ecf20Sopenharmony_ci * addresses from the global local address list. 61598c2ecf20Sopenharmony_ci */ 61608c2ecf20Sopenharmony_ci if (sctp_list_single_entry(&bp->address_list)) { 61618c2ecf20Sopenharmony_ci addr = list_entry(bp->address_list.next, 61628c2ecf20Sopenharmony_ci struct sctp_sockaddr_entry, list); 61638c2ecf20Sopenharmony_ci if (sctp_is_any(sk, &addr->a)) { 61648c2ecf20Sopenharmony_ci cnt = sctp_copy_laddrs(sk, bp->port, addrs, 61658c2ecf20Sopenharmony_ci space_left, &bytes_copied); 61668c2ecf20Sopenharmony_ci if (cnt < 0) { 61678c2ecf20Sopenharmony_ci err = cnt; 61688c2ecf20Sopenharmony_ci goto out; 61698c2ecf20Sopenharmony_ci } 61708c2ecf20Sopenharmony_ci goto copy_getaddrs; 61718c2ecf20Sopenharmony_ci } 61728c2ecf20Sopenharmony_ci } 61738c2ecf20Sopenharmony_ci 61748c2ecf20Sopenharmony_ci buf = addrs; 61758c2ecf20Sopenharmony_ci /* Protection on the bound address list is not needed since 61768c2ecf20Sopenharmony_ci * in the socket option context we hold a socket lock and 61778c2ecf20Sopenharmony_ci * thus the bound address list can't change. 61788c2ecf20Sopenharmony_ci */ 61798c2ecf20Sopenharmony_ci list_for_each_entry(addr, &bp->address_list, list) { 61808c2ecf20Sopenharmony_ci memcpy(&temp, &addr->a, sizeof(temp)); 61818c2ecf20Sopenharmony_ci addrlen = sctp_get_pf_specific(sk->sk_family) 61828c2ecf20Sopenharmony_ci ->addr_to_user(sp, &temp); 61838c2ecf20Sopenharmony_ci if (space_left < addrlen) { 61848c2ecf20Sopenharmony_ci err = -ENOMEM; /*fixme: right error?*/ 61858c2ecf20Sopenharmony_ci goto out; 61868c2ecf20Sopenharmony_ci } 61878c2ecf20Sopenharmony_ci memcpy(buf, &temp, addrlen); 61888c2ecf20Sopenharmony_ci buf += addrlen; 61898c2ecf20Sopenharmony_ci bytes_copied += addrlen; 61908c2ecf20Sopenharmony_ci cnt++; 61918c2ecf20Sopenharmony_ci space_left -= addrlen; 61928c2ecf20Sopenharmony_ci } 61938c2ecf20Sopenharmony_ci 61948c2ecf20Sopenharmony_cicopy_getaddrs: 61958c2ecf20Sopenharmony_ci if (copy_to_user(to, addrs, bytes_copied)) { 61968c2ecf20Sopenharmony_ci err = -EFAULT; 61978c2ecf20Sopenharmony_ci goto out; 61988c2ecf20Sopenharmony_ci } 61998c2ecf20Sopenharmony_ci if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) { 62008c2ecf20Sopenharmony_ci err = -EFAULT; 62018c2ecf20Sopenharmony_ci goto out; 62028c2ecf20Sopenharmony_ci } 62038c2ecf20Sopenharmony_ci /* XXX: We should have accounted for sizeof(struct sctp_getaddrs) too, 62048c2ecf20Sopenharmony_ci * but we can't change it anymore. 62058c2ecf20Sopenharmony_ci */ 62068c2ecf20Sopenharmony_ci if (put_user(bytes_copied, optlen)) 62078c2ecf20Sopenharmony_ci err = -EFAULT; 62088c2ecf20Sopenharmony_ciout: 62098c2ecf20Sopenharmony_ci kfree(addrs); 62108c2ecf20Sopenharmony_ci return err; 62118c2ecf20Sopenharmony_ci} 62128c2ecf20Sopenharmony_ci 62138c2ecf20Sopenharmony_ci/* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 62148c2ecf20Sopenharmony_ci * 62158c2ecf20Sopenharmony_ci * Requests that the local SCTP stack use the enclosed peer address as 62168c2ecf20Sopenharmony_ci * the association primary. The enclosed address must be one of the 62178c2ecf20Sopenharmony_ci * association peer's addresses. 62188c2ecf20Sopenharmony_ci */ 62198c2ecf20Sopenharmony_cistatic int sctp_getsockopt_primary_addr(struct sock *sk, int len, 62208c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 62218c2ecf20Sopenharmony_ci{ 62228c2ecf20Sopenharmony_ci struct sctp_prim prim; 62238c2ecf20Sopenharmony_ci struct sctp_association *asoc; 62248c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 62258c2ecf20Sopenharmony_ci 62268c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_prim)) 62278c2ecf20Sopenharmony_ci return -EINVAL; 62288c2ecf20Sopenharmony_ci 62298c2ecf20Sopenharmony_ci len = sizeof(struct sctp_prim); 62308c2ecf20Sopenharmony_ci 62318c2ecf20Sopenharmony_ci if (copy_from_user(&prim, optval, len)) 62328c2ecf20Sopenharmony_ci return -EFAULT; 62338c2ecf20Sopenharmony_ci 62348c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); 62358c2ecf20Sopenharmony_ci if (!asoc) 62368c2ecf20Sopenharmony_ci return -EINVAL; 62378c2ecf20Sopenharmony_ci 62388c2ecf20Sopenharmony_ci if (!asoc->peer.primary_path) 62398c2ecf20Sopenharmony_ci return -ENOTCONN; 62408c2ecf20Sopenharmony_ci 62418c2ecf20Sopenharmony_ci memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, 62428c2ecf20Sopenharmony_ci asoc->peer.primary_path->af_specific->sockaddr_len); 62438c2ecf20Sopenharmony_ci 62448c2ecf20Sopenharmony_ci sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp, 62458c2ecf20Sopenharmony_ci (union sctp_addr *)&prim.ssp_addr); 62468c2ecf20Sopenharmony_ci 62478c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 62488c2ecf20Sopenharmony_ci return -EFAULT; 62498c2ecf20Sopenharmony_ci if (copy_to_user(optval, &prim, len)) 62508c2ecf20Sopenharmony_ci return -EFAULT; 62518c2ecf20Sopenharmony_ci 62528c2ecf20Sopenharmony_ci return 0; 62538c2ecf20Sopenharmony_ci} 62548c2ecf20Sopenharmony_ci 62558c2ecf20Sopenharmony_ci/* 62568c2ecf20Sopenharmony_ci * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) 62578c2ecf20Sopenharmony_ci * 62588c2ecf20Sopenharmony_ci * Requests that the local endpoint set the specified Adaptation Layer 62598c2ecf20Sopenharmony_ci * Indication parameter for all future INIT and INIT-ACK exchanges. 62608c2ecf20Sopenharmony_ci */ 62618c2ecf20Sopenharmony_cistatic int sctp_getsockopt_adaptation_layer(struct sock *sk, int len, 62628c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 62638c2ecf20Sopenharmony_ci{ 62648c2ecf20Sopenharmony_ci struct sctp_setadaptation adaptation; 62658c2ecf20Sopenharmony_ci 62668c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_setadaptation)) 62678c2ecf20Sopenharmony_ci return -EINVAL; 62688c2ecf20Sopenharmony_ci 62698c2ecf20Sopenharmony_ci len = sizeof(struct sctp_setadaptation); 62708c2ecf20Sopenharmony_ci 62718c2ecf20Sopenharmony_ci adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind; 62728c2ecf20Sopenharmony_ci 62738c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 62748c2ecf20Sopenharmony_ci return -EFAULT; 62758c2ecf20Sopenharmony_ci if (copy_to_user(optval, &adaptation, len)) 62768c2ecf20Sopenharmony_ci return -EFAULT; 62778c2ecf20Sopenharmony_ci 62788c2ecf20Sopenharmony_ci return 0; 62798c2ecf20Sopenharmony_ci} 62808c2ecf20Sopenharmony_ci 62818c2ecf20Sopenharmony_ci/* 62828c2ecf20Sopenharmony_ci * 62838c2ecf20Sopenharmony_ci * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 62848c2ecf20Sopenharmony_ci * 62858c2ecf20Sopenharmony_ci * Applications that wish to use the sendto() system call may wish to 62868c2ecf20Sopenharmony_ci * specify a default set of parameters that would normally be supplied 62878c2ecf20Sopenharmony_ci * through the inclusion of ancillary data. This socket option allows 62888c2ecf20Sopenharmony_ci * such an application to set the default sctp_sndrcvinfo structure. 62898c2ecf20Sopenharmony_ci 62908c2ecf20Sopenharmony_ci 62918c2ecf20Sopenharmony_ci * The application that wishes to use this socket option simply passes 62928c2ecf20Sopenharmony_ci * in to this call the sctp_sndrcvinfo structure defined in Section 62938c2ecf20Sopenharmony_ci * 5.2.2) The input parameters accepted by this call include 62948c2ecf20Sopenharmony_ci * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 62958c2ecf20Sopenharmony_ci * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 62968c2ecf20Sopenharmony_ci * to this call if the caller is using the UDP model. 62978c2ecf20Sopenharmony_ci * 62988c2ecf20Sopenharmony_ci * For getsockopt, it get the default sctp_sndrcvinfo structure. 62998c2ecf20Sopenharmony_ci */ 63008c2ecf20Sopenharmony_cistatic int sctp_getsockopt_default_send_param(struct sock *sk, 63018c2ecf20Sopenharmony_ci int len, char __user *optval, 63028c2ecf20Sopenharmony_ci int __user *optlen) 63038c2ecf20Sopenharmony_ci{ 63048c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 63058c2ecf20Sopenharmony_ci struct sctp_association *asoc; 63068c2ecf20Sopenharmony_ci struct sctp_sndrcvinfo info; 63078c2ecf20Sopenharmony_ci 63088c2ecf20Sopenharmony_ci if (len < sizeof(info)) 63098c2ecf20Sopenharmony_ci return -EINVAL; 63108c2ecf20Sopenharmony_ci 63118c2ecf20Sopenharmony_ci len = sizeof(info); 63128c2ecf20Sopenharmony_ci 63138c2ecf20Sopenharmony_ci if (copy_from_user(&info, optval, len)) 63148c2ecf20Sopenharmony_ci return -EFAULT; 63158c2ecf20Sopenharmony_ci 63168c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); 63178c2ecf20Sopenharmony_ci if (!asoc && info.sinfo_assoc_id != SCTP_FUTURE_ASSOC && 63188c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 63198c2ecf20Sopenharmony_ci return -EINVAL; 63208c2ecf20Sopenharmony_ci 63218c2ecf20Sopenharmony_ci if (asoc) { 63228c2ecf20Sopenharmony_ci info.sinfo_stream = asoc->default_stream; 63238c2ecf20Sopenharmony_ci info.sinfo_flags = asoc->default_flags; 63248c2ecf20Sopenharmony_ci info.sinfo_ppid = asoc->default_ppid; 63258c2ecf20Sopenharmony_ci info.sinfo_context = asoc->default_context; 63268c2ecf20Sopenharmony_ci info.sinfo_timetolive = asoc->default_timetolive; 63278c2ecf20Sopenharmony_ci } else { 63288c2ecf20Sopenharmony_ci info.sinfo_stream = sp->default_stream; 63298c2ecf20Sopenharmony_ci info.sinfo_flags = sp->default_flags; 63308c2ecf20Sopenharmony_ci info.sinfo_ppid = sp->default_ppid; 63318c2ecf20Sopenharmony_ci info.sinfo_context = sp->default_context; 63328c2ecf20Sopenharmony_ci info.sinfo_timetolive = sp->default_timetolive; 63338c2ecf20Sopenharmony_ci } 63348c2ecf20Sopenharmony_ci 63358c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 63368c2ecf20Sopenharmony_ci return -EFAULT; 63378c2ecf20Sopenharmony_ci if (copy_to_user(optval, &info, len)) 63388c2ecf20Sopenharmony_ci return -EFAULT; 63398c2ecf20Sopenharmony_ci 63408c2ecf20Sopenharmony_ci return 0; 63418c2ecf20Sopenharmony_ci} 63428c2ecf20Sopenharmony_ci 63438c2ecf20Sopenharmony_ci/* RFC6458, Section 8.1.31. Set/get Default Send Parameters 63448c2ecf20Sopenharmony_ci * (SCTP_DEFAULT_SNDINFO) 63458c2ecf20Sopenharmony_ci */ 63468c2ecf20Sopenharmony_cistatic int sctp_getsockopt_default_sndinfo(struct sock *sk, int len, 63478c2ecf20Sopenharmony_ci char __user *optval, 63488c2ecf20Sopenharmony_ci int __user *optlen) 63498c2ecf20Sopenharmony_ci{ 63508c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 63518c2ecf20Sopenharmony_ci struct sctp_association *asoc; 63528c2ecf20Sopenharmony_ci struct sctp_sndinfo info; 63538c2ecf20Sopenharmony_ci 63548c2ecf20Sopenharmony_ci if (len < sizeof(info)) 63558c2ecf20Sopenharmony_ci return -EINVAL; 63568c2ecf20Sopenharmony_ci 63578c2ecf20Sopenharmony_ci len = sizeof(info); 63588c2ecf20Sopenharmony_ci 63598c2ecf20Sopenharmony_ci if (copy_from_user(&info, optval, len)) 63608c2ecf20Sopenharmony_ci return -EFAULT; 63618c2ecf20Sopenharmony_ci 63628c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, info.snd_assoc_id); 63638c2ecf20Sopenharmony_ci if (!asoc && info.snd_assoc_id != SCTP_FUTURE_ASSOC && 63648c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 63658c2ecf20Sopenharmony_ci return -EINVAL; 63668c2ecf20Sopenharmony_ci 63678c2ecf20Sopenharmony_ci if (asoc) { 63688c2ecf20Sopenharmony_ci info.snd_sid = asoc->default_stream; 63698c2ecf20Sopenharmony_ci info.snd_flags = asoc->default_flags; 63708c2ecf20Sopenharmony_ci info.snd_ppid = asoc->default_ppid; 63718c2ecf20Sopenharmony_ci info.snd_context = asoc->default_context; 63728c2ecf20Sopenharmony_ci } else { 63738c2ecf20Sopenharmony_ci info.snd_sid = sp->default_stream; 63748c2ecf20Sopenharmony_ci info.snd_flags = sp->default_flags; 63758c2ecf20Sopenharmony_ci info.snd_ppid = sp->default_ppid; 63768c2ecf20Sopenharmony_ci info.snd_context = sp->default_context; 63778c2ecf20Sopenharmony_ci } 63788c2ecf20Sopenharmony_ci 63798c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 63808c2ecf20Sopenharmony_ci return -EFAULT; 63818c2ecf20Sopenharmony_ci if (copy_to_user(optval, &info, len)) 63828c2ecf20Sopenharmony_ci return -EFAULT; 63838c2ecf20Sopenharmony_ci 63848c2ecf20Sopenharmony_ci return 0; 63858c2ecf20Sopenharmony_ci} 63868c2ecf20Sopenharmony_ci 63878c2ecf20Sopenharmony_ci/* 63888c2ecf20Sopenharmony_ci * 63898c2ecf20Sopenharmony_ci * 7.1.5 SCTP_NODELAY 63908c2ecf20Sopenharmony_ci * 63918c2ecf20Sopenharmony_ci * Turn on/off any Nagle-like algorithm. This means that packets are 63928c2ecf20Sopenharmony_ci * generally sent as soon as possible and no unnecessary delays are 63938c2ecf20Sopenharmony_ci * introduced, at the cost of more packets in the network. Expects an 63948c2ecf20Sopenharmony_ci * integer boolean flag. 63958c2ecf20Sopenharmony_ci */ 63968c2ecf20Sopenharmony_ci 63978c2ecf20Sopenharmony_cistatic int sctp_getsockopt_nodelay(struct sock *sk, int len, 63988c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 63998c2ecf20Sopenharmony_ci{ 64008c2ecf20Sopenharmony_ci int val; 64018c2ecf20Sopenharmony_ci 64028c2ecf20Sopenharmony_ci if (len < sizeof(int)) 64038c2ecf20Sopenharmony_ci return -EINVAL; 64048c2ecf20Sopenharmony_ci 64058c2ecf20Sopenharmony_ci len = sizeof(int); 64068c2ecf20Sopenharmony_ci val = (sctp_sk(sk)->nodelay == 1); 64078c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 64088c2ecf20Sopenharmony_ci return -EFAULT; 64098c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 64108c2ecf20Sopenharmony_ci return -EFAULT; 64118c2ecf20Sopenharmony_ci return 0; 64128c2ecf20Sopenharmony_ci} 64138c2ecf20Sopenharmony_ci 64148c2ecf20Sopenharmony_ci/* 64158c2ecf20Sopenharmony_ci * 64168c2ecf20Sopenharmony_ci * 7.1.1 SCTP_RTOINFO 64178c2ecf20Sopenharmony_ci * 64188c2ecf20Sopenharmony_ci * The protocol parameters used to initialize and bound retransmission 64198c2ecf20Sopenharmony_ci * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 64208c2ecf20Sopenharmony_ci * and modify these parameters. 64218c2ecf20Sopenharmony_ci * All parameters are time values, in milliseconds. A value of 0, when 64228c2ecf20Sopenharmony_ci * modifying the parameters, indicates that the current value should not 64238c2ecf20Sopenharmony_ci * be changed. 64248c2ecf20Sopenharmony_ci * 64258c2ecf20Sopenharmony_ci */ 64268c2ecf20Sopenharmony_cistatic int sctp_getsockopt_rtoinfo(struct sock *sk, int len, 64278c2ecf20Sopenharmony_ci char __user *optval, 64288c2ecf20Sopenharmony_ci int __user *optlen) { 64298c2ecf20Sopenharmony_ci struct sctp_rtoinfo rtoinfo; 64308c2ecf20Sopenharmony_ci struct sctp_association *asoc; 64318c2ecf20Sopenharmony_ci 64328c2ecf20Sopenharmony_ci if (len < sizeof (struct sctp_rtoinfo)) 64338c2ecf20Sopenharmony_ci return -EINVAL; 64348c2ecf20Sopenharmony_ci 64358c2ecf20Sopenharmony_ci len = sizeof(struct sctp_rtoinfo); 64368c2ecf20Sopenharmony_ci 64378c2ecf20Sopenharmony_ci if (copy_from_user(&rtoinfo, optval, len)) 64388c2ecf20Sopenharmony_ci return -EFAULT; 64398c2ecf20Sopenharmony_ci 64408c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); 64418c2ecf20Sopenharmony_ci 64428c2ecf20Sopenharmony_ci if (!asoc && rtoinfo.srto_assoc_id != SCTP_FUTURE_ASSOC && 64438c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 64448c2ecf20Sopenharmony_ci return -EINVAL; 64458c2ecf20Sopenharmony_ci 64468c2ecf20Sopenharmony_ci /* Values corresponding to the specific association. */ 64478c2ecf20Sopenharmony_ci if (asoc) { 64488c2ecf20Sopenharmony_ci rtoinfo.srto_initial = jiffies_to_msecs(asoc->rto_initial); 64498c2ecf20Sopenharmony_ci rtoinfo.srto_max = jiffies_to_msecs(asoc->rto_max); 64508c2ecf20Sopenharmony_ci rtoinfo.srto_min = jiffies_to_msecs(asoc->rto_min); 64518c2ecf20Sopenharmony_ci } else { 64528c2ecf20Sopenharmony_ci /* Values corresponding to the endpoint. */ 64538c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 64548c2ecf20Sopenharmony_ci 64558c2ecf20Sopenharmony_ci rtoinfo.srto_initial = sp->rtoinfo.srto_initial; 64568c2ecf20Sopenharmony_ci rtoinfo.srto_max = sp->rtoinfo.srto_max; 64578c2ecf20Sopenharmony_ci rtoinfo.srto_min = sp->rtoinfo.srto_min; 64588c2ecf20Sopenharmony_ci } 64598c2ecf20Sopenharmony_ci 64608c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 64618c2ecf20Sopenharmony_ci return -EFAULT; 64628c2ecf20Sopenharmony_ci 64638c2ecf20Sopenharmony_ci if (copy_to_user(optval, &rtoinfo, len)) 64648c2ecf20Sopenharmony_ci return -EFAULT; 64658c2ecf20Sopenharmony_ci 64668c2ecf20Sopenharmony_ci return 0; 64678c2ecf20Sopenharmony_ci} 64688c2ecf20Sopenharmony_ci 64698c2ecf20Sopenharmony_ci/* 64708c2ecf20Sopenharmony_ci * 64718c2ecf20Sopenharmony_ci * 7.1.2 SCTP_ASSOCINFO 64728c2ecf20Sopenharmony_ci * 64738c2ecf20Sopenharmony_ci * This option is used to tune the maximum retransmission attempts 64748c2ecf20Sopenharmony_ci * of the association. 64758c2ecf20Sopenharmony_ci * Returns an error if the new association retransmission value is 64768c2ecf20Sopenharmony_ci * greater than the sum of the retransmission value of the peer. 64778c2ecf20Sopenharmony_ci * See [SCTP] for more information. 64788c2ecf20Sopenharmony_ci * 64798c2ecf20Sopenharmony_ci */ 64808c2ecf20Sopenharmony_cistatic int sctp_getsockopt_associnfo(struct sock *sk, int len, 64818c2ecf20Sopenharmony_ci char __user *optval, 64828c2ecf20Sopenharmony_ci int __user *optlen) 64838c2ecf20Sopenharmony_ci{ 64848c2ecf20Sopenharmony_ci 64858c2ecf20Sopenharmony_ci struct sctp_assocparams assocparams; 64868c2ecf20Sopenharmony_ci struct sctp_association *asoc; 64878c2ecf20Sopenharmony_ci struct list_head *pos; 64888c2ecf20Sopenharmony_ci int cnt = 0; 64898c2ecf20Sopenharmony_ci 64908c2ecf20Sopenharmony_ci if (len < sizeof (struct sctp_assocparams)) 64918c2ecf20Sopenharmony_ci return -EINVAL; 64928c2ecf20Sopenharmony_ci 64938c2ecf20Sopenharmony_ci len = sizeof(struct sctp_assocparams); 64948c2ecf20Sopenharmony_ci 64958c2ecf20Sopenharmony_ci if (copy_from_user(&assocparams, optval, len)) 64968c2ecf20Sopenharmony_ci return -EFAULT; 64978c2ecf20Sopenharmony_ci 64988c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); 64998c2ecf20Sopenharmony_ci 65008c2ecf20Sopenharmony_ci if (!asoc && assocparams.sasoc_assoc_id != SCTP_FUTURE_ASSOC && 65018c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 65028c2ecf20Sopenharmony_ci return -EINVAL; 65038c2ecf20Sopenharmony_ci 65048c2ecf20Sopenharmony_ci /* Values correspoinding to the specific association */ 65058c2ecf20Sopenharmony_ci if (asoc) { 65068c2ecf20Sopenharmony_ci assocparams.sasoc_asocmaxrxt = asoc->max_retrans; 65078c2ecf20Sopenharmony_ci assocparams.sasoc_peer_rwnd = asoc->peer.rwnd; 65088c2ecf20Sopenharmony_ci assocparams.sasoc_local_rwnd = asoc->a_rwnd; 65098c2ecf20Sopenharmony_ci assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life); 65108c2ecf20Sopenharmony_ci 65118c2ecf20Sopenharmony_ci list_for_each(pos, &asoc->peer.transport_addr_list) { 65128c2ecf20Sopenharmony_ci cnt++; 65138c2ecf20Sopenharmony_ci } 65148c2ecf20Sopenharmony_ci 65158c2ecf20Sopenharmony_ci assocparams.sasoc_number_peer_destinations = cnt; 65168c2ecf20Sopenharmony_ci } else { 65178c2ecf20Sopenharmony_ci /* Values corresponding to the endpoint */ 65188c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 65198c2ecf20Sopenharmony_ci 65208c2ecf20Sopenharmony_ci assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt; 65218c2ecf20Sopenharmony_ci assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd; 65228c2ecf20Sopenharmony_ci assocparams.sasoc_local_rwnd = sp->assocparams.sasoc_local_rwnd; 65238c2ecf20Sopenharmony_ci assocparams.sasoc_cookie_life = 65248c2ecf20Sopenharmony_ci sp->assocparams.sasoc_cookie_life; 65258c2ecf20Sopenharmony_ci assocparams.sasoc_number_peer_destinations = 65268c2ecf20Sopenharmony_ci sp->assocparams. 65278c2ecf20Sopenharmony_ci sasoc_number_peer_destinations; 65288c2ecf20Sopenharmony_ci } 65298c2ecf20Sopenharmony_ci 65308c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 65318c2ecf20Sopenharmony_ci return -EFAULT; 65328c2ecf20Sopenharmony_ci 65338c2ecf20Sopenharmony_ci if (copy_to_user(optval, &assocparams, len)) 65348c2ecf20Sopenharmony_ci return -EFAULT; 65358c2ecf20Sopenharmony_ci 65368c2ecf20Sopenharmony_ci return 0; 65378c2ecf20Sopenharmony_ci} 65388c2ecf20Sopenharmony_ci 65398c2ecf20Sopenharmony_ci/* 65408c2ecf20Sopenharmony_ci * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 65418c2ecf20Sopenharmony_ci * 65428c2ecf20Sopenharmony_ci * This socket option is a boolean flag which turns on or off mapped V4 65438c2ecf20Sopenharmony_ci * addresses. If this option is turned on and the socket is type 65448c2ecf20Sopenharmony_ci * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 65458c2ecf20Sopenharmony_ci * If this option is turned off, then no mapping will be done of V4 65468c2ecf20Sopenharmony_ci * addresses and a user will receive both PF_INET6 and PF_INET type 65478c2ecf20Sopenharmony_ci * addresses on the socket. 65488c2ecf20Sopenharmony_ci */ 65498c2ecf20Sopenharmony_cistatic int sctp_getsockopt_mappedv4(struct sock *sk, int len, 65508c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 65518c2ecf20Sopenharmony_ci{ 65528c2ecf20Sopenharmony_ci int val; 65538c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 65548c2ecf20Sopenharmony_ci 65558c2ecf20Sopenharmony_ci if (len < sizeof(int)) 65568c2ecf20Sopenharmony_ci return -EINVAL; 65578c2ecf20Sopenharmony_ci 65588c2ecf20Sopenharmony_ci len = sizeof(int); 65598c2ecf20Sopenharmony_ci val = sp->v4mapped; 65608c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 65618c2ecf20Sopenharmony_ci return -EFAULT; 65628c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 65638c2ecf20Sopenharmony_ci return -EFAULT; 65648c2ecf20Sopenharmony_ci 65658c2ecf20Sopenharmony_ci return 0; 65668c2ecf20Sopenharmony_ci} 65678c2ecf20Sopenharmony_ci 65688c2ecf20Sopenharmony_ci/* 65698c2ecf20Sopenharmony_ci * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 65708c2ecf20Sopenharmony_ci * (chapter and verse is quoted at sctp_setsockopt_context()) 65718c2ecf20Sopenharmony_ci */ 65728c2ecf20Sopenharmony_cistatic int sctp_getsockopt_context(struct sock *sk, int len, 65738c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 65748c2ecf20Sopenharmony_ci{ 65758c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 65768c2ecf20Sopenharmony_ci struct sctp_association *asoc; 65778c2ecf20Sopenharmony_ci 65788c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_assoc_value)) 65798c2ecf20Sopenharmony_ci return -EINVAL; 65808c2ecf20Sopenharmony_ci 65818c2ecf20Sopenharmony_ci len = sizeof(struct sctp_assoc_value); 65828c2ecf20Sopenharmony_ci 65838c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 65848c2ecf20Sopenharmony_ci return -EFAULT; 65858c2ecf20Sopenharmony_ci 65868c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 65878c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 65888c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 65898c2ecf20Sopenharmony_ci return -EINVAL; 65908c2ecf20Sopenharmony_ci 65918c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->default_rcv_context 65928c2ecf20Sopenharmony_ci : sctp_sk(sk)->default_rcv_context; 65938c2ecf20Sopenharmony_ci 65948c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 65958c2ecf20Sopenharmony_ci return -EFAULT; 65968c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 65978c2ecf20Sopenharmony_ci return -EFAULT; 65988c2ecf20Sopenharmony_ci 65998c2ecf20Sopenharmony_ci return 0; 66008c2ecf20Sopenharmony_ci} 66018c2ecf20Sopenharmony_ci 66028c2ecf20Sopenharmony_ci/* 66038c2ecf20Sopenharmony_ci * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 66048c2ecf20Sopenharmony_ci * This option will get or set the maximum size to put in any outgoing 66058c2ecf20Sopenharmony_ci * SCTP DATA chunk. If a message is larger than this size it will be 66068c2ecf20Sopenharmony_ci * fragmented by SCTP into the specified size. Note that the underlying 66078c2ecf20Sopenharmony_ci * SCTP implementation may fragment into smaller sized chunks when the 66088c2ecf20Sopenharmony_ci * PMTU of the underlying association is smaller than the value set by 66098c2ecf20Sopenharmony_ci * the user. The default value for this option is '0' which indicates 66108c2ecf20Sopenharmony_ci * the user is NOT limiting fragmentation and only the PMTU will effect 66118c2ecf20Sopenharmony_ci * SCTP's choice of DATA chunk size. Note also that values set larger 66128c2ecf20Sopenharmony_ci * than the maximum size of an IP datagram will effectively let SCTP 66138c2ecf20Sopenharmony_ci * control fragmentation (i.e. the same as setting this option to 0). 66148c2ecf20Sopenharmony_ci * 66158c2ecf20Sopenharmony_ci * The following structure is used to access and modify this parameter: 66168c2ecf20Sopenharmony_ci * 66178c2ecf20Sopenharmony_ci * struct sctp_assoc_value { 66188c2ecf20Sopenharmony_ci * sctp_assoc_t assoc_id; 66198c2ecf20Sopenharmony_ci * uint32_t assoc_value; 66208c2ecf20Sopenharmony_ci * }; 66218c2ecf20Sopenharmony_ci * 66228c2ecf20Sopenharmony_ci * assoc_id: This parameter is ignored for one-to-one style sockets. 66238c2ecf20Sopenharmony_ci * For one-to-many style sockets this parameter indicates which 66248c2ecf20Sopenharmony_ci * association the user is performing an action upon. Note that if 66258c2ecf20Sopenharmony_ci * this field's value is zero then the endpoints default value is 66268c2ecf20Sopenharmony_ci * changed (effecting future associations only). 66278c2ecf20Sopenharmony_ci * assoc_value: This parameter specifies the maximum size in bytes. 66288c2ecf20Sopenharmony_ci */ 66298c2ecf20Sopenharmony_cistatic int sctp_getsockopt_maxseg(struct sock *sk, int len, 66308c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 66318c2ecf20Sopenharmony_ci{ 66328c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 66338c2ecf20Sopenharmony_ci struct sctp_association *asoc; 66348c2ecf20Sopenharmony_ci 66358c2ecf20Sopenharmony_ci if (len == sizeof(int)) { 66368c2ecf20Sopenharmony_ci pr_warn_ratelimited(DEPRECATED 66378c2ecf20Sopenharmony_ci "%s (pid %d) " 66388c2ecf20Sopenharmony_ci "Use of int in maxseg socket option.\n" 66398c2ecf20Sopenharmony_ci "Use struct sctp_assoc_value instead\n", 66408c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current)); 66418c2ecf20Sopenharmony_ci params.assoc_id = SCTP_FUTURE_ASSOC; 66428c2ecf20Sopenharmony_ci } else if (len >= sizeof(struct sctp_assoc_value)) { 66438c2ecf20Sopenharmony_ci len = sizeof(struct sctp_assoc_value); 66448c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 66458c2ecf20Sopenharmony_ci return -EFAULT; 66468c2ecf20Sopenharmony_ci } else 66478c2ecf20Sopenharmony_ci return -EINVAL; 66488c2ecf20Sopenharmony_ci 66498c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 66508c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 66518c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 66528c2ecf20Sopenharmony_ci return -EINVAL; 66538c2ecf20Sopenharmony_ci 66548c2ecf20Sopenharmony_ci if (asoc) 66558c2ecf20Sopenharmony_ci params.assoc_value = asoc->frag_point; 66568c2ecf20Sopenharmony_ci else 66578c2ecf20Sopenharmony_ci params.assoc_value = sctp_sk(sk)->user_frag; 66588c2ecf20Sopenharmony_ci 66598c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 66608c2ecf20Sopenharmony_ci return -EFAULT; 66618c2ecf20Sopenharmony_ci if (len == sizeof(int)) { 66628c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms.assoc_value, len)) 66638c2ecf20Sopenharmony_ci return -EFAULT; 66648c2ecf20Sopenharmony_ci } else { 66658c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 66668c2ecf20Sopenharmony_ci return -EFAULT; 66678c2ecf20Sopenharmony_ci } 66688c2ecf20Sopenharmony_ci 66698c2ecf20Sopenharmony_ci return 0; 66708c2ecf20Sopenharmony_ci} 66718c2ecf20Sopenharmony_ci 66728c2ecf20Sopenharmony_ci/* 66738c2ecf20Sopenharmony_ci * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 66748c2ecf20Sopenharmony_ci * (chapter and verse is quoted at sctp_setsockopt_fragment_interleave()) 66758c2ecf20Sopenharmony_ci */ 66768c2ecf20Sopenharmony_cistatic int sctp_getsockopt_fragment_interleave(struct sock *sk, int len, 66778c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 66788c2ecf20Sopenharmony_ci{ 66798c2ecf20Sopenharmony_ci int val; 66808c2ecf20Sopenharmony_ci 66818c2ecf20Sopenharmony_ci if (len < sizeof(int)) 66828c2ecf20Sopenharmony_ci return -EINVAL; 66838c2ecf20Sopenharmony_ci 66848c2ecf20Sopenharmony_ci len = sizeof(int); 66858c2ecf20Sopenharmony_ci 66868c2ecf20Sopenharmony_ci val = sctp_sk(sk)->frag_interleave; 66878c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 66888c2ecf20Sopenharmony_ci return -EFAULT; 66898c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 66908c2ecf20Sopenharmony_ci return -EFAULT; 66918c2ecf20Sopenharmony_ci 66928c2ecf20Sopenharmony_ci return 0; 66938c2ecf20Sopenharmony_ci} 66948c2ecf20Sopenharmony_ci 66958c2ecf20Sopenharmony_ci/* 66968c2ecf20Sopenharmony_ci * 7.1.25. Set or Get the sctp partial delivery point 66978c2ecf20Sopenharmony_ci * (chapter and verse is quoted at sctp_setsockopt_partial_delivery_point()) 66988c2ecf20Sopenharmony_ci */ 66998c2ecf20Sopenharmony_cistatic int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len, 67008c2ecf20Sopenharmony_ci char __user *optval, 67018c2ecf20Sopenharmony_ci int __user *optlen) 67028c2ecf20Sopenharmony_ci{ 67038c2ecf20Sopenharmony_ci u32 val; 67048c2ecf20Sopenharmony_ci 67058c2ecf20Sopenharmony_ci if (len < sizeof(u32)) 67068c2ecf20Sopenharmony_ci return -EINVAL; 67078c2ecf20Sopenharmony_ci 67088c2ecf20Sopenharmony_ci len = sizeof(u32); 67098c2ecf20Sopenharmony_ci 67108c2ecf20Sopenharmony_ci val = sctp_sk(sk)->pd_point; 67118c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 67128c2ecf20Sopenharmony_ci return -EFAULT; 67138c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 67148c2ecf20Sopenharmony_ci return -EFAULT; 67158c2ecf20Sopenharmony_ci 67168c2ecf20Sopenharmony_ci return 0; 67178c2ecf20Sopenharmony_ci} 67188c2ecf20Sopenharmony_ci 67198c2ecf20Sopenharmony_ci/* 67208c2ecf20Sopenharmony_ci * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 67218c2ecf20Sopenharmony_ci * (chapter and verse is quoted at sctp_setsockopt_maxburst()) 67228c2ecf20Sopenharmony_ci */ 67238c2ecf20Sopenharmony_cistatic int sctp_getsockopt_maxburst(struct sock *sk, int len, 67248c2ecf20Sopenharmony_ci char __user *optval, 67258c2ecf20Sopenharmony_ci int __user *optlen) 67268c2ecf20Sopenharmony_ci{ 67278c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 67288c2ecf20Sopenharmony_ci struct sctp_association *asoc; 67298c2ecf20Sopenharmony_ci 67308c2ecf20Sopenharmony_ci if (len == sizeof(int)) { 67318c2ecf20Sopenharmony_ci pr_warn_ratelimited(DEPRECATED 67328c2ecf20Sopenharmony_ci "%s (pid %d) " 67338c2ecf20Sopenharmony_ci "Use of int in max_burst socket option.\n" 67348c2ecf20Sopenharmony_ci "Use struct sctp_assoc_value instead\n", 67358c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current)); 67368c2ecf20Sopenharmony_ci params.assoc_id = SCTP_FUTURE_ASSOC; 67378c2ecf20Sopenharmony_ci } else if (len >= sizeof(struct sctp_assoc_value)) { 67388c2ecf20Sopenharmony_ci len = sizeof(struct sctp_assoc_value); 67398c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 67408c2ecf20Sopenharmony_ci return -EFAULT; 67418c2ecf20Sopenharmony_ci } else 67428c2ecf20Sopenharmony_ci return -EINVAL; 67438c2ecf20Sopenharmony_ci 67448c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 67458c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 67468c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 67478c2ecf20Sopenharmony_ci return -EINVAL; 67488c2ecf20Sopenharmony_ci 67498c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->max_burst : sctp_sk(sk)->max_burst; 67508c2ecf20Sopenharmony_ci 67518c2ecf20Sopenharmony_ci if (len == sizeof(int)) { 67528c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms.assoc_value, len)) 67538c2ecf20Sopenharmony_ci return -EFAULT; 67548c2ecf20Sopenharmony_ci } else { 67558c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 67568c2ecf20Sopenharmony_ci return -EFAULT; 67578c2ecf20Sopenharmony_ci } 67588c2ecf20Sopenharmony_ci 67598c2ecf20Sopenharmony_ci return 0; 67608c2ecf20Sopenharmony_ci 67618c2ecf20Sopenharmony_ci} 67628c2ecf20Sopenharmony_ci 67638c2ecf20Sopenharmony_cistatic int sctp_getsockopt_hmac_ident(struct sock *sk, int len, 67648c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 67658c2ecf20Sopenharmony_ci{ 67668c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 67678c2ecf20Sopenharmony_ci struct sctp_hmacalgo __user *p = (void __user *)optval; 67688c2ecf20Sopenharmony_ci struct sctp_hmac_algo_param *hmacs; 67698c2ecf20Sopenharmony_ci __u16 data_len = 0; 67708c2ecf20Sopenharmony_ci u32 num_idents; 67718c2ecf20Sopenharmony_ci int i; 67728c2ecf20Sopenharmony_ci 67738c2ecf20Sopenharmony_ci if (!ep->auth_enable) 67748c2ecf20Sopenharmony_ci return -EACCES; 67758c2ecf20Sopenharmony_ci 67768c2ecf20Sopenharmony_ci hmacs = ep->auth_hmacs_list; 67778c2ecf20Sopenharmony_ci data_len = ntohs(hmacs->param_hdr.length) - 67788c2ecf20Sopenharmony_ci sizeof(struct sctp_paramhdr); 67798c2ecf20Sopenharmony_ci 67808c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_hmacalgo) + data_len) 67818c2ecf20Sopenharmony_ci return -EINVAL; 67828c2ecf20Sopenharmony_ci 67838c2ecf20Sopenharmony_ci len = sizeof(struct sctp_hmacalgo) + data_len; 67848c2ecf20Sopenharmony_ci num_idents = data_len / sizeof(u16); 67858c2ecf20Sopenharmony_ci 67868c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 67878c2ecf20Sopenharmony_ci return -EFAULT; 67888c2ecf20Sopenharmony_ci if (put_user(num_idents, &p->shmac_num_idents)) 67898c2ecf20Sopenharmony_ci return -EFAULT; 67908c2ecf20Sopenharmony_ci for (i = 0; i < num_idents; i++) { 67918c2ecf20Sopenharmony_ci __u16 hmacid = ntohs(hmacs->hmac_ids[i]); 67928c2ecf20Sopenharmony_ci 67938c2ecf20Sopenharmony_ci if (copy_to_user(&p->shmac_idents[i], &hmacid, sizeof(__u16))) 67948c2ecf20Sopenharmony_ci return -EFAULT; 67958c2ecf20Sopenharmony_ci } 67968c2ecf20Sopenharmony_ci return 0; 67978c2ecf20Sopenharmony_ci} 67988c2ecf20Sopenharmony_ci 67998c2ecf20Sopenharmony_cistatic int sctp_getsockopt_active_key(struct sock *sk, int len, 68008c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 68018c2ecf20Sopenharmony_ci{ 68028c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 68038c2ecf20Sopenharmony_ci struct sctp_authkeyid val; 68048c2ecf20Sopenharmony_ci struct sctp_association *asoc; 68058c2ecf20Sopenharmony_ci 68068c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_authkeyid)) 68078c2ecf20Sopenharmony_ci return -EINVAL; 68088c2ecf20Sopenharmony_ci 68098c2ecf20Sopenharmony_ci len = sizeof(struct sctp_authkeyid); 68108c2ecf20Sopenharmony_ci if (copy_from_user(&val, optval, len)) 68118c2ecf20Sopenharmony_ci return -EFAULT; 68128c2ecf20Sopenharmony_ci 68138c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, val.scact_assoc_id); 68148c2ecf20Sopenharmony_ci if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 68158c2ecf20Sopenharmony_ci return -EINVAL; 68168c2ecf20Sopenharmony_ci 68178c2ecf20Sopenharmony_ci if (asoc) { 68188c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 68198c2ecf20Sopenharmony_ci return -EACCES; 68208c2ecf20Sopenharmony_ci val.scact_keynumber = asoc->active_key_id; 68218c2ecf20Sopenharmony_ci } else { 68228c2ecf20Sopenharmony_ci if (!ep->auth_enable) 68238c2ecf20Sopenharmony_ci return -EACCES; 68248c2ecf20Sopenharmony_ci val.scact_keynumber = ep->active_key_id; 68258c2ecf20Sopenharmony_ci } 68268c2ecf20Sopenharmony_ci 68278c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 68288c2ecf20Sopenharmony_ci return -EFAULT; 68298c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 68308c2ecf20Sopenharmony_ci return -EFAULT; 68318c2ecf20Sopenharmony_ci 68328c2ecf20Sopenharmony_ci return 0; 68338c2ecf20Sopenharmony_ci} 68348c2ecf20Sopenharmony_ci 68358c2ecf20Sopenharmony_cistatic int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, 68368c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 68378c2ecf20Sopenharmony_ci{ 68388c2ecf20Sopenharmony_ci struct sctp_authchunks __user *p = (void __user *)optval; 68398c2ecf20Sopenharmony_ci struct sctp_authchunks val; 68408c2ecf20Sopenharmony_ci struct sctp_association *asoc; 68418c2ecf20Sopenharmony_ci struct sctp_chunks_param *ch; 68428c2ecf20Sopenharmony_ci u32 num_chunks = 0; 68438c2ecf20Sopenharmony_ci char __user *to; 68448c2ecf20Sopenharmony_ci 68458c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_authchunks)) 68468c2ecf20Sopenharmony_ci return -EINVAL; 68478c2ecf20Sopenharmony_ci 68488c2ecf20Sopenharmony_ci if (copy_from_user(&val, optval, sizeof(val))) 68498c2ecf20Sopenharmony_ci return -EFAULT; 68508c2ecf20Sopenharmony_ci 68518c2ecf20Sopenharmony_ci to = p->gauth_chunks; 68528c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 68538c2ecf20Sopenharmony_ci if (!asoc) 68548c2ecf20Sopenharmony_ci return -EINVAL; 68558c2ecf20Sopenharmony_ci 68568c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 68578c2ecf20Sopenharmony_ci return -EACCES; 68588c2ecf20Sopenharmony_ci 68598c2ecf20Sopenharmony_ci ch = asoc->peer.peer_chunks; 68608c2ecf20Sopenharmony_ci if (!ch) 68618c2ecf20Sopenharmony_ci goto num; 68628c2ecf20Sopenharmony_ci 68638c2ecf20Sopenharmony_ci /* See if the user provided enough room for all the data */ 68648c2ecf20Sopenharmony_ci num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); 68658c2ecf20Sopenharmony_ci if (len < num_chunks) 68668c2ecf20Sopenharmony_ci return -EINVAL; 68678c2ecf20Sopenharmony_ci 68688c2ecf20Sopenharmony_ci if (copy_to_user(to, ch->chunks, num_chunks)) 68698c2ecf20Sopenharmony_ci return -EFAULT; 68708c2ecf20Sopenharmony_cinum: 68718c2ecf20Sopenharmony_ci len = sizeof(struct sctp_authchunks) + num_chunks; 68728c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 68738c2ecf20Sopenharmony_ci return -EFAULT; 68748c2ecf20Sopenharmony_ci if (put_user(num_chunks, &p->gauth_number_of_chunks)) 68758c2ecf20Sopenharmony_ci return -EFAULT; 68768c2ecf20Sopenharmony_ci return 0; 68778c2ecf20Sopenharmony_ci} 68788c2ecf20Sopenharmony_ci 68798c2ecf20Sopenharmony_cistatic int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, 68808c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 68818c2ecf20Sopenharmony_ci{ 68828c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 68838c2ecf20Sopenharmony_ci struct sctp_authchunks __user *p = (void __user *)optval; 68848c2ecf20Sopenharmony_ci struct sctp_authchunks val; 68858c2ecf20Sopenharmony_ci struct sctp_association *asoc; 68868c2ecf20Sopenharmony_ci struct sctp_chunks_param *ch; 68878c2ecf20Sopenharmony_ci u32 num_chunks = 0; 68888c2ecf20Sopenharmony_ci char __user *to; 68898c2ecf20Sopenharmony_ci 68908c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_authchunks)) 68918c2ecf20Sopenharmony_ci return -EINVAL; 68928c2ecf20Sopenharmony_ci 68938c2ecf20Sopenharmony_ci if (copy_from_user(&val, optval, sizeof(val))) 68948c2ecf20Sopenharmony_ci return -EFAULT; 68958c2ecf20Sopenharmony_ci 68968c2ecf20Sopenharmony_ci to = p->gauth_chunks; 68978c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 68988c2ecf20Sopenharmony_ci if (!asoc && val.gauth_assoc_id != SCTP_FUTURE_ASSOC && 68998c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 69008c2ecf20Sopenharmony_ci return -EINVAL; 69018c2ecf20Sopenharmony_ci 69028c2ecf20Sopenharmony_ci if (asoc) { 69038c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 69048c2ecf20Sopenharmony_ci return -EACCES; 69058c2ecf20Sopenharmony_ci ch = (struct sctp_chunks_param *)asoc->c.auth_chunks; 69068c2ecf20Sopenharmony_ci } else { 69078c2ecf20Sopenharmony_ci if (!ep->auth_enable) 69088c2ecf20Sopenharmony_ci return -EACCES; 69098c2ecf20Sopenharmony_ci ch = ep->auth_chunk_list; 69108c2ecf20Sopenharmony_ci } 69118c2ecf20Sopenharmony_ci if (!ch) 69128c2ecf20Sopenharmony_ci goto num; 69138c2ecf20Sopenharmony_ci 69148c2ecf20Sopenharmony_ci num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); 69158c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_authchunks) + num_chunks) 69168c2ecf20Sopenharmony_ci return -EINVAL; 69178c2ecf20Sopenharmony_ci 69188c2ecf20Sopenharmony_ci if (copy_to_user(to, ch->chunks, num_chunks)) 69198c2ecf20Sopenharmony_ci return -EFAULT; 69208c2ecf20Sopenharmony_cinum: 69218c2ecf20Sopenharmony_ci len = sizeof(struct sctp_authchunks) + num_chunks; 69228c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 69238c2ecf20Sopenharmony_ci return -EFAULT; 69248c2ecf20Sopenharmony_ci if (put_user(num_chunks, &p->gauth_number_of_chunks)) 69258c2ecf20Sopenharmony_ci return -EFAULT; 69268c2ecf20Sopenharmony_ci 69278c2ecf20Sopenharmony_ci return 0; 69288c2ecf20Sopenharmony_ci} 69298c2ecf20Sopenharmony_ci 69308c2ecf20Sopenharmony_ci/* 69318c2ecf20Sopenharmony_ci * 8.2.5. Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER) 69328c2ecf20Sopenharmony_ci * This option gets the current number of associations that are attached 69338c2ecf20Sopenharmony_ci * to a one-to-many style socket. The option value is an uint32_t. 69348c2ecf20Sopenharmony_ci */ 69358c2ecf20Sopenharmony_cistatic int sctp_getsockopt_assoc_number(struct sock *sk, int len, 69368c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 69378c2ecf20Sopenharmony_ci{ 69388c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 69398c2ecf20Sopenharmony_ci struct sctp_association *asoc; 69408c2ecf20Sopenharmony_ci u32 val = 0; 69418c2ecf20Sopenharmony_ci 69428c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 69438c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 69448c2ecf20Sopenharmony_ci 69458c2ecf20Sopenharmony_ci if (len < sizeof(u32)) 69468c2ecf20Sopenharmony_ci return -EINVAL; 69478c2ecf20Sopenharmony_ci 69488c2ecf20Sopenharmony_ci len = sizeof(u32); 69498c2ecf20Sopenharmony_ci 69508c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 69518c2ecf20Sopenharmony_ci val++; 69528c2ecf20Sopenharmony_ci } 69538c2ecf20Sopenharmony_ci 69548c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 69558c2ecf20Sopenharmony_ci return -EFAULT; 69568c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 69578c2ecf20Sopenharmony_ci return -EFAULT; 69588c2ecf20Sopenharmony_ci 69598c2ecf20Sopenharmony_ci return 0; 69608c2ecf20Sopenharmony_ci} 69618c2ecf20Sopenharmony_ci 69628c2ecf20Sopenharmony_ci/* 69638c2ecf20Sopenharmony_ci * 8.1.23 SCTP_AUTO_ASCONF 69648c2ecf20Sopenharmony_ci * See the corresponding setsockopt entry as description 69658c2ecf20Sopenharmony_ci */ 69668c2ecf20Sopenharmony_cistatic int sctp_getsockopt_auto_asconf(struct sock *sk, int len, 69678c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 69688c2ecf20Sopenharmony_ci{ 69698c2ecf20Sopenharmony_ci int val = 0; 69708c2ecf20Sopenharmony_ci 69718c2ecf20Sopenharmony_ci if (len < sizeof(int)) 69728c2ecf20Sopenharmony_ci return -EINVAL; 69738c2ecf20Sopenharmony_ci 69748c2ecf20Sopenharmony_ci len = sizeof(int); 69758c2ecf20Sopenharmony_ci if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk)) 69768c2ecf20Sopenharmony_ci val = 1; 69778c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 69788c2ecf20Sopenharmony_ci return -EFAULT; 69798c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 69808c2ecf20Sopenharmony_ci return -EFAULT; 69818c2ecf20Sopenharmony_ci return 0; 69828c2ecf20Sopenharmony_ci} 69838c2ecf20Sopenharmony_ci 69848c2ecf20Sopenharmony_ci/* 69858c2ecf20Sopenharmony_ci * 8.2.6. Get the Current Identifiers of Associations 69868c2ecf20Sopenharmony_ci * (SCTP_GET_ASSOC_ID_LIST) 69878c2ecf20Sopenharmony_ci * 69888c2ecf20Sopenharmony_ci * This option gets the current list of SCTP association identifiers of 69898c2ecf20Sopenharmony_ci * the SCTP associations handled by a one-to-many style socket. 69908c2ecf20Sopenharmony_ci */ 69918c2ecf20Sopenharmony_cistatic int sctp_getsockopt_assoc_ids(struct sock *sk, int len, 69928c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 69938c2ecf20Sopenharmony_ci{ 69948c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 69958c2ecf20Sopenharmony_ci struct sctp_association *asoc; 69968c2ecf20Sopenharmony_ci struct sctp_assoc_ids *ids; 69978c2ecf20Sopenharmony_ci u32 num = 0; 69988c2ecf20Sopenharmony_ci 69998c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP)) 70008c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 70018c2ecf20Sopenharmony_ci 70028c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_assoc_ids)) 70038c2ecf20Sopenharmony_ci return -EINVAL; 70048c2ecf20Sopenharmony_ci 70058c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 70068c2ecf20Sopenharmony_ci num++; 70078c2ecf20Sopenharmony_ci } 70088c2ecf20Sopenharmony_ci 70098c2ecf20Sopenharmony_ci if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num) 70108c2ecf20Sopenharmony_ci return -EINVAL; 70118c2ecf20Sopenharmony_ci 70128c2ecf20Sopenharmony_ci len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num; 70138c2ecf20Sopenharmony_ci 70148c2ecf20Sopenharmony_ci ids = kmalloc(len, GFP_USER | __GFP_NOWARN); 70158c2ecf20Sopenharmony_ci if (unlikely(!ids)) 70168c2ecf20Sopenharmony_ci return -ENOMEM; 70178c2ecf20Sopenharmony_ci 70188c2ecf20Sopenharmony_ci ids->gaids_number_of_ids = num; 70198c2ecf20Sopenharmony_ci num = 0; 70208c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 70218c2ecf20Sopenharmony_ci ids->gaids_assoc_id[num++] = asoc->assoc_id; 70228c2ecf20Sopenharmony_ci } 70238c2ecf20Sopenharmony_ci 70248c2ecf20Sopenharmony_ci if (put_user(len, optlen) || copy_to_user(optval, ids, len)) { 70258c2ecf20Sopenharmony_ci kfree(ids); 70268c2ecf20Sopenharmony_ci return -EFAULT; 70278c2ecf20Sopenharmony_ci } 70288c2ecf20Sopenharmony_ci 70298c2ecf20Sopenharmony_ci kfree(ids); 70308c2ecf20Sopenharmony_ci return 0; 70318c2ecf20Sopenharmony_ci} 70328c2ecf20Sopenharmony_ci 70338c2ecf20Sopenharmony_ci/* 70348c2ecf20Sopenharmony_ci * SCTP_PEER_ADDR_THLDS 70358c2ecf20Sopenharmony_ci * 70368c2ecf20Sopenharmony_ci * This option allows us to fetch the partially failed threshold for one or all 70378c2ecf20Sopenharmony_ci * transports in an association. See Section 6.1 of: 70388c2ecf20Sopenharmony_ci * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 70398c2ecf20Sopenharmony_ci */ 70408c2ecf20Sopenharmony_cistatic int sctp_getsockopt_paddr_thresholds(struct sock *sk, 70418c2ecf20Sopenharmony_ci char __user *optval, int len, 70428c2ecf20Sopenharmony_ci int __user *optlen, bool v2) 70438c2ecf20Sopenharmony_ci{ 70448c2ecf20Sopenharmony_ci struct sctp_paddrthlds_v2 val; 70458c2ecf20Sopenharmony_ci struct sctp_transport *trans; 70468c2ecf20Sopenharmony_ci struct sctp_association *asoc; 70478c2ecf20Sopenharmony_ci int min; 70488c2ecf20Sopenharmony_ci 70498c2ecf20Sopenharmony_ci min = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds); 70508c2ecf20Sopenharmony_ci if (len < min) 70518c2ecf20Sopenharmony_ci return -EINVAL; 70528c2ecf20Sopenharmony_ci len = min; 70538c2ecf20Sopenharmony_ci if (copy_from_user(&val, optval, len)) 70548c2ecf20Sopenharmony_ci return -EFAULT; 70558c2ecf20Sopenharmony_ci 70568c2ecf20Sopenharmony_ci if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { 70578c2ecf20Sopenharmony_ci trans = sctp_addr_id2transport(sk, &val.spt_address, 70588c2ecf20Sopenharmony_ci val.spt_assoc_id); 70598c2ecf20Sopenharmony_ci if (!trans) 70608c2ecf20Sopenharmony_ci return -ENOENT; 70618c2ecf20Sopenharmony_ci 70628c2ecf20Sopenharmony_ci val.spt_pathmaxrxt = trans->pathmaxrxt; 70638c2ecf20Sopenharmony_ci val.spt_pathpfthld = trans->pf_retrans; 70648c2ecf20Sopenharmony_ci val.spt_pathcpthld = trans->ps_retrans; 70658c2ecf20Sopenharmony_ci 70668c2ecf20Sopenharmony_ci goto out; 70678c2ecf20Sopenharmony_ci } 70688c2ecf20Sopenharmony_ci 70698c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, val.spt_assoc_id); 70708c2ecf20Sopenharmony_ci if (!asoc && val.spt_assoc_id != SCTP_FUTURE_ASSOC && 70718c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 70728c2ecf20Sopenharmony_ci return -EINVAL; 70738c2ecf20Sopenharmony_ci 70748c2ecf20Sopenharmony_ci if (asoc) { 70758c2ecf20Sopenharmony_ci val.spt_pathpfthld = asoc->pf_retrans; 70768c2ecf20Sopenharmony_ci val.spt_pathmaxrxt = asoc->pathmaxrxt; 70778c2ecf20Sopenharmony_ci val.spt_pathcpthld = asoc->ps_retrans; 70788c2ecf20Sopenharmony_ci } else { 70798c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 70808c2ecf20Sopenharmony_ci 70818c2ecf20Sopenharmony_ci val.spt_pathpfthld = sp->pf_retrans; 70828c2ecf20Sopenharmony_ci val.spt_pathmaxrxt = sp->pathmaxrxt; 70838c2ecf20Sopenharmony_ci val.spt_pathcpthld = sp->ps_retrans; 70848c2ecf20Sopenharmony_ci } 70858c2ecf20Sopenharmony_ci 70868c2ecf20Sopenharmony_ciout: 70878c2ecf20Sopenharmony_ci if (put_user(len, optlen) || copy_to_user(optval, &val, len)) 70888c2ecf20Sopenharmony_ci return -EFAULT; 70898c2ecf20Sopenharmony_ci 70908c2ecf20Sopenharmony_ci return 0; 70918c2ecf20Sopenharmony_ci} 70928c2ecf20Sopenharmony_ci 70938c2ecf20Sopenharmony_ci/* 70948c2ecf20Sopenharmony_ci * SCTP_GET_ASSOC_STATS 70958c2ecf20Sopenharmony_ci * 70968c2ecf20Sopenharmony_ci * This option retrieves local per endpoint statistics. It is modeled 70978c2ecf20Sopenharmony_ci * after OpenSolaris' implementation 70988c2ecf20Sopenharmony_ci */ 70998c2ecf20Sopenharmony_cistatic int sctp_getsockopt_assoc_stats(struct sock *sk, int len, 71008c2ecf20Sopenharmony_ci char __user *optval, 71018c2ecf20Sopenharmony_ci int __user *optlen) 71028c2ecf20Sopenharmony_ci{ 71038c2ecf20Sopenharmony_ci struct sctp_assoc_stats sas; 71048c2ecf20Sopenharmony_ci struct sctp_association *asoc = NULL; 71058c2ecf20Sopenharmony_ci 71068c2ecf20Sopenharmony_ci /* User must provide at least the assoc id */ 71078c2ecf20Sopenharmony_ci if (len < sizeof(sctp_assoc_t)) 71088c2ecf20Sopenharmony_ci return -EINVAL; 71098c2ecf20Sopenharmony_ci 71108c2ecf20Sopenharmony_ci /* Allow the struct to grow and fill in as much as possible */ 71118c2ecf20Sopenharmony_ci len = min_t(size_t, len, sizeof(sas)); 71128c2ecf20Sopenharmony_ci 71138c2ecf20Sopenharmony_ci if (copy_from_user(&sas, optval, len)) 71148c2ecf20Sopenharmony_ci return -EFAULT; 71158c2ecf20Sopenharmony_ci 71168c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, sas.sas_assoc_id); 71178c2ecf20Sopenharmony_ci if (!asoc) 71188c2ecf20Sopenharmony_ci return -EINVAL; 71198c2ecf20Sopenharmony_ci 71208c2ecf20Sopenharmony_ci sas.sas_rtxchunks = asoc->stats.rtxchunks; 71218c2ecf20Sopenharmony_ci sas.sas_gapcnt = asoc->stats.gapcnt; 71228c2ecf20Sopenharmony_ci sas.sas_outofseqtsns = asoc->stats.outofseqtsns; 71238c2ecf20Sopenharmony_ci sas.sas_osacks = asoc->stats.osacks; 71248c2ecf20Sopenharmony_ci sas.sas_isacks = asoc->stats.isacks; 71258c2ecf20Sopenharmony_ci sas.sas_octrlchunks = asoc->stats.octrlchunks; 71268c2ecf20Sopenharmony_ci sas.sas_ictrlchunks = asoc->stats.ictrlchunks; 71278c2ecf20Sopenharmony_ci sas.sas_oodchunks = asoc->stats.oodchunks; 71288c2ecf20Sopenharmony_ci sas.sas_iodchunks = asoc->stats.iodchunks; 71298c2ecf20Sopenharmony_ci sas.sas_ouodchunks = asoc->stats.ouodchunks; 71308c2ecf20Sopenharmony_ci sas.sas_iuodchunks = asoc->stats.iuodchunks; 71318c2ecf20Sopenharmony_ci sas.sas_idupchunks = asoc->stats.idupchunks; 71328c2ecf20Sopenharmony_ci sas.sas_opackets = asoc->stats.opackets; 71338c2ecf20Sopenharmony_ci sas.sas_ipackets = asoc->stats.ipackets; 71348c2ecf20Sopenharmony_ci 71358c2ecf20Sopenharmony_ci /* New high max rto observed, will return 0 if not a single 71368c2ecf20Sopenharmony_ci * RTO update took place. obs_rto_ipaddr will be bogus 71378c2ecf20Sopenharmony_ci * in such a case 71388c2ecf20Sopenharmony_ci */ 71398c2ecf20Sopenharmony_ci sas.sas_maxrto = asoc->stats.max_obs_rto; 71408c2ecf20Sopenharmony_ci memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr, 71418c2ecf20Sopenharmony_ci sizeof(struct sockaddr_storage)); 71428c2ecf20Sopenharmony_ci 71438c2ecf20Sopenharmony_ci /* Mark beginning of a new observation period */ 71448c2ecf20Sopenharmony_ci asoc->stats.max_obs_rto = asoc->rto_min; 71458c2ecf20Sopenharmony_ci 71468c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 71478c2ecf20Sopenharmony_ci return -EFAULT; 71488c2ecf20Sopenharmony_ci 71498c2ecf20Sopenharmony_ci pr_debug("%s: len:%d, assoc_id:%d\n", __func__, len, sas.sas_assoc_id); 71508c2ecf20Sopenharmony_ci 71518c2ecf20Sopenharmony_ci if (copy_to_user(optval, &sas, len)) 71528c2ecf20Sopenharmony_ci return -EFAULT; 71538c2ecf20Sopenharmony_ci 71548c2ecf20Sopenharmony_ci return 0; 71558c2ecf20Sopenharmony_ci} 71568c2ecf20Sopenharmony_ci 71578c2ecf20Sopenharmony_cistatic int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, 71588c2ecf20Sopenharmony_ci char __user *optval, 71598c2ecf20Sopenharmony_ci int __user *optlen) 71608c2ecf20Sopenharmony_ci{ 71618c2ecf20Sopenharmony_ci int val = 0; 71628c2ecf20Sopenharmony_ci 71638c2ecf20Sopenharmony_ci if (len < sizeof(int)) 71648c2ecf20Sopenharmony_ci return -EINVAL; 71658c2ecf20Sopenharmony_ci 71668c2ecf20Sopenharmony_ci len = sizeof(int); 71678c2ecf20Sopenharmony_ci if (sctp_sk(sk)->recvrcvinfo) 71688c2ecf20Sopenharmony_ci val = 1; 71698c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 71708c2ecf20Sopenharmony_ci return -EFAULT; 71718c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 71728c2ecf20Sopenharmony_ci return -EFAULT; 71738c2ecf20Sopenharmony_ci 71748c2ecf20Sopenharmony_ci return 0; 71758c2ecf20Sopenharmony_ci} 71768c2ecf20Sopenharmony_ci 71778c2ecf20Sopenharmony_cistatic int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len, 71788c2ecf20Sopenharmony_ci char __user *optval, 71798c2ecf20Sopenharmony_ci int __user *optlen) 71808c2ecf20Sopenharmony_ci{ 71818c2ecf20Sopenharmony_ci int val = 0; 71828c2ecf20Sopenharmony_ci 71838c2ecf20Sopenharmony_ci if (len < sizeof(int)) 71848c2ecf20Sopenharmony_ci return -EINVAL; 71858c2ecf20Sopenharmony_ci 71868c2ecf20Sopenharmony_ci len = sizeof(int); 71878c2ecf20Sopenharmony_ci if (sctp_sk(sk)->recvnxtinfo) 71888c2ecf20Sopenharmony_ci val = 1; 71898c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 71908c2ecf20Sopenharmony_ci return -EFAULT; 71918c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 71928c2ecf20Sopenharmony_ci return -EFAULT; 71938c2ecf20Sopenharmony_ci 71948c2ecf20Sopenharmony_ci return 0; 71958c2ecf20Sopenharmony_ci} 71968c2ecf20Sopenharmony_ci 71978c2ecf20Sopenharmony_cistatic int sctp_getsockopt_pr_supported(struct sock *sk, int len, 71988c2ecf20Sopenharmony_ci char __user *optval, 71998c2ecf20Sopenharmony_ci int __user *optlen) 72008c2ecf20Sopenharmony_ci{ 72018c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 72028c2ecf20Sopenharmony_ci struct sctp_association *asoc; 72038c2ecf20Sopenharmony_ci int retval = -EFAULT; 72048c2ecf20Sopenharmony_ci 72058c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 72068c2ecf20Sopenharmony_ci retval = -EINVAL; 72078c2ecf20Sopenharmony_ci goto out; 72088c2ecf20Sopenharmony_ci } 72098c2ecf20Sopenharmony_ci 72108c2ecf20Sopenharmony_ci len = sizeof(params); 72118c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 72128c2ecf20Sopenharmony_ci goto out; 72138c2ecf20Sopenharmony_ci 72148c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 72158c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 72168c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 72178c2ecf20Sopenharmony_ci retval = -EINVAL; 72188c2ecf20Sopenharmony_ci goto out; 72198c2ecf20Sopenharmony_ci } 72208c2ecf20Sopenharmony_ci 72218c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->peer.prsctp_capable 72228c2ecf20Sopenharmony_ci : sctp_sk(sk)->ep->prsctp_enable; 72238c2ecf20Sopenharmony_ci 72248c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 72258c2ecf20Sopenharmony_ci goto out; 72268c2ecf20Sopenharmony_ci 72278c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 72288c2ecf20Sopenharmony_ci goto out; 72298c2ecf20Sopenharmony_ci 72308c2ecf20Sopenharmony_ci retval = 0; 72318c2ecf20Sopenharmony_ci 72328c2ecf20Sopenharmony_ciout: 72338c2ecf20Sopenharmony_ci return retval; 72348c2ecf20Sopenharmony_ci} 72358c2ecf20Sopenharmony_ci 72368c2ecf20Sopenharmony_cistatic int sctp_getsockopt_default_prinfo(struct sock *sk, int len, 72378c2ecf20Sopenharmony_ci char __user *optval, 72388c2ecf20Sopenharmony_ci int __user *optlen) 72398c2ecf20Sopenharmony_ci{ 72408c2ecf20Sopenharmony_ci struct sctp_default_prinfo info; 72418c2ecf20Sopenharmony_ci struct sctp_association *asoc; 72428c2ecf20Sopenharmony_ci int retval = -EFAULT; 72438c2ecf20Sopenharmony_ci 72448c2ecf20Sopenharmony_ci if (len < sizeof(info)) { 72458c2ecf20Sopenharmony_ci retval = -EINVAL; 72468c2ecf20Sopenharmony_ci goto out; 72478c2ecf20Sopenharmony_ci } 72488c2ecf20Sopenharmony_ci 72498c2ecf20Sopenharmony_ci len = sizeof(info); 72508c2ecf20Sopenharmony_ci if (copy_from_user(&info, optval, len)) 72518c2ecf20Sopenharmony_ci goto out; 72528c2ecf20Sopenharmony_ci 72538c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, info.pr_assoc_id); 72548c2ecf20Sopenharmony_ci if (!asoc && info.pr_assoc_id != SCTP_FUTURE_ASSOC && 72558c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 72568c2ecf20Sopenharmony_ci retval = -EINVAL; 72578c2ecf20Sopenharmony_ci goto out; 72588c2ecf20Sopenharmony_ci } 72598c2ecf20Sopenharmony_ci 72608c2ecf20Sopenharmony_ci if (asoc) { 72618c2ecf20Sopenharmony_ci info.pr_policy = SCTP_PR_POLICY(asoc->default_flags); 72628c2ecf20Sopenharmony_ci info.pr_value = asoc->default_timetolive; 72638c2ecf20Sopenharmony_ci } else { 72648c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 72658c2ecf20Sopenharmony_ci 72668c2ecf20Sopenharmony_ci info.pr_policy = SCTP_PR_POLICY(sp->default_flags); 72678c2ecf20Sopenharmony_ci info.pr_value = sp->default_timetolive; 72688c2ecf20Sopenharmony_ci } 72698c2ecf20Sopenharmony_ci 72708c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 72718c2ecf20Sopenharmony_ci goto out; 72728c2ecf20Sopenharmony_ci 72738c2ecf20Sopenharmony_ci if (copy_to_user(optval, &info, len)) 72748c2ecf20Sopenharmony_ci goto out; 72758c2ecf20Sopenharmony_ci 72768c2ecf20Sopenharmony_ci retval = 0; 72778c2ecf20Sopenharmony_ci 72788c2ecf20Sopenharmony_ciout: 72798c2ecf20Sopenharmony_ci return retval; 72808c2ecf20Sopenharmony_ci} 72818c2ecf20Sopenharmony_ci 72828c2ecf20Sopenharmony_cistatic int sctp_getsockopt_pr_assocstatus(struct sock *sk, int len, 72838c2ecf20Sopenharmony_ci char __user *optval, 72848c2ecf20Sopenharmony_ci int __user *optlen) 72858c2ecf20Sopenharmony_ci{ 72868c2ecf20Sopenharmony_ci struct sctp_prstatus params; 72878c2ecf20Sopenharmony_ci struct sctp_association *asoc; 72888c2ecf20Sopenharmony_ci int policy; 72898c2ecf20Sopenharmony_ci int retval = -EINVAL; 72908c2ecf20Sopenharmony_ci 72918c2ecf20Sopenharmony_ci if (len < sizeof(params)) 72928c2ecf20Sopenharmony_ci goto out; 72938c2ecf20Sopenharmony_ci 72948c2ecf20Sopenharmony_ci len = sizeof(params); 72958c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) { 72968c2ecf20Sopenharmony_ci retval = -EFAULT; 72978c2ecf20Sopenharmony_ci goto out; 72988c2ecf20Sopenharmony_ci } 72998c2ecf20Sopenharmony_ci 73008c2ecf20Sopenharmony_ci policy = params.sprstat_policy; 73018c2ecf20Sopenharmony_ci if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) || 73028c2ecf20Sopenharmony_ci ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK))) 73038c2ecf20Sopenharmony_ci goto out; 73048c2ecf20Sopenharmony_ci 73058c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); 73068c2ecf20Sopenharmony_ci if (!asoc) 73078c2ecf20Sopenharmony_ci goto out; 73088c2ecf20Sopenharmony_ci 73098c2ecf20Sopenharmony_ci if (policy == SCTP_PR_SCTP_ALL) { 73108c2ecf20Sopenharmony_ci params.sprstat_abandoned_unsent = 0; 73118c2ecf20Sopenharmony_ci params.sprstat_abandoned_sent = 0; 73128c2ecf20Sopenharmony_ci for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { 73138c2ecf20Sopenharmony_ci params.sprstat_abandoned_unsent += 73148c2ecf20Sopenharmony_ci asoc->abandoned_unsent[policy]; 73158c2ecf20Sopenharmony_ci params.sprstat_abandoned_sent += 73168c2ecf20Sopenharmony_ci asoc->abandoned_sent[policy]; 73178c2ecf20Sopenharmony_ci } 73188c2ecf20Sopenharmony_ci } else { 73198c2ecf20Sopenharmony_ci params.sprstat_abandoned_unsent = 73208c2ecf20Sopenharmony_ci asoc->abandoned_unsent[__SCTP_PR_INDEX(policy)]; 73218c2ecf20Sopenharmony_ci params.sprstat_abandoned_sent = 73228c2ecf20Sopenharmony_ci asoc->abandoned_sent[__SCTP_PR_INDEX(policy)]; 73238c2ecf20Sopenharmony_ci } 73248c2ecf20Sopenharmony_ci 73258c2ecf20Sopenharmony_ci if (put_user(len, optlen)) { 73268c2ecf20Sopenharmony_ci retval = -EFAULT; 73278c2ecf20Sopenharmony_ci goto out; 73288c2ecf20Sopenharmony_ci } 73298c2ecf20Sopenharmony_ci 73308c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) { 73318c2ecf20Sopenharmony_ci retval = -EFAULT; 73328c2ecf20Sopenharmony_ci goto out; 73338c2ecf20Sopenharmony_ci } 73348c2ecf20Sopenharmony_ci 73358c2ecf20Sopenharmony_ci retval = 0; 73368c2ecf20Sopenharmony_ci 73378c2ecf20Sopenharmony_ciout: 73388c2ecf20Sopenharmony_ci return retval; 73398c2ecf20Sopenharmony_ci} 73408c2ecf20Sopenharmony_ci 73418c2ecf20Sopenharmony_cistatic int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len, 73428c2ecf20Sopenharmony_ci char __user *optval, 73438c2ecf20Sopenharmony_ci int __user *optlen) 73448c2ecf20Sopenharmony_ci{ 73458c2ecf20Sopenharmony_ci struct sctp_stream_out_ext *streamoute; 73468c2ecf20Sopenharmony_ci struct sctp_association *asoc; 73478c2ecf20Sopenharmony_ci struct sctp_prstatus params; 73488c2ecf20Sopenharmony_ci int retval = -EINVAL; 73498c2ecf20Sopenharmony_ci int policy; 73508c2ecf20Sopenharmony_ci 73518c2ecf20Sopenharmony_ci if (len < sizeof(params)) 73528c2ecf20Sopenharmony_ci goto out; 73538c2ecf20Sopenharmony_ci 73548c2ecf20Sopenharmony_ci len = sizeof(params); 73558c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) { 73568c2ecf20Sopenharmony_ci retval = -EFAULT; 73578c2ecf20Sopenharmony_ci goto out; 73588c2ecf20Sopenharmony_ci } 73598c2ecf20Sopenharmony_ci 73608c2ecf20Sopenharmony_ci policy = params.sprstat_policy; 73618c2ecf20Sopenharmony_ci if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) || 73628c2ecf20Sopenharmony_ci ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK))) 73638c2ecf20Sopenharmony_ci goto out; 73648c2ecf20Sopenharmony_ci 73658c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); 73668c2ecf20Sopenharmony_ci if (!asoc || params.sprstat_sid >= asoc->stream.outcnt) 73678c2ecf20Sopenharmony_ci goto out; 73688c2ecf20Sopenharmony_ci 73698c2ecf20Sopenharmony_ci streamoute = SCTP_SO(&asoc->stream, params.sprstat_sid)->ext; 73708c2ecf20Sopenharmony_ci if (!streamoute) { 73718c2ecf20Sopenharmony_ci /* Not allocated yet, means all stats are 0 */ 73728c2ecf20Sopenharmony_ci params.sprstat_abandoned_unsent = 0; 73738c2ecf20Sopenharmony_ci params.sprstat_abandoned_sent = 0; 73748c2ecf20Sopenharmony_ci retval = 0; 73758c2ecf20Sopenharmony_ci goto out; 73768c2ecf20Sopenharmony_ci } 73778c2ecf20Sopenharmony_ci 73788c2ecf20Sopenharmony_ci if (policy == SCTP_PR_SCTP_ALL) { 73798c2ecf20Sopenharmony_ci params.sprstat_abandoned_unsent = 0; 73808c2ecf20Sopenharmony_ci params.sprstat_abandoned_sent = 0; 73818c2ecf20Sopenharmony_ci for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { 73828c2ecf20Sopenharmony_ci params.sprstat_abandoned_unsent += 73838c2ecf20Sopenharmony_ci streamoute->abandoned_unsent[policy]; 73848c2ecf20Sopenharmony_ci params.sprstat_abandoned_sent += 73858c2ecf20Sopenharmony_ci streamoute->abandoned_sent[policy]; 73868c2ecf20Sopenharmony_ci } 73878c2ecf20Sopenharmony_ci } else { 73888c2ecf20Sopenharmony_ci params.sprstat_abandoned_unsent = 73898c2ecf20Sopenharmony_ci streamoute->abandoned_unsent[__SCTP_PR_INDEX(policy)]; 73908c2ecf20Sopenharmony_ci params.sprstat_abandoned_sent = 73918c2ecf20Sopenharmony_ci streamoute->abandoned_sent[__SCTP_PR_INDEX(policy)]; 73928c2ecf20Sopenharmony_ci } 73938c2ecf20Sopenharmony_ci 73948c2ecf20Sopenharmony_ci if (put_user(len, optlen) || copy_to_user(optval, ¶ms, len)) { 73958c2ecf20Sopenharmony_ci retval = -EFAULT; 73968c2ecf20Sopenharmony_ci goto out; 73978c2ecf20Sopenharmony_ci } 73988c2ecf20Sopenharmony_ci 73998c2ecf20Sopenharmony_ci retval = 0; 74008c2ecf20Sopenharmony_ci 74018c2ecf20Sopenharmony_ciout: 74028c2ecf20Sopenharmony_ci return retval; 74038c2ecf20Sopenharmony_ci} 74048c2ecf20Sopenharmony_ci 74058c2ecf20Sopenharmony_cistatic int sctp_getsockopt_reconfig_supported(struct sock *sk, int len, 74068c2ecf20Sopenharmony_ci char __user *optval, 74078c2ecf20Sopenharmony_ci int __user *optlen) 74088c2ecf20Sopenharmony_ci{ 74098c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 74108c2ecf20Sopenharmony_ci struct sctp_association *asoc; 74118c2ecf20Sopenharmony_ci int retval = -EFAULT; 74128c2ecf20Sopenharmony_ci 74138c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 74148c2ecf20Sopenharmony_ci retval = -EINVAL; 74158c2ecf20Sopenharmony_ci goto out; 74168c2ecf20Sopenharmony_ci } 74178c2ecf20Sopenharmony_ci 74188c2ecf20Sopenharmony_ci len = sizeof(params); 74198c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 74208c2ecf20Sopenharmony_ci goto out; 74218c2ecf20Sopenharmony_ci 74228c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 74238c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 74248c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 74258c2ecf20Sopenharmony_ci retval = -EINVAL; 74268c2ecf20Sopenharmony_ci goto out; 74278c2ecf20Sopenharmony_ci } 74288c2ecf20Sopenharmony_ci 74298c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->peer.reconf_capable 74308c2ecf20Sopenharmony_ci : sctp_sk(sk)->ep->reconf_enable; 74318c2ecf20Sopenharmony_ci 74328c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 74338c2ecf20Sopenharmony_ci goto out; 74348c2ecf20Sopenharmony_ci 74358c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 74368c2ecf20Sopenharmony_ci goto out; 74378c2ecf20Sopenharmony_ci 74388c2ecf20Sopenharmony_ci retval = 0; 74398c2ecf20Sopenharmony_ci 74408c2ecf20Sopenharmony_ciout: 74418c2ecf20Sopenharmony_ci return retval; 74428c2ecf20Sopenharmony_ci} 74438c2ecf20Sopenharmony_ci 74448c2ecf20Sopenharmony_cistatic int sctp_getsockopt_enable_strreset(struct sock *sk, int len, 74458c2ecf20Sopenharmony_ci char __user *optval, 74468c2ecf20Sopenharmony_ci int __user *optlen) 74478c2ecf20Sopenharmony_ci{ 74488c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 74498c2ecf20Sopenharmony_ci struct sctp_association *asoc; 74508c2ecf20Sopenharmony_ci int retval = -EFAULT; 74518c2ecf20Sopenharmony_ci 74528c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 74538c2ecf20Sopenharmony_ci retval = -EINVAL; 74548c2ecf20Sopenharmony_ci goto out; 74558c2ecf20Sopenharmony_ci } 74568c2ecf20Sopenharmony_ci 74578c2ecf20Sopenharmony_ci len = sizeof(params); 74588c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 74598c2ecf20Sopenharmony_ci goto out; 74608c2ecf20Sopenharmony_ci 74618c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 74628c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 74638c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 74648c2ecf20Sopenharmony_ci retval = -EINVAL; 74658c2ecf20Sopenharmony_ci goto out; 74668c2ecf20Sopenharmony_ci } 74678c2ecf20Sopenharmony_ci 74688c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->strreset_enable 74698c2ecf20Sopenharmony_ci : sctp_sk(sk)->ep->strreset_enable; 74708c2ecf20Sopenharmony_ci 74718c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 74728c2ecf20Sopenharmony_ci goto out; 74738c2ecf20Sopenharmony_ci 74748c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 74758c2ecf20Sopenharmony_ci goto out; 74768c2ecf20Sopenharmony_ci 74778c2ecf20Sopenharmony_ci retval = 0; 74788c2ecf20Sopenharmony_ci 74798c2ecf20Sopenharmony_ciout: 74808c2ecf20Sopenharmony_ci return retval; 74818c2ecf20Sopenharmony_ci} 74828c2ecf20Sopenharmony_ci 74838c2ecf20Sopenharmony_cistatic int sctp_getsockopt_scheduler(struct sock *sk, int len, 74848c2ecf20Sopenharmony_ci char __user *optval, 74858c2ecf20Sopenharmony_ci int __user *optlen) 74868c2ecf20Sopenharmony_ci{ 74878c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 74888c2ecf20Sopenharmony_ci struct sctp_association *asoc; 74898c2ecf20Sopenharmony_ci int retval = -EFAULT; 74908c2ecf20Sopenharmony_ci 74918c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 74928c2ecf20Sopenharmony_ci retval = -EINVAL; 74938c2ecf20Sopenharmony_ci goto out; 74948c2ecf20Sopenharmony_ci } 74958c2ecf20Sopenharmony_ci 74968c2ecf20Sopenharmony_ci len = sizeof(params); 74978c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 74988c2ecf20Sopenharmony_ci goto out; 74998c2ecf20Sopenharmony_ci 75008c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 75018c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 75028c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 75038c2ecf20Sopenharmony_ci retval = -EINVAL; 75048c2ecf20Sopenharmony_ci goto out; 75058c2ecf20Sopenharmony_ci } 75068c2ecf20Sopenharmony_ci 75078c2ecf20Sopenharmony_ci params.assoc_value = asoc ? sctp_sched_get_sched(asoc) 75088c2ecf20Sopenharmony_ci : sctp_sk(sk)->default_ss; 75098c2ecf20Sopenharmony_ci 75108c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 75118c2ecf20Sopenharmony_ci goto out; 75128c2ecf20Sopenharmony_ci 75138c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 75148c2ecf20Sopenharmony_ci goto out; 75158c2ecf20Sopenharmony_ci 75168c2ecf20Sopenharmony_ci retval = 0; 75178c2ecf20Sopenharmony_ci 75188c2ecf20Sopenharmony_ciout: 75198c2ecf20Sopenharmony_ci return retval; 75208c2ecf20Sopenharmony_ci} 75218c2ecf20Sopenharmony_ci 75228c2ecf20Sopenharmony_cistatic int sctp_getsockopt_scheduler_value(struct sock *sk, int len, 75238c2ecf20Sopenharmony_ci char __user *optval, 75248c2ecf20Sopenharmony_ci int __user *optlen) 75258c2ecf20Sopenharmony_ci{ 75268c2ecf20Sopenharmony_ci struct sctp_stream_value params; 75278c2ecf20Sopenharmony_ci struct sctp_association *asoc; 75288c2ecf20Sopenharmony_ci int retval = -EFAULT; 75298c2ecf20Sopenharmony_ci 75308c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 75318c2ecf20Sopenharmony_ci retval = -EINVAL; 75328c2ecf20Sopenharmony_ci goto out; 75338c2ecf20Sopenharmony_ci } 75348c2ecf20Sopenharmony_ci 75358c2ecf20Sopenharmony_ci len = sizeof(params); 75368c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 75378c2ecf20Sopenharmony_ci goto out; 75388c2ecf20Sopenharmony_ci 75398c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 75408c2ecf20Sopenharmony_ci if (!asoc) { 75418c2ecf20Sopenharmony_ci retval = -EINVAL; 75428c2ecf20Sopenharmony_ci goto out; 75438c2ecf20Sopenharmony_ci } 75448c2ecf20Sopenharmony_ci 75458c2ecf20Sopenharmony_ci retval = sctp_sched_get_value(asoc, params.stream_id, 75468c2ecf20Sopenharmony_ci ¶ms.stream_value); 75478c2ecf20Sopenharmony_ci if (retval) 75488c2ecf20Sopenharmony_ci goto out; 75498c2ecf20Sopenharmony_ci 75508c2ecf20Sopenharmony_ci if (put_user(len, optlen)) { 75518c2ecf20Sopenharmony_ci retval = -EFAULT; 75528c2ecf20Sopenharmony_ci goto out; 75538c2ecf20Sopenharmony_ci } 75548c2ecf20Sopenharmony_ci 75558c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) { 75568c2ecf20Sopenharmony_ci retval = -EFAULT; 75578c2ecf20Sopenharmony_ci goto out; 75588c2ecf20Sopenharmony_ci } 75598c2ecf20Sopenharmony_ci 75608c2ecf20Sopenharmony_ciout: 75618c2ecf20Sopenharmony_ci return retval; 75628c2ecf20Sopenharmony_ci} 75638c2ecf20Sopenharmony_ci 75648c2ecf20Sopenharmony_cistatic int sctp_getsockopt_interleaving_supported(struct sock *sk, int len, 75658c2ecf20Sopenharmony_ci char __user *optval, 75668c2ecf20Sopenharmony_ci int __user *optlen) 75678c2ecf20Sopenharmony_ci{ 75688c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 75698c2ecf20Sopenharmony_ci struct sctp_association *asoc; 75708c2ecf20Sopenharmony_ci int retval = -EFAULT; 75718c2ecf20Sopenharmony_ci 75728c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 75738c2ecf20Sopenharmony_ci retval = -EINVAL; 75748c2ecf20Sopenharmony_ci goto out; 75758c2ecf20Sopenharmony_ci } 75768c2ecf20Sopenharmony_ci 75778c2ecf20Sopenharmony_ci len = sizeof(params); 75788c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 75798c2ecf20Sopenharmony_ci goto out; 75808c2ecf20Sopenharmony_ci 75818c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 75828c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 75838c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 75848c2ecf20Sopenharmony_ci retval = -EINVAL; 75858c2ecf20Sopenharmony_ci goto out; 75868c2ecf20Sopenharmony_ci } 75878c2ecf20Sopenharmony_ci 75888c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->peer.intl_capable 75898c2ecf20Sopenharmony_ci : sctp_sk(sk)->ep->intl_enable; 75908c2ecf20Sopenharmony_ci 75918c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 75928c2ecf20Sopenharmony_ci goto out; 75938c2ecf20Sopenharmony_ci 75948c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 75958c2ecf20Sopenharmony_ci goto out; 75968c2ecf20Sopenharmony_ci 75978c2ecf20Sopenharmony_ci retval = 0; 75988c2ecf20Sopenharmony_ci 75998c2ecf20Sopenharmony_ciout: 76008c2ecf20Sopenharmony_ci return retval; 76018c2ecf20Sopenharmony_ci} 76028c2ecf20Sopenharmony_ci 76038c2ecf20Sopenharmony_cistatic int sctp_getsockopt_reuse_port(struct sock *sk, int len, 76048c2ecf20Sopenharmony_ci char __user *optval, 76058c2ecf20Sopenharmony_ci int __user *optlen) 76068c2ecf20Sopenharmony_ci{ 76078c2ecf20Sopenharmony_ci int val; 76088c2ecf20Sopenharmony_ci 76098c2ecf20Sopenharmony_ci if (len < sizeof(int)) 76108c2ecf20Sopenharmony_ci return -EINVAL; 76118c2ecf20Sopenharmony_ci 76128c2ecf20Sopenharmony_ci len = sizeof(int); 76138c2ecf20Sopenharmony_ci val = sctp_sk(sk)->reuse; 76148c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 76158c2ecf20Sopenharmony_ci return -EFAULT; 76168c2ecf20Sopenharmony_ci 76178c2ecf20Sopenharmony_ci if (copy_to_user(optval, &val, len)) 76188c2ecf20Sopenharmony_ci return -EFAULT; 76198c2ecf20Sopenharmony_ci 76208c2ecf20Sopenharmony_ci return 0; 76218c2ecf20Sopenharmony_ci} 76228c2ecf20Sopenharmony_ci 76238c2ecf20Sopenharmony_cistatic int sctp_getsockopt_event(struct sock *sk, int len, char __user *optval, 76248c2ecf20Sopenharmony_ci int __user *optlen) 76258c2ecf20Sopenharmony_ci{ 76268c2ecf20Sopenharmony_ci struct sctp_association *asoc; 76278c2ecf20Sopenharmony_ci struct sctp_event param; 76288c2ecf20Sopenharmony_ci __u16 subscribe; 76298c2ecf20Sopenharmony_ci 76308c2ecf20Sopenharmony_ci if (len < sizeof(param)) 76318c2ecf20Sopenharmony_ci return -EINVAL; 76328c2ecf20Sopenharmony_ci 76338c2ecf20Sopenharmony_ci len = sizeof(param); 76348c2ecf20Sopenharmony_ci if (copy_from_user(¶m, optval, len)) 76358c2ecf20Sopenharmony_ci return -EFAULT; 76368c2ecf20Sopenharmony_ci 76378c2ecf20Sopenharmony_ci if (param.se_type < SCTP_SN_TYPE_BASE || 76388c2ecf20Sopenharmony_ci param.se_type > SCTP_SN_TYPE_MAX) 76398c2ecf20Sopenharmony_ci return -EINVAL; 76408c2ecf20Sopenharmony_ci 76418c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, param.se_assoc_id); 76428c2ecf20Sopenharmony_ci if (!asoc && param.se_assoc_id != SCTP_FUTURE_ASSOC && 76438c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) 76448c2ecf20Sopenharmony_ci return -EINVAL; 76458c2ecf20Sopenharmony_ci 76468c2ecf20Sopenharmony_ci subscribe = asoc ? asoc->subscribe : sctp_sk(sk)->subscribe; 76478c2ecf20Sopenharmony_ci param.se_on = sctp_ulpevent_type_enabled(subscribe, param.se_type); 76488c2ecf20Sopenharmony_ci 76498c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 76508c2ecf20Sopenharmony_ci return -EFAULT; 76518c2ecf20Sopenharmony_ci 76528c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶m, len)) 76538c2ecf20Sopenharmony_ci return -EFAULT; 76548c2ecf20Sopenharmony_ci 76558c2ecf20Sopenharmony_ci return 0; 76568c2ecf20Sopenharmony_ci} 76578c2ecf20Sopenharmony_ci 76588c2ecf20Sopenharmony_cistatic int sctp_getsockopt_asconf_supported(struct sock *sk, int len, 76598c2ecf20Sopenharmony_ci char __user *optval, 76608c2ecf20Sopenharmony_ci int __user *optlen) 76618c2ecf20Sopenharmony_ci{ 76628c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 76638c2ecf20Sopenharmony_ci struct sctp_association *asoc; 76648c2ecf20Sopenharmony_ci int retval = -EFAULT; 76658c2ecf20Sopenharmony_ci 76668c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 76678c2ecf20Sopenharmony_ci retval = -EINVAL; 76688c2ecf20Sopenharmony_ci goto out; 76698c2ecf20Sopenharmony_ci } 76708c2ecf20Sopenharmony_ci 76718c2ecf20Sopenharmony_ci len = sizeof(params); 76728c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 76738c2ecf20Sopenharmony_ci goto out; 76748c2ecf20Sopenharmony_ci 76758c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 76768c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 76778c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 76788c2ecf20Sopenharmony_ci retval = -EINVAL; 76798c2ecf20Sopenharmony_ci goto out; 76808c2ecf20Sopenharmony_ci } 76818c2ecf20Sopenharmony_ci 76828c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->peer.asconf_capable 76838c2ecf20Sopenharmony_ci : sctp_sk(sk)->ep->asconf_enable; 76848c2ecf20Sopenharmony_ci 76858c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 76868c2ecf20Sopenharmony_ci goto out; 76878c2ecf20Sopenharmony_ci 76888c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 76898c2ecf20Sopenharmony_ci goto out; 76908c2ecf20Sopenharmony_ci 76918c2ecf20Sopenharmony_ci retval = 0; 76928c2ecf20Sopenharmony_ci 76938c2ecf20Sopenharmony_ciout: 76948c2ecf20Sopenharmony_ci return retval; 76958c2ecf20Sopenharmony_ci} 76968c2ecf20Sopenharmony_ci 76978c2ecf20Sopenharmony_cistatic int sctp_getsockopt_auth_supported(struct sock *sk, int len, 76988c2ecf20Sopenharmony_ci char __user *optval, 76998c2ecf20Sopenharmony_ci int __user *optlen) 77008c2ecf20Sopenharmony_ci{ 77018c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 77028c2ecf20Sopenharmony_ci struct sctp_association *asoc; 77038c2ecf20Sopenharmony_ci int retval = -EFAULT; 77048c2ecf20Sopenharmony_ci 77058c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 77068c2ecf20Sopenharmony_ci retval = -EINVAL; 77078c2ecf20Sopenharmony_ci goto out; 77088c2ecf20Sopenharmony_ci } 77098c2ecf20Sopenharmony_ci 77108c2ecf20Sopenharmony_ci len = sizeof(params); 77118c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 77128c2ecf20Sopenharmony_ci goto out; 77138c2ecf20Sopenharmony_ci 77148c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 77158c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 77168c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 77178c2ecf20Sopenharmony_ci retval = -EINVAL; 77188c2ecf20Sopenharmony_ci goto out; 77198c2ecf20Sopenharmony_ci } 77208c2ecf20Sopenharmony_ci 77218c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->peer.auth_capable 77228c2ecf20Sopenharmony_ci : sctp_sk(sk)->ep->auth_enable; 77238c2ecf20Sopenharmony_ci 77248c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 77258c2ecf20Sopenharmony_ci goto out; 77268c2ecf20Sopenharmony_ci 77278c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 77288c2ecf20Sopenharmony_ci goto out; 77298c2ecf20Sopenharmony_ci 77308c2ecf20Sopenharmony_ci retval = 0; 77318c2ecf20Sopenharmony_ci 77328c2ecf20Sopenharmony_ciout: 77338c2ecf20Sopenharmony_ci return retval; 77348c2ecf20Sopenharmony_ci} 77358c2ecf20Sopenharmony_ci 77368c2ecf20Sopenharmony_cistatic int sctp_getsockopt_ecn_supported(struct sock *sk, int len, 77378c2ecf20Sopenharmony_ci char __user *optval, 77388c2ecf20Sopenharmony_ci int __user *optlen) 77398c2ecf20Sopenharmony_ci{ 77408c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 77418c2ecf20Sopenharmony_ci struct sctp_association *asoc; 77428c2ecf20Sopenharmony_ci int retval = -EFAULT; 77438c2ecf20Sopenharmony_ci 77448c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 77458c2ecf20Sopenharmony_ci retval = -EINVAL; 77468c2ecf20Sopenharmony_ci goto out; 77478c2ecf20Sopenharmony_ci } 77488c2ecf20Sopenharmony_ci 77498c2ecf20Sopenharmony_ci len = sizeof(params); 77508c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 77518c2ecf20Sopenharmony_ci goto out; 77528c2ecf20Sopenharmony_ci 77538c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 77548c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 77558c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 77568c2ecf20Sopenharmony_ci retval = -EINVAL; 77578c2ecf20Sopenharmony_ci goto out; 77588c2ecf20Sopenharmony_ci } 77598c2ecf20Sopenharmony_ci 77608c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->peer.ecn_capable 77618c2ecf20Sopenharmony_ci : sctp_sk(sk)->ep->ecn_enable; 77628c2ecf20Sopenharmony_ci 77638c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 77648c2ecf20Sopenharmony_ci goto out; 77658c2ecf20Sopenharmony_ci 77668c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 77678c2ecf20Sopenharmony_ci goto out; 77688c2ecf20Sopenharmony_ci 77698c2ecf20Sopenharmony_ci retval = 0; 77708c2ecf20Sopenharmony_ci 77718c2ecf20Sopenharmony_ciout: 77728c2ecf20Sopenharmony_ci return retval; 77738c2ecf20Sopenharmony_ci} 77748c2ecf20Sopenharmony_ci 77758c2ecf20Sopenharmony_cistatic int sctp_getsockopt_pf_expose(struct sock *sk, int len, 77768c2ecf20Sopenharmony_ci char __user *optval, 77778c2ecf20Sopenharmony_ci int __user *optlen) 77788c2ecf20Sopenharmony_ci{ 77798c2ecf20Sopenharmony_ci struct sctp_assoc_value params; 77808c2ecf20Sopenharmony_ci struct sctp_association *asoc; 77818c2ecf20Sopenharmony_ci int retval = -EFAULT; 77828c2ecf20Sopenharmony_ci 77838c2ecf20Sopenharmony_ci if (len < sizeof(params)) { 77848c2ecf20Sopenharmony_ci retval = -EINVAL; 77858c2ecf20Sopenharmony_ci goto out; 77868c2ecf20Sopenharmony_ci } 77878c2ecf20Sopenharmony_ci 77888c2ecf20Sopenharmony_ci len = sizeof(params); 77898c2ecf20Sopenharmony_ci if (copy_from_user(¶ms, optval, len)) 77908c2ecf20Sopenharmony_ci goto out; 77918c2ecf20Sopenharmony_ci 77928c2ecf20Sopenharmony_ci asoc = sctp_id2assoc(sk, params.assoc_id); 77938c2ecf20Sopenharmony_ci if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 77948c2ecf20Sopenharmony_ci sctp_style(sk, UDP)) { 77958c2ecf20Sopenharmony_ci retval = -EINVAL; 77968c2ecf20Sopenharmony_ci goto out; 77978c2ecf20Sopenharmony_ci } 77988c2ecf20Sopenharmony_ci 77998c2ecf20Sopenharmony_ci params.assoc_value = asoc ? asoc->pf_expose 78008c2ecf20Sopenharmony_ci : sctp_sk(sk)->pf_expose; 78018c2ecf20Sopenharmony_ci 78028c2ecf20Sopenharmony_ci if (put_user(len, optlen)) 78038c2ecf20Sopenharmony_ci goto out; 78048c2ecf20Sopenharmony_ci 78058c2ecf20Sopenharmony_ci if (copy_to_user(optval, ¶ms, len)) 78068c2ecf20Sopenharmony_ci goto out; 78078c2ecf20Sopenharmony_ci 78088c2ecf20Sopenharmony_ci retval = 0; 78098c2ecf20Sopenharmony_ci 78108c2ecf20Sopenharmony_ciout: 78118c2ecf20Sopenharmony_ci return retval; 78128c2ecf20Sopenharmony_ci} 78138c2ecf20Sopenharmony_ci 78148c2ecf20Sopenharmony_cistatic int sctp_getsockopt(struct sock *sk, int level, int optname, 78158c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 78168c2ecf20Sopenharmony_ci{ 78178c2ecf20Sopenharmony_ci int retval = 0; 78188c2ecf20Sopenharmony_ci int len; 78198c2ecf20Sopenharmony_ci 78208c2ecf20Sopenharmony_ci pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 78218c2ecf20Sopenharmony_ci 78228c2ecf20Sopenharmony_ci /* I can hardly begin to describe how wrong this is. This is 78238c2ecf20Sopenharmony_ci * so broken as to be worse than useless. The API draft 78248c2ecf20Sopenharmony_ci * REALLY is NOT helpful here... I am not convinced that the 78258c2ecf20Sopenharmony_ci * semantics of getsockopt() with a level OTHER THAN SOL_SCTP 78268c2ecf20Sopenharmony_ci * are at all well-founded. 78278c2ecf20Sopenharmony_ci */ 78288c2ecf20Sopenharmony_ci if (level != SOL_SCTP) { 78298c2ecf20Sopenharmony_ci struct sctp_af *af = sctp_sk(sk)->pf->af; 78308c2ecf20Sopenharmony_ci 78318c2ecf20Sopenharmony_ci retval = af->getsockopt(sk, level, optname, optval, optlen); 78328c2ecf20Sopenharmony_ci return retval; 78338c2ecf20Sopenharmony_ci } 78348c2ecf20Sopenharmony_ci 78358c2ecf20Sopenharmony_ci if (get_user(len, optlen)) 78368c2ecf20Sopenharmony_ci return -EFAULT; 78378c2ecf20Sopenharmony_ci 78388c2ecf20Sopenharmony_ci if (len < 0) 78398c2ecf20Sopenharmony_ci return -EINVAL; 78408c2ecf20Sopenharmony_ci 78418c2ecf20Sopenharmony_ci lock_sock(sk); 78428c2ecf20Sopenharmony_ci 78438c2ecf20Sopenharmony_ci switch (optname) { 78448c2ecf20Sopenharmony_ci case SCTP_STATUS: 78458c2ecf20Sopenharmony_ci retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); 78468c2ecf20Sopenharmony_ci break; 78478c2ecf20Sopenharmony_ci case SCTP_DISABLE_FRAGMENTS: 78488c2ecf20Sopenharmony_ci retval = sctp_getsockopt_disable_fragments(sk, len, optval, 78498c2ecf20Sopenharmony_ci optlen); 78508c2ecf20Sopenharmony_ci break; 78518c2ecf20Sopenharmony_ci case SCTP_EVENTS: 78528c2ecf20Sopenharmony_ci retval = sctp_getsockopt_events(sk, len, optval, optlen); 78538c2ecf20Sopenharmony_ci break; 78548c2ecf20Sopenharmony_ci case SCTP_AUTOCLOSE: 78558c2ecf20Sopenharmony_ci retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); 78568c2ecf20Sopenharmony_ci break; 78578c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_PEELOFF: 78588c2ecf20Sopenharmony_ci retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); 78598c2ecf20Sopenharmony_ci break; 78608c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_PEELOFF_FLAGS: 78618c2ecf20Sopenharmony_ci retval = sctp_getsockopt_peeloff_flags(sk, len, optval, optlen); 78628c2ecf20Sopenharmony_ci break; 78638c2ecf20Sopenharmony_ci case SCTP_PEER_ADDR_PARAMS: 78648c2ecf20Sopenharmony_ci retval = sctp_getsockopt_peer_addr_params(sk, len, optval, 78658c2ecf20Sopenharmony_ci optlen); 78668c2ecf20Sopenharmony_ci break; 78678c2ecf20Sopenharmony_ci case SCTP_DELAYED_SACK: 78688c2ecf20Sopenharmony_ci retval = sctp_getsockopt_delayed_ack(sk, len, optval, 78698c2ecf20Sopenharmony_ci optlen); 78708c2ecf20Sopenharmony_ci break; 78718c2ecf20Sopenharmony_ci case SCTP_INITMSG: 78728c2ecf20Sopenharmony_ci retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); 78738c2ecf20Sopenharmony_ci break; 78748c2ecf20Sopenharmony_ci case SCTP_GET_PEER_ADDRS: 78758c2ecf20Sopenharmony_ci retval = sctp_getsockopt_peer_addrs(sk, len, optval, 78768c2ecf20Sopenharmony_ci optlen); 78778c2ecf20Sopenharmony_ci break; 78788c2ecf20Sopenharmony_ci case SCTP_GET_LOCAL_ADDRS: 78798c2ecf20Sopenharmony_ci retval = sctp_getsockopt_local_addrs(sk, len, optval, 78808c2ecf20Sopenharmony_ci optlen); 78818c2ecf20Sopenharmony_ci break; 78828c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_CONNECTX3: 78838c2ecf20Sopenharmony_ci retval = sctp_getsockopt_connectx3(sk, len, optval, optlen); 78848c2ecf20Sopenharmony_ci break; 78858c2ecf20Sopenharmony_ci case SCTP_DEFAULT_SEND_PARAM: 78868c2ecf20Sopenharmony_ci retval = sctp_getsockopt_default_send_param(sk, len, 78878c2ecf20Sopenharmony_ci optval, optlen); 78888c2ecf20Sopenharmony_ci break; 78898c2ecf20Sopenharmony_ci case SCTP_DEFAULT_SNDINFO: 78908c2ecf20Sopenharmony_ci retval = sctp_getsockopt_default_sndinfo(sk, len, 78918c2ecf20Sopenharmony_ci optval, optlen); 78928c2ecf20Sopenharmony_ci break; 78938c2ecf20Sopenharmony_ci case SCTP_PRIMARY_ADDR: 78948c2ecf20Sopenharmony_ci retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); 78958c2ecf20Sopenharmony_ci break; 78968c2ecf20Sopenharmony_ci case SCTP_NODELAY: 78978c2ecf20Sopenharmony_ci retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); 78988c2ecf20Sopenharmony_ci break; 78998c2ecf20Sopenharmony_ci case SCTP_RTOINFO: 79008c2ecf20Sopenharmony_ci retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen); 79018c2ecf20Sopenharmony_ci break; 79028c2ecf20Sopenharmony_ci case SCTP_ASSOCINFO: 79038c2ecf20Sopenharmony_ci retval = sctp_getsockopt_associnfo(sk, len, optval, optlen); 79048c2ecf20Sopenharmony_ci break; 79058c2ecf20Sopenharmony_ci case SCTP_I_WANT_MAPPED_V4_ADDR: 79068c2ecf20Sopenharmony_ci retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); 79078c2ecf20Sopenharmony_ci break; 79088c2ecf20Sopenharmony_ci case SCTP_MAXSEG: 79098c2ecf20Sopenharmony_ci retval = sctp_getsockopt_maxseg(sk, len, optval, optlen); 79108c2ecf20Sopenharmony_ci break; 79118c2ecf20Sopenharmony_ci case SCTP_GET_PEER_ADDR_INFO: 79128c2ecf20Sopenharmony_ci retval = sctp_getsockopt_peer_addr_info(sk, len, optval, 79138c2ecf20Sopenharmony_ci optlen); 79148c2ecf20Sopenharmony_ci break; 79158c2ecf20Sopenharmony_ci case SCTP_ADAPTATION_LAYER: 79168c2ecf20Sopenharmony_ci retval = sctp_getsockopt_adaptation_layer(sk, len, optval, 79178c2ecf20Sopenharmony_ci optlen); 79188c2ecf20Sopenharmony_ci break; 79198c2ecf20Sopenharmony_ci case SCTP_CONTEXT: 79208c2ecf20Sopenharmony_ci retval = sctp_getsockopt_context(sk, len, optval, optlen); 79218c2ecf20Sopenharmony_ci break; 79228c2ecf20Sopenharmony_ci case SCTP_FRAGMENT_INTERLEAVE: 79238c2ecf20Sopenharmony_ci retval = sctp_getsockopt_fragment_interleave(sk, len, optval, 79248c2ecf20Sopenharmony_ci optlen); 79258c2ecf20Sopenharmony_ci break; 79268c2ecf20Sopenharmony_ci case SCTP_PARTIAL_DELIVERY_POINT: 79278c2ecf20Sopenharmony_ci retval = sctp_getsockopt_partial_delivery_point(sk, len, optval, 79288c2ecf20Sopenharmony_ci optlen); 79298c2ecf20Sopenharmony_ci break; 79308c2ecf20Sopenharmony_ci case SCTP_MAX_BURST: 79318c2ecf20Sopenharmony_ci retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); 79328c2ecf20Sopenharmony_ci break; 79338c2ecf20Sopenharmony_ci case SCTP_AUTH_KEY: 79348c2ecf20Sopenharmony_ci case SCTP_AUTH_CHUNK: 79358c2ecf20Sopenharmony_ci case SCTP_AUTH_DELETE_KEY: 79368c2ecf20Sopenharmony_ci case SCTP_AUTH_DEACTIVATE_KEY: 79378c2ecf20Sopenharmony_ci retval = -EOPNOTSUPP; 79388c2ecf20Sopenharmony_ci break; 79398c2ecf20Sopenharmony_ci case SCTP_HMAC_IDENT: 79408c2ecf20Sopenharmony_ci retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen); 79418c2ecf20Sopenharmony_ci break; 79428c2ecf20Sopenharmony_ci case SCTP_AUTH_ACTIVE_KEY: 79438c2ecf20Sopenharmony_ci retval = sctp_getsockopt_active_key(sk, len, optval, optlen); 79448c2ecf20Sopenharmony_ci break; 79458c2ecf20Sopenharmony_ci case SCTP_PEER_AUTH_CHUNKS: 79468c2ecf20Sopenharmony_ci retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval, 79478c2ecf20Sopenharmony_ci optlen); 79488c2ecf20Sopenharmony_ci break; 79498c2ecf20Sopenharmony_ci case SCTP_LOCAL_AUTH_CHUNKS: 79508c2ecf20Sopenharmony_ci retval = sctp_getsockopt_local_auth_chunks(sk, len, optval, 79518c2ecf20Sopenharmony_ci optlen); 79528c2ecf20Sopenharmony_ci break; 79538c2ecf20Sopenharmony_ci case SCTP_GET_ASSOC_NUMBER: 79548c2ecf20Sopenharmony_ci retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); 79558c2ecf20Sopenharmony_ci break; 79568c2ecf20Sopenharmony_ci case SCTP_GET_ASSOC_ID_LIST: 79578c2ecf20Sopenharmony_ci retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); 79588c2ecf20Sopenharmony_ci break; 79598c2ecf20Sopenharmony_ci case SCTP_AUTO_ASCONF: 79608c2ecf20Sopenharmony_ci retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); 79618c2ecf20Sopenharmony_ci break; 79628c2ecf20Sopenharmony_ci case SCTP_PEER_ADDR_THLDS: 79638c2ecf20Sopenharmony_ci retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, 79648c2ecf20Sopenharmony_ci optlen, false); 79658c2ecf20Sopenharmony_ci break; 79668c2ecf20Sopenharmony_ci case SCTP_PEER_ADDR_THLDS_V2: 79678c2ecf20Sopenharmony_ci retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, 79688c2ecf20Sopenharmony_ci optlen, true); 79698c2ecf20Sopenharmony_ci break; 79708c2ecf20Sopenharmony_ci case SCTP_GET_ASSOC_STATS: 79718c2ecf20Sopenharmony_ci retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); 79728c2ecf20Sopenharmony_ci break; 79738c2ecf20Sopenharmony_ci case SCTP_RECVRCVINFO: 79748c2ecf20Sopenharmony_ci retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); 79758c2ecf20Sopenharmony_ci break; 79768c2ecf20Sopenharmony_ci case SCTP_RECVNXTINFO: 79778c2ecf20Sopenharmony_ci retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen); 79788c2ecf20Sopenharmony_ci break; 79798c2ecf20Sopenharmony_ci case SCTP_PR_SUPPORTED: 79808c2ecf20Sopenharmony_ci retval = sctp_getsockopt_pr_supported(sk, len, optval, optlen); 79818c2ecf20Sopenharmony_ci break; 79828c2ecf20Sopenharmony_ci case SCTP_DEFAULT_PRINFO: 79838c2ecf20Sopenharmony_ci retval = sctp_getsockopt_default_prinfo(sk, len, optval, 79848c2ecf20Sopenharmony_ci optlen); 79858c2ecf20Sopenharmony_ci break; 79868c2ecf20Sopenharmony_ci case SCTP_PR_ASSOC_STATUS: 79878c2ecf20Sopenharmony_ci retval = sctp_getsockopt_pr_assocstatus(sk, len, optval, 79888c2ecf20Sopenharmony_ci optlen); 79898c2ecf20Sopenharmony_ci break; 79908c2ecf20Sopenharmony_ci case SCTP_PR_STREAM_STATUS: 79918c2ecf20Sopenharmony_ci retval = sctp_getsockopt_pr_streamstatus(sk, len, optval, 79928c2ecf20Sopenharmony_ci optlen); 79938c2ecf20Sopenharmony_ci break; 79948c2ecf20Sopenharmony_ci case SCTP_RECONFIG_SUPPORTED: 79958c2ecf20Sopenharmony_ci retval = sctp_getsockopt_reconfig_supported(sk, len, optval, 79968c2ecf20Sopenharmony_ci optlen); 79978c2ecf20Sopenharmony_ci break; 79988c2ecf20Sopenharmony_ci case SCTP_ENABLE_STREAM_RESET: 79998c2ecf20Sopenharmony_ci retval = sctp_getsockopt_enable_strreset(sk, len, optval, 80008c2ecf20Sopenharmony_ci optlen); 80018c2ecf20Sopenharmony_ci break; 80028c2ecf20Sopenharmony_ci case SCTP_STREAM_SCHEDULER: 80038c2ecf20Sopenharmony_ci retval = sctp_getsockopt_scheduler(sk, len, optval, 80048c2ecf20Sopenharmony_ci optlen); 80058c2ecf20Sopenharmony_ci break; 80068c2ecf20Sopenharmony_ci case SCTP_STREAM_SCHEDULER_VALUE: 80078c2ecf20Sopenharmony_ci retval = sctp_getsockopt_scheduler_value(sk, len, optval, 80088c2ecf20Sopenharmony_ci optlen); 80098c2ecf20Sopenharmony_ci break; 80108c2ecf20Sopenharmony_ci case SCTP_INTERLEAVING_SUPPORTED: 80118c2ecf20Sopenharmony_ci retval = sctp_getsockopt_interleaving_supported(sk, len, optval, 80128c2ecf20Sopenharmony_ci optlen); 80138c2ecf20Sopenharmony_ci break; 80148c2ecf20Sopenharmony_ci case SCTP_REUSE_PORT: 80158c2ecf20Sopenharmony_ci retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen); 80168c2ecf20Sopenharmony_ci break; 80178c2ecf20Sopenharmony_ci case SCTP_EVENT: 80188c2ecf20Sopenharmony_ci retval = sctp_getsockopt_event(sk, len, optval, optlen); 80198c2ecf20Sopenharmony_ci break; 80208c2ecf20Sopenharmony_ci case SCTP_ASCONF_SUPPORTED: 80218c2ecf20Sopenharmony_ci retval = sctp_getsockopt_asconf_supported(sk, len, optval, 80228c2ecf20Sopenharmony_ci optlen); 80238c2ecf20Sopenharmony_ci break; 80248c2ecf20Sopenharmony_ci case SCTP_AUTH_SUPPORTED: 80258c2ecf20Sopenharmony_ci retval = sctp_getsockopt_auth_supported(sk, len, optval, 80268c2ecf20Sopenharmony_ci optlen); 80278c2ecf20Sopenharmony_ci break; 80288c2ecf20Sopenharmony_ci case SCTP_ECN_SUPPORTED: 80298c2ecf20Sopenharmony_ci retval = sctp_getsockopt_ecn_supported(sk, len, optval, optlen); 80308c2ecf20Sopenharmony_ci break; 80318c2ecf20Sopenharmony_ci case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: 80328c2ecf20Sopenharmony_ci retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen); 80338c2ecf20Sopenharmony_ci break; 80348c2ecf20Sopenharmony_ci default: 80358c2ecf20Sopenharmony_ci retval = -ENOPROTOOPT; 80368c2ecf20Sopenharmony_ci break; 80378c2ecf20Sopenharmony_ci } 80388c2ecf20Sopenharmony_ci 80398c2ecf20Sopenharmony_ci release_sock(sk); 80408c2ecf20Sopenharmony_ci return retval; 80418c2ecf20Sopenharmony_ci} 80428c2ecf20Sopenharmony_ci 80438c2ecf20Sopenharmony_cistatic bool sctp_bpf_bypass_getsockopt(int level, int optname) 80448c2ecf20Sopenharmony_ci{ 80458c2ecf20Sopenharmony_ci if (level == SOL_SCTP) { 80468c2ecf20Sopenharmony_ci switch (optname) { 80478c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_PEELOFF: 80488c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_PEELOFF_FLAGS: 80498c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_CONNECTX3: 80508c2ecf20Sopenharmony_ci return true; 80518c2ecf20Sopenharmony_ci default: 80528c2ecf20Sopenharmony_ci return false; 80538c2ecf20Sopenharmony_ci } 80548c2ecf20Sopenharmony_ci } 80558c2ecf20Sopenharmony_ci 80568c2ecf20Sopenharmony_ci return false; 80578c2ecf20Sopenharmony_ci} 80588c2ecf20Sopenharmony_ci 80598c2ecf20Sopenharmony_cistatic int sctp_hash(struct sock *sk) 80608c2ecf20Sopenharmony_ci{ 80618c2ecf20Sopenharmony_ci /* STUB */ 80628c2ecf20Sopenharmony_ci return 0; 80638c2ecf20Sopenharmony_ci} 80648c2ecf20Sopenharmony_ci 80658c2ecf20Sopenharmony_cistatic void sctp_unhash(struct sock *sk) 80668c2ecf20Sopenharmony_ci{ 80678c2ecf20Sopenharmony_ci /* STUB */ 80688c2ecf20Sopenharmony_ci} 80698c2ecf20Sopenharmony_ci 80708c2ecf20Sopenharmony_ci/* Check if port is acceptable. Possibly find first available port. 80718c2ecf20Sopenharmony_ci * 80728c2ecf20Sopenharmony_ci * The port hash table (contained in the 'global' SCTP protocol storage 80738c2ecf20Sopenharmony_ci * returned by struct sctp_protocol *sctp_get_protocol()). The hash 80748c2ecf20Sopenharmony_ci * table is an array of 4096 lists (sctp_bind_hashbucket). Each 80758c2ecf20Sopenharmony_ci * list (the list number is the port number hashed out, so as you 80768c2ecf20Sopenharmony_ci * would expect from a hash function, all the ports in a given list have 80778c2ecf20Sopenharmony_ci * such a number that hashes out to the same list number; you were 80788c2ecf20Sopenharmony_ci * expecting that, right?); so each list has a set of ports, with a 80798c2ecf20Sopenharmony_ci * link to the socket (struct sock) that uses it, the port number and 80808c2ecf20Sopenharmony_ci * a fastreuse flag (FIXME: NPI ipg). 80818c2ecf20Sopenharmony_ci */ 80828c2ecf20Sopenharmony_cistatic struct sctp_bind_bucket *sctp_bucket_create( 80838c2ecf20Sopenharmony_ci struct sctp_bind_hashbucket *head, struct net *, unsigned short snum); 80848c2ecf20Sopenharmony_ci 80858c2ecf20Sopenharmony_cistatic int sctp_get_port_local(struct sock *sk, union sctp_addr *addr) 80868c2ecf20Sopenharmony_ci{ 80878c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 80888c2ecf20Sopenharmony_ci bool reuse = (sk->sk_reuse || sp->reuse); 80898c2ecf20Sopenharmony_ci struct sctp_bind_hashbucket *head; /* hash list */ 80908c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 80918c2ecf20Sopenharmony_ci kuid_t uid = sock_i_uid(sk); 80928c2ecf20Sopenharmony_ci struct sctp_bind_bucket *pp; 80938c2ecf20Sopenharmony_ci unsigned short snum; 80948c2ecf20Sopenharmony_ci int ret; 80958c2ecf20Sopenharmony_ci 80968c2ecf20Sopenharmony_ci snum = ntohs(addr->v4.sin_port); 80978c2ecf20Sopenharmony_ci 80988c2ecf20Sopenharmony_ci pr_debug("%s: begins, snum:%d\n", __func__, snum); 80998c2ecf20Sopenharmony_ci 81008c2ecf20Sopenharmony_ci if (snum == 0) { 81018c2ecf20Sopenharmony_ci /* Search for an available port. */ 81028c2ecf20Sopenharmony_ci int low, high, remaining, index; 81038c2ecf20Sopenharmony_ci unsigned int rover; 81048c2ecf20Sopenharmony_ci 81058c2ecf20Sopenharmony_ci inet_get_local_port_range(net, &low, &high); 81068c2ecf20Sopenharmony_ci remaining = (high - low) + 1; 81078c2ecf20Sopenharmony_ci rover = prandom_u32() % remaining + low; 81088c2ecf20Sopenharmony_ci 81098c2ecf20Sopenharmony_ci do { 81108c2ecf20Sopenharmony_ci rover++; 81118c2ecf20Sopenharmony_ci if ((rover < low) || (rover > high)) 81128c2ecf20Sopenharmony_ci rover = low; 81138c2ecf20Sopenharmony_ci if (inet_is_local_reserved_port(net, rover)) 81148c2ecf20Sopenharmony_ci continue; 81158c2ecf20Sopenharmony_ci index = sctp_phashfn(net, rover); 81168c2ecf20Sopenharmony_ci head = &sctp_port_hashtable[index]; 81178c2ecf20Sopenharmony_ci spin_lock_bh(&head->lock); 81188c2ecf20Sopenharmony_ci sctp_for_each_hentry(pp, &head->chain) 81198c2ecf20Sopenharmony_ci if ((pp->port == rover) && 81208c2ecf20Sopenharmony_ci net_eq(net, pp->net)) 81218c2ecf20Sopenharmony_ci goto next; 81228c2ecf20Sopenharmony_ci break; 81238c2ecf20Sopenharmony_ci next: 81248c2ecf20Sopenharmony_ci spin_unlock_bh(&head->lock); 81258c2ecf20Sopenharmony_ci cond_resched(); 81268c2ecf20Sopenharmony_ci } while (--remaining > 0); 81278c2ecf20Sopenharmony_ci 81288c2ecf20Sopenharmony_ci /* Exhausted local port range during search? */ 81298c2ecf20Sopenharmony_ci ret = 1; 81308c2ecf20Sopenharmony_ci if (remaining <= 0) 81318c2ecf20Sopenharmony_ci return ret; 81328c2ecf20Sopenharmony_ci 81338c2ecf20Sopenharmony_ci /* OK, here is the one we will use. HEAD (the port 81348c2ecf20Sopenharmony_ci * hash table list entry) is non-NULL and we hold it's 81358c2ecf20Sopenharmony_ci * mutex. 81368c2ecf20Sopenharmony_ci */ 81378c2ecf20Sopenharmony_ci snum = rover; 81388c2ecf20Sopenharmony_ci } else { 81398c2ecf20Sopenharmony_ci /* We are given an specific port number; we verify 81408c2ecf20Sopenharmony_ci * that it is not being used. If it is used, we will 81418c2ecf20Sopenharmony_ci * exahust the search in the hash list corresponding 81428c2ecf20Sopenharmony_ci * to the port number (snum) - we detect that with the 81438c2ecf20Sopenharmony_ci * port iterator, pp being NULL. 81448c2ecf20Sopenharmony_ci */ 81458c2ecf20Sopenharmony_ci head = &sctp_port_hashtable[sctp_phashfn(net, snum)]; 81468c2ecf20Sopenharmony_ci spin_lock_bh(&head->lock); 81478c2ecf20Sopenharmony_ci sctp_for_each_hentry(pp, &head->chain) { 81488c2ecf20Sopenharmony_ci if ((pp->port == snum) && net_eq(pp->net, net)) 81498c2ecf20Sopenharmony_ci goto pp_found; 81508c2ecf20Sopenharmony_ci } 81518c2ecf20Sopenharmony_ci } 81528c2ecf20Sopenharmony_ci pp = NULL; 81538c2ecf20Sopenharmony_ci goto pp_not_found; 81548c2ecf20Sopenharmony_cipp_found: 81558c2ecf20Sopenharmony_ci if (!hlist_empty(&pp->owner)) { 81568c2ecf20Sopenharmony_ci /* We had a port hash table hit - there is an 81578c2ecf20Sopenharmony_ci * available port (pp != NULL) and it is being 81588c2ecf20Sopenharmony_ci * used by other socket (pp->owner not empty); that other 81598c2ecf20Sopenharmony_ci * socket is going to be sk2. 81608c2ecf20Sopenharmony_ci */ 81618c2ecf20Sopenharmony_ci struct sock *sk2; 81628c2ecf20Sopenharmony_ci 81638c2ecf20Sopenharmony_ci pr_debug("%s: found a possible match\n", __func__); 81648c2ecf20Sopenharmony_ci 81658c2ecf20Sopenharmony_ci if ((pp->fastreuse && reuse && 81668c2ecf20Sopenharmony_ci sk->sk_state != SCTP_SS_LISTENING) || 81678c2ecf20Sopenharmony_ci (pp->fastreuseport && sk->sk_reuseport && 81688c2ecf20Sopenharmony_ci uid_eq(pp->fastuid, uid))) 81698c2ecf20Sopenharmony_ci goto success; 81708c2ecf20Sopenharmony_ci 81718c2ecf20Sopenharmony_ci /* Run through the list of sockets bound to the port 81728c2ecf20Sopenharmony_ci * (pp->port) [via the pointers bind_next and 81738c2ecf20Sopenharmony_ci * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one, 81748c2ecf20Sopenharmony_ci * we get the endpoint they describe and run through 81758c2ecf20Sopenharmony_ci * the endpoint's list of IP (v4 or v6) addresses, 81768c2ecf20Sopenharmony_ci * comparing each of the addresses with the address of 81778c2ecf20Sopenharmony_ci * the socket sk. If we find a match, then that means 81788c2ecf20Sopenharmony_ci * that this port/socket (sk) combination are already 81798c2ecf20Sopenharmony_ci * in an endpoint. 81808c2ecf20Sopenharmony_ci */ 81818c2ecf20Sopenharmony_ci sk_for_each_bound(sk2, &pp->owner) { 81828c2ecf20Sopenharmony_ci struct sctp_sock *sp2 = sctp_sk(sk2); 81838c2ecf20Sopenharmony_ci struct sctp_endpoint *ep2 = sp2->ep; 81848c2ecf20Sopenharmony_ci 81858c2ecf20Sopenharmony_ci if (sk == sk2 || 81868c2ecf20Sopenharmony_ci (reuse && (sk2->sk_reuse || sp2->reuse) && 81878c2ecf20Sopenharmony_ci sk2->sk_state != SCTP_SS_LISTENING) || 81888c2ecf20Sopenharmony_ci (sk->sk_reuseport && sk2->sk_reuseport && 81898c2ecf20Sopenharmony_ci uid_eq(uid, sock_i_uid(sk2)))) 81908c2ecf20Sopenharmony_ci continue; 81918c2ecf20Sopenharmony_ci 81928c2ecf20Sopenharmony_ci if (sctp_bind_addr_conflict(&ep2->base.bind_addr, 81938c2ecf20Sopenharmony_ci addr, sp2, sp)) { 81948c2ecf20Sopenharmony_ci ret = 1; 81958c2ecf20Sopenharmony_ci goto fail_unlock; 81968c2ecf20Sopenharmony_ci } 81978c2ecf20Sopenharmony_ci } 81988c2ecf20Sopenharmony_ci 81998c2ecf20Sopenharmony_ci pr_debug("%s: found a match\n", __func__); 82008c2ecf20Sopenharmony_ci } 82018c2ecf20Sopenharmony_cipp_not_found: 82028c2ecf20Sopenharmony_ci /* If there was a hash table miss, create a new port. */ 82038c2ecf20Sopenharmony_ci ret = 1; 82048c2ecf20Sopenharmony_ci if (!pp && !(pp = sctp_bucket_create(head, net, snum))) 82058c2ecf20Sopenharmony_ci goto fail_unlock; 82068c2ecf20Sopenharmony_ci 82078c2ecf20Sopenharmony_ci /* In either case (hit or miss), make sure fastreuse is 1 only 82088c2ecf20Sopenharmony_ci * if sk->sk_reuse is too (that is, if the caller requested 82098c2ecf20Sopenharmony_ci * SO_REUSEADDR on this socket -sk-). 82108c2ecf20Sopenharmony_ci */ 82118c2ecf20Sopenharmony_ci if (hlist_empty(&pp->owner)) { 82128c2ecf20Sopenharmony_ci if (reuse && sk->sk_state != SCTP_SS_LISTENING) 82138c2ecf20Sopenharmony_ci pp->fastreuse = 1; 82148c2ecf20Sopenharmony_ci else 82158c2ecf20Sopenharmony_ci pp->fastreuse = 0; 82168c2ecf20Sopenharmony_ci 82178c2ecf20Sopenharmony_ci if (sk->sk_reuseport) { 82188c2ecf20Sopenharmony_ci pp->fastreuseport = 1; 82198c2ecf20Sopenharmony_ci pp->fastuid = uid; 82208c2ecf20Sopenharmony_ci } else { 82218c2ecf20Sopenharmony_ci pp->fastreuseport = 0; 82228c2ecf20Sopenharmony_ci } 82238c2ecf20Sopenharmony_ci } else { 82248c2ecf20Sopenharmony_ci if (pp->fastreuse && 82258c2ecf20Sopenharmony_ci (!reuse || sk->sk_state == SCTP_SS_LISTENING)) 82268c2ecf20Sopenharmony_ci pp->fastreuse = 0; 82278c2ecf20Sopenharmony_ci 82288c2ecf20Sopenharmony_ci if (pp->fastreuseport && 82298c2ecf20Sopenharmony_ci (!sk->sk_reuseport || !uid_eq(pp->fastuid, uid))) 82308c2ecf20Sopenharmony_ci pp->fastreuseport = 0; 82318c2ecf20Sopenharmony_ci } 82328c2ecf20Sopenharmony_ci 82338c2ecf20Sopenharmony_ci /* We are set, so fill up all the data in the hash table 82348c2ecf20Sopenharmony_ci * entry, tie the socket list information with the rest of the 82358c2ecf20Sopenharmony_ci * sockets FIXME: Blurry, NPI (ipg). 82368c2ecf20Sopenharmony_ci */ 82378c2ecf20Sopenharmony_cisuccess: 82388c2ecf20Sopenharmony_ci if (!sp->bind_hash) { 82398c2ecf20Sopenharmony_ci inet_sk(sk)->inet_num = snum; 82408c2ecf20Sopenharmony_ci sk_add_bind_node(sk, &pp->owner); 82418c2ecf20Sopenharmony_ci sp->bind_hash = pp; 82428c2ecf20Sopenharmony_ci } 82438c2ecf20Sopenharmony_ci ret = 0; 82448c2ecf20Sopenharmony_ci 82458c2ecf20Sopenharmony_cifail_unlock: 82468c2ecf20Sopenharmony_ci spin_unlock_bh(&head->lock); 82478c2ecf20Sopenharmony_ci return ret; 82488c2ecf20Sopenharmony_ci} 82498c2ecf20Sopenharmony_ci 82508c2ecf20Sopenharmony_ci/* Assign a 'snum' port to the socket. If snum == 0, an ephemeral 82518c2ecf20Sopenharmony_ci * port is requested. 82528c2ecf20Sopenharmony_ci */ 82538c2ecf20Sopenharmony_cistatic int sctp_get_port(struct sock *sk, unsigned short snum) 82548c2ecf20Sopenharmony_ci{ 82558c2ecf20Sopenharmony_ci union sctp_addr addr; 82568c2ecf20Sopenharmony_ci struct sctp_af *af = sctp_sk(sk)->pf->af; 82578c2ecf20Sopenharmony_ci 82588c2ecf20Sopenharmony_ci /* Set up a dummy address struct from the sk. */ 82598c2ecf20Sopenharmony_ci af->from_sk(&addr, sk); 82608c2ecf20Sopenharmony_ci addr.v4.sin_port = htons(snum); 82618c2ecf20Sopenharmony_ci 82628c2ecf20Sopenharmony_ci /* Note: sk->sk_num gets filled in if ephemeral port request. */ 82638c2ecf20Sopenharmony_ci return sctp_get_port_local(sk, &addr); 82648c2ecf20Sopenharmony_ci} 82658c2ecf20Sopenharmony_ci 82668c2ecf20Sopenharmony_ci/* 82678c2ecf20Sopenharmony_ci * Move a socket to LISTENING state. 82688c2ecf20Sopenharmony_ci */ 82698c2ecf20Sopenharmony_cistatic int sctp_listen_start(struct sock *sk, int backlog) 82708c2ecf20Sopenharmony_ci{ 82718c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 82728c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sp->ep; 82738c2ecf20Sopenharmony_ci struct crypto_shash *tfm = NULL; 82748c2ecf20Sopenharmony_ci char alg[32]; 82758c2ecf20Sopenharmony_ci 82768c2ecf20Sopenharmony_ci /* Allocate HMAC for generating cookie. */ 82778c2ecf20Sopenharmony_ci if (!sp->hmac && sp->sctp_hmac_alg) { 82788c2ecf20Sopenharmony_ci sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg); 82798c2ecf20Sopenharmony_ci tfm = crypto_alloc_shash(alg, 0, 0); 82808c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) { 82818c2ecf20Sopenharmony_ci net_info_ratelimited("failed to load transform for %s: %ld\n", 82828c2ecf20Sopenharmony_ci sp->sctp_hmac_alg, PTR_ERR(tfm)); 82838c2ecf20Sopenharmony_ci return -ENOSYS; 82848c2ecf20Sopenharmony_ci } 82858c2ecf20Sopenharmony_ci sctp_sk(sk)->hmac = tfm; 82868c2ecf20Sopenharmony_ci } 82878c2ecf20Sopenharmony_ci 82888c2ecf20Sopenharmony_ci /* 82898c2ecf20Sopenharmony_ci * If a bind() or sctp_bindx() is not called prior to a listen() 82908c2ecf20Sopenharmony_ci * call that allows new associations to be accepted, the system 82918c2ecf20Sopenharmony_ci * picks an ephemeral port and will choose an address set equivalent 82928c2ecf20Sopenharmony_ci * to binding with a wildcard address. 82938c2ecf20Sopenharmony_ci * 82948c2ecf20Sopenharmony_ci * This is not currently spelled out in the SCTP sockets 82958c2ecf20Sopenharmony_ci * extensions draft, but follows the practice as seen in TCP 82968c2ecf20Sopenharmony_ci * sockets. 82978c2ecf20Sopenharmony_ci * 82988c2ecf20Sopenharmony_ci */ 82998c2ecf20Sopenharmony_ci inet_sk_set_state(sk, SCTP_SS_LISTENING); 83008c2ecf20Sopenharmony_ci if (!ep->base.bind_addr.port) { 83018c2ecf20Sopenharmony_ci if (sctp_autobind(sk)) 83028c2ecf20Sopenharmony_ci return -EAGAIN; 83038c2ecf20Sopenharmony_ci } else { 83048c2ecf20Sopenharmony_ci if (sctp_get_port(sk, inet_sk(sk)->inet_num)) { 83058c2ecf20Sopenharmony_ci inet_sk_set_state(sk, SCTP_SS_CLOSED); 83068c2ecf20Sopenharmony_ci return -EADDRINUSE; 83078c2ecf20Sopenharmony_ci } 83088c2ecf20Sopenharmony_ci } 83098c2ecf20Sopenharmony_ci 83108c2ecf20Sopenharmony_ci WRITE_ONCE(sk->sk_max_ack_backlog, backlog); 83118c2ecf20Sopenharmony_ci return sctp_hash_endpoint(ep); 83128c2ecf20Sopenharmony_ci} 83138c2ecf20Sopenharmony_ci 83148c2ecf20Sopenharmony_ci/* 83158c2ecf20Sopenharmony_ci * 4.1.3 / 5.1.3 listen() 83168c2ecf20Sopenharmony_ci * 83178c2ecf20Sopenharmony_ci * By default, new associations are not accepted for UDP style sockets. 83188c2ecf20Sopenharmony_ci * An application uses listen() to mark a socket as being able to 83198c2ecf20Sopenharmony_ci * accept new associations. 83208c2ecf20Sopenharmony_ci * 83218c2ecf20Sopenharmony_ci * On TCP style sockets, applications use listen() to ready the SCTP 83228c2ecf20Sopenharmony_ci * endpoint for accepting inbound associations. 83238c2ecf20Sopenharmony_ci * 83248c2ecf20Sopenharmony_ci * On both types of endpoints a backlog of '0' disables listening. 83258c2ecf20Sopenharmony_ci * 83268c2ecf20Sopenharmony_ci * Move a socket to LISTENING state. 83278c2ecf20Sopenharmony_ci */ 83288c2ecf20Sopenharmony_ciint sctp_inet_listen(struct socket *sock, int backlog) 83298c2ecf20Sopenharmony_ci{ 83308c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 83318c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sctp_sk(sk)->ep; 83328c2ecf20Sopenharmony_ci int err = -EINVAL; 83338c2ecf20Sopenharmony_ci 83348c2ecf20Sopenharmony_ci if (unlikely(backlog < 0)) 83358c2ecf20Sopenharmony_ci return err; 83368c2ecf20Sopenharmony_ci 83378c2ecf20Sopenharmony_ci lock_sock(sk); 83388c2ecf20Sopenharmony_ci 83398c2ecf20Sopenharmony_ci /* Peeled-off sockets are not allowed to listen(). */ 83408c2ecf20Sopenharmony_ci if (sctp_style(sk, UDP_HIGH_BANDWIDTH)) 83418c2ecf20Sopenharmony_ci goto out; 83428c2ecf20Sopenharmony_ci 83438c2ecf20Sopenharmony_ci if (sock->state != SS_UNCONNECTED) 83448c2ecf20Sopenharmony_ci goto out; 83458c2ecf20Sopenharmony_ci 83468c2ecf20Sopenharmony_ci if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED)) 83478c2ecf20Sopenharmony_ci goto out; 83488c2ecf20Sopenharmony_ci 83498c2ecf20Sopenharmony_ci /* If backlog is zero, disable listening. */ 83508c2ecf20Sopenharmony_ci if (!backlog) { 83518c2ecf20Sopenharmony_ci if (sctp_sstate(sk, CLOSED)) 83528c2ecf20Sopenharmony_ci goto out; 83538c2ecf20Sopenharmony_ci 83548c2ecf20Sopenharmony_ci err = 0; 83558c2ecf20Sopenharmony_ci sctp_unhash_endpoint(ep); 83568c2ecf20Sopenharmony_ci sk->sk_state = SCTP_SS_CLOSED; 83578c2ecf20Sopenharmony_ci if (sk->sk_reuse || sctp_sk(sk)->reuse) 83588c2ecf20Sopenharmony_ci sctp_sk(sk)->bind_hash->fastreuse = 1; 83598c2ecf20Sopenharmony_ci goto out; 83608c2ecf20Sopenharmony_ci } 83618c2ecf20Sopenharmony_ci 83628c2ecf20Sopenharmony_ci /* If we are already listening, just update the backlog */ 83638c2ecf20Sopenharmony_ci if (sctp_sstate(sk, LISTENING)) 83648c2ecf20Sopenharmony_ci WRITE_ONCE(sk->sk_max_ack_backlog, backlog); 83658c2ecf20Sopenharmony_ci else { 83668c2ecf20Sopenharmony_ci err = sctp_listen_start(sk, backlog); 83678c2ecf20Sopenharmony_ci if (err) 83688c2ecf20Sopenharmony_ci goto out; 83698c2ecf20Sopenharmony_ci } 83708c2ecf20Sopenharmony_ci 83718c2ecf20Sopenharmony_ci err = 0; 83728c2ecf20Sopenharmony_ciout: 83738c2ecf20Sopenharmony_ci release_sock(sk); 83748c2ecf20Sopenharmony_ci return err; 83758c2ecf20Sopenharmony_ci} 83768c2ecf20Sopenharmony_ci 83778c2ecf20Sopenharmony_ci/* 83788c2ecf20Sopenharmony_ci * This function is done by modeling the current datagram_poll() and the 83798c2ecf20Sopenharmony_ci * tcp_poll(). Note that, based on these implementations, we don't 83808c2ecf20Sopenharmony_ci * lock the socket in this function, even though it seems that, 83818c2ecf20Sopenharmony_ci * ideally, locking or some other mechanisms can be used to ensure 83828c2ecf20Sopenharmony_ci * the integrity of the counters (sndbuf and wmem_alloc) used 83838c2ecf20Sopenharmony_ci * in this place. We assume that we don't need locks either until proven 83848c2ecf20Sopenharmony_ci * otherwise. 83858c2ecf20Sopenharmony_ci * 83868c2ecf20Sopenharmony_ci * Another thing to note is that we include the Async I/O support 83878c2ecf20Sopenharmony_ci * here, again, by modeling the current TCP/UDP code. We don't have 83888c2ecf20Sopenharmony_ci * a good way to test with it yet. 83898c2ecf20Sopenharmony_ci */ 83908c2ecf20Sopenharmony_ci__poll_t sctp_poll(struct file *file, struct socket *sock, poll_table *wait) 83918c2ecf20Sopenharmony_ci{ 83928c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 83938c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 83948c2ecf20Sopenharmony_ci __poll_t mask; 83958c2ecf20Sopenharmony_ci 83968c2ecf20Sopenharmony_ci poll_wait(file, sk_sleep(sk), wait); 83978c2ecf20Sopenharmony_ci 83988c2ecf20Sopenharmony_ci sock_rps_record_flow(sk); 83998c2ecf20Sopenharmony_ci 84008c2ecf20Sopenharmony_ci /* A TCP-style listening socket becomes readable when the accept queue 84018c2ecf20Sopenharmony_ci * is not empty. 84028c2ecf20Sopenharmony_ci */ 84038c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 84048c2ecf20Sopenharmony_ci return (!list_empty(&sp->ep->asocs)) ? 84058c2ecf20Sopenharmony_ci (EPOLLIN | EPOLLRDNORM) : 0; 84068c2ecf20Sopenharmony_ci 84078c2ecf20Sopenharmony_ci mask = 0; 84088c2ecf20Sopenharmony_ci 84098c2ecf20Sopenharmony_ci /* Is there any exceptional events? */ 84108c2ecf20Sopenharmony_ci if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue)) 84118c2ecf20Sopenharmony_ci mask |= EPOLLERR | 84128c2ecf20Sopenharmony_ci (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0); 84138c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) 84148c2ecf20Sopenharmony_ci mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; 84158c2ecf20Sopenharmony_ci if (sk->sk_shutdown == SHUTDOWN_MASK) 84168c2ecf20Sopenharmony_ci mask |= EPOLLHUP; 84178c2ecf20Sopenharmony_ci 84188c2ecf20Sopenharmony_ci /* Is it readable? Reconsider this code with TCP-style support. */ 84198c2ecf20Sopenharmony_ci if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 84208c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 84218c2ecf20Sopenharmony_ci 84228c2ecf20Sopenharmony_ci /* The association is either gone or not ready. */ 84238c2ecf20Sopenharmony_ci if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED)) 84248c2ecf20Sopenharmony_ci return mask; 84258c2ecf20Sopenharmony_ci 84268c2ecf20Sopenharmony_ci /* Is it writable? */ 84278c2ecf20Sopenharmony_ci if (sctp_writeable(sk)) { 84288c2ecf20Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM; 84298c2ecf20Sopenharmony_ci } else { 84308c2ecf20Sopenharmony_ci sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 84318c2ecf20Sopenharmony_ci /* 84328c2ecf20Sopenharmony_ci * Since the socket is not locked, the buffer 84338c2ecf20Sopenharmony_ci * might be made available after the writeable check and 84348c2ecf20Sopenharmony_ci * before the bit is set. This could cause a lost I/O 84358c2ecf20Sopenharmony_ci * signal. tcp_poll() has a race breaker for this race 84368c2ecf20Sopenharmony_ci * condition. Based on their implementation, we put 84378c2ecf20Sopenharmony_ci * in the following code to cover it as well. 84388c2ecf20Sopenharmony_ci */ 84398c2ecf20Sopenharmony_ci if (sctp_writeable(sk)) 84408c2ecf20Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM; 84418c2ecf20Sopenharmony_ci } 84428c2ecf20Sopenharmony_ci return mask; 84438c2ecf20Sopenharmony_ci} 84448c2ecf20Sopenharmony_ci 84458c2ecf20Sopenharmony_ci/******************************************************************** 84468c2ecf20Sopenharmony_ci * 2nd Level Abstractions 84478c2ecf20Sopenharmony_ci ********************************************************************/ 84488c2ecf20Sopenharmony_ci 84498c2ecf20Sopenharmony_cistatic struct sctp_bind_bucket *sctp_bucket_create( 84508c2ecf20Sopenharmony_ci struct sctp_bind_hashbucket *head, struct net *net, unsigned short snum) 84518c2ecf20Sopenharmony_ci{ 84528c2ecf20Sopenharmony_ci struct sctp_bind_bucket *pp; 84538c2ecf20Sopenharmony_ci 84548c2ecf20Sopenharmony_ci pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC); 84558c2ecf20Sopenharmony_ci if (pp) { 84568c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_INC(bind_bucket); 84578c2ecf20Sopenharmony_ci pp->port = snum; 84588c2ecf20Sopenharmony_ci pp->fastreuse = 0; 84598c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&pp->owner); 84608c2ecf20Sopenharmony_ci pp->net = net; 84618c2ecf20Sopenharmony_ci hlist_add_head(&pp->node, &head->chain); 84628c2ecf20Sopenharmony_ci } 84638c2ecf20Sopenharmony_ci return pp; 84648c2ecf20Sopenharmony_ci} 84658c2ecf20Sopenharmony_ci 84668c2ecf20Sopenharmony_ci/* Caller must hold hashbucket lock for this tb with local BH disabled */ 84678c2ecf20Sopenharmony_cistatic void sctp_bucket_destroy(struct sctp_bind_bucket *pp) 84688c2ecf20Sopenharmony_ci{ 84698c2ecf20Sopenharmony_ci if (pp && hlist_empty(&pp->owner)) { 84708c2ecf20Sopenharmony_ci __hlist_del(&pp->node); 84718c2ecf20Sopenharmony_ci kmem_cache_free(sctp_bucket_cachep, pp); 84728c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_DEC(bind_bucket); 84738c2ecf20Sopenharmony_ci } 84748c2ecf20Sopenharmony_ci} 84758c2ecf20Sopenharmony_ci 84768c2ecf20Sopenharmony_ci/* Release this socket's reference to a local port. */ 84778c2ecf20Sopenharmony_cistatic inline void __sctp_put_port(struct sock *sk) 84788c2ecf20Sopenharmony_ci{ 84798c2ecf20Sopenharmony_ci struct sctp_bind_hashbucket *head = 84808c2ecf20Sopenharmony_ci &sctp_port_hashtable[sctp_phashfn(sock_net(sk), 84818c2ecf20Sopenharmony_ci inet_sk(sk)->inet_num)]; 84828c2ecf20Sopenharmony_ci struct sctp_bind_bucket *pp; 84838c2ecf20Sopenharmony_ci 84848c2ecf20Sopenharmony_ci spin_lock(&head->lock); 84858c2ecf20Sopenharmony_ci pp = sctp_sk(sk)->bind_hash; 84868c2ecf20Sopenharmony_ci __sk_del_bind_node(sk); 84878c2ecf20Sopenharmony_ci sctp_sk(sk)->bind_hash = NULL; 84888c2ecf20Sopenharmony_ci inet_sk(sk)->inet_num = 0; 84898c2ecf20Sopenharmony_ci sctp_bucket_destroy(pp); 84908c2ecf20Sopenharmony_ci spin_unlock(&head->lock); 84918c2ecf20Sopenharmony_ci} 84928c2ecf20Sopenharmony_ci 84938c2ecf20Sopenharmony_civoid sctp_put_port(struct sock *sk) 84948c2ecf20Sopenharmony_ci{ 84958c2ecf20Sopenharmony_ci local_bh_disable(); 84968c2ecf20Sopenharmony_ci __sctp_put_port(sk); 84978c2ecf20Sopenharmony_ci local_bh_enable(); 84988c2ecf20Sopenharmony_ci} 84998c2ecf20Sopenharmony_ci 85008c2ecf20Sopenharmony_ci/* 85018c2ecf20Sopenharmony_ci * The system picks an ephemeral port and choose an address set equivalent 85028c2ecf20Sopenharmony_ci * to binding with a wildcard address. 85038c2ecf20Sopenharmony_ci * One of those addresses will be the primary address for the association. 85048c2ecf20Sopenharmony_ci * This automatically enables the multihoming capability of SCTP. 85058c2ecf20Sopenharmony_ci */ 85068c2ecf20Sopenharmony_cistatic int sctp_autobind(struct sock *sk) 85078c2ecf20Sopenharmony_ci{ 85088c2ecf20Sopenharmony_ci union sctp_addr autoaddr; 85098c2ecf20Sopenharmony_ci struct sctp_af *af; 85108c2ecf20Sopenharmony_ci __be16 port; 85118c2ecf20Sopenharmony_ci 85128c2ecf20Sopenharmony_ci /* Initialize a local sockaddr structure to INADDR_ANY. */ 85138c2ecf20Sopenharmony_ci af = sctp_sk(sk)->pf->af; 85148c2ecf20Sopenharmony_ci 85158c2ecf20Sopenharmony_ci port = htons(inet_sk(sk)->inet_num); 85168c2ecf20Sopenharmony_ci af->inaddr_any(&autoaddr, port); 85178c2ecf20Sopenharmony_ci 85188c2ecf20Sopenharmony_ci return sctp_do_bind(sk, &autoaddr, af->sockaddr_len); 85198c2ecf20Sopenharmony_ci} 85208c2ecf20Sopenharmony_ci 85218c2ecf20Sopenharmony_ci/* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. 85228c2ecf20Sopenharmony_ci * 85238c2ecf20Sopenharmony_ci * From RFC 2292 85248c2ecf20Sopenharmony_ci * 4.2 The cmsghdr Structure * 85258c2ecf20Sopenharmony_ci * 85268c2ecf20Sopenharmony_ci * When ancillary data is sent or received, any number of ancillary data 85278c2ecf20Sopenharmony_ci * objects can be specified by the msg_control and msg_controllen members of 85288c2ecf20Sopenharmony_ci * the msghdr structure, because each object is preceded by 85298c2ecf20Sopenharmony_ci * a cmsghdr structure defining the object's length (the cmsg_len member). 85308c2ecf20Sopenharmony_ci * Historically Berkeley-derived implementations have passed only one object 85318c2ecf20Sopenharmony_ci * at a time, but this API allows multiple objects to be 85328c2ecf20Sopenharmony_ci * passed in a single call to sendmsg() or recvmsg(). The following example 85338c2ecf20Sopenharmony_ci * shows two ancillary data objects in a control buffer. 85348c2ecf20Sopenharmony_ci * 85358c2ecf20Sopenharmony_ci * |<--------------------------- msg_controllen -------------------------->| 85368c2ecf20Sopenharmony_ci * | | 85378c2ecf20Sopenharmony_ci * 85388c2ecf20Sopenharmony_ci * |<----- ancillary data object ----->|<----- ancillary data object ----->| 85398c2ecf20Sopenharmony_ci * 85408c2ecf20Sopenharmony_ci * |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->| 85418c2ecf20Sopenharmony_ci * | | | 85428c2ecf20Sopenharmony_ci * 85438c2ecf20Sopenharmony_ci * |<---------- cmsg_len ---------->| |<--------- cmsg_len ----------->| | 85448c2ecf20Sopenharmony_ci * 85458c2ecf20Sopenharmony_ci * |<--------- CMSG_LEN() --------->| |<-------- CMSG_LEN() ---------->| | 85468c2ecf20Sopenharmony_ci * | | | | | 85478c2ecf20Sopenharmony_ci * 85488c2ecf20Sopenharmony_ci * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 85498c2ecf20Sopenharmony_ci * |cmsg_|cmsg_|cmsg_|XX| |XX|cmsg_|cmsg_|cmsg_|XX| |XX| 85508c2ecf20Sopenharmony_ci * 85518c2ecf20Sopenharmony_ci * |len |level|type |XX|cmsg_data[]|XX|len |level|type |XX|cmsg_data[]|XX| 85528c2ecf20Sopenharmony_ci * 85538c2ecf20Sopenharmony_ci * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 85548c2ecf20Sopenharmony_ci * ^ 85558c2ecf20Sopenharmony_ci * | 85568c2ecf20Sopenharmony_ci * 85578c2ecf20Sopenharmony_ci * msg_control 85588c2ecf20Sopenharmony_ci * points here 85598c2ecf20Sopenharmony_ci */ 85608c2ecf20Sopenharmony_cistatic int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs) 85618c2ecf20Sopenharmony_ci{ 85628c2ecf20Sopenharmony_ci struct msghdr *my_msg = (struct msghdr *)msg; 85638c2ecf20Sopenharmony_ci struct cmsghdr *cmsg; 85648c2ecf20Sopenharmony_ci 85658c2ecf20Sopenharmony_ci for_each_cmsghdr(cmsg, my_msg) { 85668c2ecf20Sopenharmony_ci if (!CMSG_OK(my_msg, cmsg)) 85678c2ecf20Sopenharmony_ci return -EINVAL; 85688c2ecf20Sopenharmony_ci 85698c2ecf20Sopenharmony_ci /* Should we parse this header or ignore? */ 85708c2ecf20Sopenharmony_ci if (cmsg->cmsg_level != IPPROTO_SCTP) 85718c2ecf20Sopenharmony_ci continue; 85728c2ecf20Sopenharmony_ci 85738c2ecf20Sopenharmony_ci /* Strictly check lengths following example in SCM code. */ 85748c2ecf20Sopenharmony_ci switch (cmsg->cmsg_type) { 85758c2ecf20Sopenharmony_ci case SCTP_INIT: 85768c2ecf20Sopenharmony_ci /* SCTP Socket API Extension 85778c2ecf20Sopenharmony_ci * 5.3.1 SCTP Initiation Structure (SCTP_INIT) 85788c2ecf20Sopenharmony_ci * 85798c2ecf20Sopenharmony_ci * This cmsghdr structure provides information for 85808c2ecf20Sopenharmony_ci * initializing new SCTP associations with sendmsg(). 85818c2ecf20Sopenharmony_ci * The SCTP_INITMSG socket option uses this same data 85828c2ecf20Sopenharmony_ci * structure. This structure is not used for 85838c2ecf20Sopenharmony_ci * recvmsg(). 85848c2ecf20Sopenharmony_ci * 85858c2ecf20Sopenharmony_ci * cmsg_level cmsg_type cmsg_data[] 85868c2ecf20Sopenharmony_ci * ------------ ------------ ---------------------- 85878c2ecf20Sopenharmony_ci * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg 85888c2ecf20Sopenharmony_ci */ 85898c2ecf20Sopenharmony_ci if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg))) 85908c2ecf20Sopenharmony_ci return -EINVAL; 85918c2ecf20Sopenharmony_ci 85928c2ecf20Sopenharmony_ci cmsgs->init = CMSG_DATA(cmsg); 85938c2ecf20Sopenharmony_ci break; 85948c2ecf20Sopenharmony_ci 85958c2ecf20Sopenharmony_ci case SCTP_SNDRCV: 85968c2ecf20Sopenharmony_ci /* SCTP Socket API Extension 85978c2ecf20Sopenharmony_ci * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV) 85988c2ecf20Sopenharmony_ci * 85998c2ecf20Sopenharmony_ci * This cmsghdr structure specifies SCTP options for 86008c2ecf20Sopenharmony_ci * sendmsg() and describes SCTP header information 86018c2ecf20Sopenharmony_ci * about a received message through recvmsg(). 86028c2ecf20Sopenharmony_ci * 86038c2ecf20Sopenharmony_ci * cmsg_level cmsg_type cmsg_data[] 86048c2ecf20Sopenharmony_ci * ------------ ------------ ---------------------- 86058c2ecf20Sopenharmony_ci * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo 86068c2ecf20Sopenharmony_ci */ 86078c2ecf20Sopenharmony_ci if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) 86088c2ecf20Sopenharmony_ci return -EINVAL; 86098c2ecf20Sopenharmony_ci 86108c2ecf20Sopenharmony_ci cmsgs->srinfo = CMSG_DATA(cmsg); 86118c2ecf20Sopenharmony_ci 86128c2ecf20Sopenharmony_ci if (cmsgs->srinfo->sinfo_flags & 86138c2ecf20Sopenharmony_ci ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 86148c2ecf20Sopenharmony_ci SCTP_SACK_IMMEDIATELY | SCTP_SENDALL | 86158c2ecf20Sopenharmony_ci SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF)) 86168c2ecf20Sopenharmony_ci return -EINVAL; 86178c2ecf20Sopenharmony_ci break; 86188c2ecf20Sopenharmony_ci 86198c2ecf20Sopenharmony_ci case SCTP_SNDINFO: 86208c2ecf20Sopenharmony_ci /* SCTP Socket API Extension 86218c2ecf20Sopenharmony_ci * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) 86228c2ecf20Sopenharmony_ci * 86238c2ecf20Sopenharmony_ci * This cmsghdr structure specifies SCTP options for 86248c2ecf20Sopenharmony_ci * sendmsg(). This structure and SCTP_RCVINFO replaces 86258c2ecf20Sopenharmony_ci * SCTP_SNDRCV which has been deprecated. 86268c2ecf20Sopenharmony_ci * 86278c2ecf20Sopenharmony_ci * cmsg_level cmsg_type cmsg_data[] 86288c2ecf20Sopenharmony_ci * ------------ ------------ --------------------- 86298c2ecf20Sopenharmony_ci * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo 86308c2ecf20Sopenharmony_ci */ 86318c2ecf20Sopenharmony_ci if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo))) 86328c2ecf20Sopenharmony_ci return -EINVAL; 86338c2ecf20Sopenharmony_ci 86348c2ecf20Sopenharmony_ci cmsgs->sinfo = CMSG_DATA(cmsg); 86358c2ecf20Sopenharmony_ci 86368c2ecf20Sopenharmony_ci if (cmsgs->sinfo->snd_flags & 86378c2ecf20Sopenharmony_ci ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 86388c2ecf20Sopenharmony_ci SCTP_SACK_IMMEDIATELY | SCTP_SENDALL | 86398c2ecf20Sopenharmony_ci SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF)) 86408c2ecf20Sopenharmony_ci return -EINVAL; 86418c2ecf20Sopenharmony_ci break; 86428c2ecf20Sopenharmony_ci case SCTP_PRINFO: 86438c2ecf20Sopenharmony_ci /* SCTP Socket API Extension 86448c2ecf20Sopenharmony_ci * 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO) 86458c2ecf20Sopenharmony_ci * 86468c2ecf20Sopenharmony_ci * This cmsghdr structure specifies SCTP options for sendmsg(). 86478c2ecf20Sopenharmony_ci * 86488c2ecf20Sopenharmony_ci * cmsg_level cmsg_type cmsg_data[] 86498c2ecf20Sopenharmony_ci * ------------ ------------ --------------------- 86508c2ecf20Sopenharmony_ci * IPPROTO_SCTP SCTP_PRINFO struct sctp_prinfo 86518c2ecf20Sopenharmony_ci */ 86528c2ecf20Sopenharmony_ci if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_prinfo))) 86538c2ecf20Sopenharmony_ci return -EINVAL; 86548c2ecf20Sopenharmony_ci 86558c2ecf20Sopenharmony_ci cmsgs->prinfo = CMSG_DATA(cmsg); 86568c2ecf20Sopenharmony_ci if (cmsgs->prinfo->pr_policy & ~SCTP_PR_SCTP_MASK) 86578c2ecf20Sopenharmony_ci return -EINVAL; 86588c2ecf20Sopenharmony_ci 86598c2ecf20Sopenharmony_ci if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE) 86608c2ecf20Sopenharmony_ci cmsgs->prinfo->pr_value = 0; 86618c2ecf20Sopenharmony_ci break; 86628c2ecf20Sopenharmony_ci case SCTP_AUTHINFO: 86638c2ecf20Sopenharmony_ci /* SCTP Socket API Extension 86648c2ecf20Sopenharmony_ci * 5.3.8 SCTP AUTH Information Structure (SCTP_AUTHINFO) 86658c2ecf20Sopenharmony_ci * 86668c2ecf20Sopenharmony_ci * This cmsghdr structure specifies SCTP options for sendmsg(). 86678c2ecf20Sopenharmony_ci * 86688c2ecf20Sopenharmony_ci * cmsg_level cmsg_type cmsg_data[] 86698c2ecf20Sopenharmony_ci * ------------ ------------ --------------------- 86708c2ecf20Sopenharmony_ci * IPPROTO_SCTP SCTP_AUTHINFO struct sctp_authinfo 86718c2ecf20Sopenharmony_ci */ 86728c2ecf20Sopenharmony_ci if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_authinfo))) 86738c2ecf20Sopenharmony_ci return -EINVAL; 86748c2ecf20Sopenharmony_ci 86758c2ecf20Sopenharmony_ci cmsgs->authinfo = CMSG_DATA(cmsg); 86768c2ecf20Sopenharmony_ci break; 86778c2ecf20Sopenharmony_ci case SCTP_DSTADDRV4: 86788c2ecf20Sopenharmony_ci case SCTP_DSTADDRV6: 86798c2ecf20Sopenharmony_ci /* SCTP Socket API Extension 86808c2ecf20Sopenharmony_ci * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6) 86818c2ecf20Sopenharmony_ci * 86828c2ecf20Sopenharmony_ci * This cmsghdr structure specifies SCTP options for sendmsg(). 86838c2ecf20Sopenharmony_ci * 86848c2ecf20Sopenharmony_ci * cmsg_level cmsg_type cmsg_data[] 86858c2ecf20Sopenharmony_ci * ------------ ------------ --------------------- 86868c2ecf20Sopenharmony_ci * IPPROTO_SCTP SCTP_DSTADDRV4 struct in_addr 86878c2ecf20Sopenharmony_ci * ------------ ------------ --------------------- 86888c2ecf20Sopenharmony_ci * IPPROTO_SCTP SCTP_DSTADDRV6 struct in6_addr 86898c2ecf20Sopenharmony_ci */ 86908c2ecf20Sopenharmony_ci cmsgs->addrs_msg = my_msg; 86918c2ecf20Sopenharmony_ci break; 86928c2ecf20Sopenharmony_ci default: 86938c2ecf20Sopenharmony_ci return -EINVAL; 86948c2ecf20Sopenharmony_ci } 86958c2ecf20Sopenharmony_ci } 86968c2ecf20Sopenharmony_ci 86978c2ecf20Sopenharmony_ci return 0; 86988c2ecf20Sopenharmony_ci} 86998c2ecf20Sopenharmony_ci 87008c2ecf20Sopenharmony_ci/* 87018c2ecf20Sopenharmony_ci * Wait for a packet.. 87028c2ecf20Sopenharmony_ci * Note: This function is the same function as in core/datagram.c 87038c2ecf20Sopenharmony_ci * with a few modifications to make lksctp work. 87048c2ecf20Sopenharmony_ci */ 87058c2ecf20Sopenharmony_cistatic int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p) 87068c2ecf20Sopenharmony_ci{ 87078c2ecf20Sopenharmony_ci int error; 87088c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 87098c2ecf20Sopenharmony_ci 87108c2ecf20Sopenharmony_ci prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 87118c2ecf20Sopenharmony_ci 87128c2ecf20Sopenharmony_ci /* Socket errors? */ 87138c2ecf20Sopenharmony_ci error = sock_error(sk); 87148c2ecf20Sopenharmony_ci if (error) 87158c2ecf20Sopenharmony_ci goto out; 87168c2ecf20Sopenharmony_ci 87178c2ecf20Sopenharmony_ci if (!skb_queue_empty(&sk->sk_receive_queue)) 87188c2ecf20Sopenharmony_ci goto ready; 87198c2ecf20Sopenharmony_ci 87208c2ecf20Sopenharmony_ci /* Socket shut down? */ 87218c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) 87228c2ecf20Sopenharmony_ci goto out; 87238c2ecf20Sopenharmony_ci 87248c2ecf20Sopenharmony_ci /* Sequenced packets can come disconnected. If so we report the 87258c2ecf20Sopenharmony_ci * problem. 87268c2ecf20Sopenharmony_ci */ 87278c2ecf20Sopenharmony_ci error = -ENOTCONN; 87288c2ecf20Sopenharmony_ci 87298c2ecf20Sopenharmony_ci /* Is there a good reason to think that we may receive some data? */ 87308c2ecf20Sopenharmony_ci if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING)) 87318c2ecf20Sopenharmony_ci goto out; 87328c2ecf20Sopenharmony_ci 87338c2ecf20Sopenharmony_ci /* Handle signals. */ 87348c2ecf20Sopenharmony_ci if (signal_pending(current)) 87358c2ecf20Sopenharmony_ci goto interrupted; 87368c2ecf20Sopenharmony_ci 87378c2ecf20Sopenharmony_ci /* Let another process have a go. Since we are going to sleep 87388c2ecf20Sopenharmony_ci * anyway. Note: This may cause odd behaviors if the message 87398c2ecf20Sopenharmony_ci * does not fit in the user's buffer, but this seems to be the 87408c2ecf20Sopenharmony_ci * only way to honor MSG_DONTWAIT realistically. 87418c2ecf20Sopenharmony_ci */ 87428c2ecf20Sopenharmony_ci release_sock(sk); 87438c2ecf20Sopenharmony_ci *timeo_p = schedule_timeout(*timeo_p); 87448c2ecf20Sopenharmony_ci lock_sock(sk); 87458c2ecf20Sopenharmony_ci 87468c2ecf20Sopenharmony_ciready: 87478c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 87488c2ecf20Sopenharmony_ci return 0; 87498c2ecf20Sopenharmony_ci 87508c2ecf20Sopenharmony_ciinterrupted: 87518c2ecf20Sopenharmony_ci error = sock_intr_errno(*timeo_p); 87528c2ecf20Sopenharmony_ci 87538c2ecf20Sopenharmony_ciout: 87548c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 87558c2ecf20Sopenharmony_ci *err = error; 87568c2ecf20Sopenharmony_ci return error; 87578c2ecf20Sopenharmony_ci} 87588c2ecf20Sopenharmony_ci 87598c2ecf20Sopenharmony_ci/* Receive a datagram. 87608c2ecf20Sopenharmony_ci * Note: This is pretty much the same routine as in core/datagram.c 87618c2ecf20Sopenharmony_ci * with a few changes to make lksctp work. 87628c2ecf20Sopenharmony_ci */ 87638c2ecf20Sopenharmony_cistruct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, 87648c2ecf20Sopenharmony_ci int noblock, int *err) 87658c2ecf20Sopenharmony_ci{ 87668c2ecf20Sopenharmony_ci int error; 87678c2ecf20Sopenharmony_ci struct sk_buff *skb; 87688c2ecf20Sopenharmony_ci long timeo; 87698c2ecf20Sopenharmony_ci 87708c2ecf20Sopenharmony_ci timeo = sock_rcvtimeo(sk, noblock); 87718c2ecf20Sopenharmony_ci 87728c2ecf20Sopenharmony_ci pr_debug("%s: timeo:%ld, max:%ld\n", __func__, timeo, 87738c2ecf20Sopenharmony_ci MAX_SCHEDULE_TIMEOUT); 87748c2ecf20Sopenharmony_ci 87758c2ecf20Sopenharmony_ci do { 87768c2ecf20Sopenharmony_ci /* Again only user level code calls this function, 87778c2ecf20Sopenharmony_ci * so nothing interrupt level 87788c2ecf20Sopenharmony_ci * will suddenly eat the receive_queue. 87798c2ecf20Sopenharmony_ci * 87808c2ecf20Sopenharmony_ci * Look at current nfs client by the way... 87818c2ecf20Sopenharmony_ci * However, this function was correct in any case. 8) 87828c2ecf20Sopenharmony_ci */ 87838c2ecf20Sopenharmony_ci if (flags & MSG_PEEK) { 87848c2ecf20Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 87858c2ecf20Sopenharmony_ci if (skb) 87868c2ecf20Sopenharmony_ci refcount_inc(&skb->users); 87878c2ecf20Sopenharmony_ci } else { 87888c2ecf20Sopenharmony_ci skb = __skb_dequeue(&sk->sk_receive_queue); 87898c2ecf20Sopenharmony_ci } 87908c2ecf20Sopenharmony_ci 87918c2ecf20Sopenharmony_ci if (skb) 87928c2ecf20Sopenharmony_ci return skb; 87938c2ecf20Sopenharmony_ci 87948c2ecf20Sopenharmony_ci /* Caller is allowed not to check sk->sk_err before calling. */ 87958c2ecf20Sopenharmony_ci error = sock_error(sk); 87968c2ecf20Sopenharmony_ci if (error) 87978c2ecf20Sopenharmony_ci goto no_packet; 87988c2ecf20Sopenharmony_ci 87998c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) 88008c2ecf20Sopenharmony_ci break; 88018c2ecf20Sopenharmony_ci 88028c2ecf20Sopenharmony_ci if (sk_can_busy_loop(sk)) { 88038c2ecf20Sopenharmony_ci sk_busy_loop(sk, noblock); 88048c2ecf20Sopenharmony_ci 88058c2ecf20Sopenharmony_ci if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 88068c2ecf20Sopenharmony_ci continue; 88078c2ecf20Sopenharmony_ci } 88088c2ecf20Sopenharmony_ci 88098c2ecf20Sopenharmony_ci /* User doesn't want to wait. */ 88108c2ecf20Sopenharmony_ci error = -EAGAIN; 88118c2ecf20Sopenharmony_ci if (!timeo) 88128c2ecf20Sopenharmony_ci goto no_packet; 88138c2ecf20Sopenharmony_ci } while (sctp_wait_for_packet(sk, err, &timeo) == 0); 88148c2ecf20Sopenharmony_ci 88158c2ecf20Sopenharmony_ci return NULL; 88168c2ecf20Sopenharmony_ci 88178c2ecf20Sopenharmony_cino_packet: 88188c2ecf20Sopenharmony_ci *err = error; 88198c2ecf20Sopenharmony_ci return NULL; 88208c2ecf20Sopenharmony_ci} 88218c2ecf20Sopenharmony_ci 88228c2ecf20Sopenharmony_ci/* If sndbuf has changed, wake up per association sndbuf waiters. */ 88238c2ecf20Sopenharmony_cistatic void __sctp_write_space(struct sctp_association *asoc) 88248c2ecf20Sopenharmony_ci{ 88258c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 88268c2ecf20Sopenharmony_ci 88278c2ecf20Sopenharmony_ci if (sctp_wspace(asoc) <= 0) 88288c2ecf20Sopenharmony_ci return; 88298c2ecf20Sopenharmony_ci 88308c2ecf20Sopenharmony_ci if (waitqueue_active(&asoc->wait)) 88318c2ecf20Sopenharmony_ci wake_up_interruptible(&asoc->wait); 88328c2ecf20Sopenharmony_ci 88338c2ecf20Sopenharmony_ci if (sctp_writeable(sk)) { 88348c2ecf20Sopenharmony_ci struct socket_wq *wq; 88358c2ecf20Sopenharmony_ci 88368c2ecf20Sopenharmony_ci rcu_read_lock(); 88378c2ecf20Sopenharmony_ci wq = rcu_dereference(sk->sk_wq); 88388c2ecf20Sopenharmony_ci if (wq) { 88398c2ecf20Sopenharmony_ci if (waitqueue_active(&wq->wait)) 88408c2ecf20Sopenharmony_ci wake_up_interruptible(&wq->wait); 88418c2ecf20Sopenharmony_ci 88428c2ecf20Sopenharmony_ci /* Note that we try to include the Async I/O support 88438c2ecf20Sopenharmony_ci * here by modeling from the current TCP/UDP code. 88448c2ecf20Sopenharmony_ci * We have not tested with it yet. 88458c2ecf20Sopenharmony_ci */ 88468c2ecf20Sopenharmony_ci if (!(sk->sk_shutdown & SEND_SHUTDOWN)) 88478c2ecf20Sopenharmony_ci sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT); 88488c2ecf20Sopenharmony_ci } 88498c2ecf20Sopenharmony_ci rcu_read_unlock(); 88508c2ecf20Sopenharmony_ci } 88518c2ecf20Sopenharmony_ci} 88528c2ecf20Sopenharmony_ci 88538c2ecf20Sopenharmony_cistatic void sctp_wake_up_waiters(struct sock *sk, 88548c2ecf20Sopenharmony_ci struct sctp_association *asoc) 88558c2ecf20Sopenharmony_ci{ 88568c2ecf20Sopenharmony_ci struct sctp_association *tmp = asoc; 88578c2ecf20Sopenharmony_ci 88588c2ecf20Sopenharmony_ci /* We do accounting for the sndbuf space per association, 88598c2ecf20Sopenharmony_ci * so we only need to wake our own association. 88608c2ecf20Sopenharmony_ci */ 88618c2ecf20Sopenharmony_ci if (asoc->ep->sndbuf_policy) 88628c2ecf20Sopenharmony_ci return __sctp_write_space(asoc); 88638c2ecf20Sopenharmony_ci 88648c2ecf20Sopenharmony_ci /* If association goes down and is just flushing its 88658c2ecf20Sopenharmony_ci * outq, then just normally notify others. 88668c2ecf20Sopenharmony_ci */ 88678c2ecf20Sopenharmony_ci if (asoc->base.dead) 88688c2ecf20Sopenharmony_ci return sctp_write_space(sk); 88698c2ecf20Sopenharmony_ci 88708c2ecf20Sopenharmony_ci /* Accounting for the sndbuf space is per socket, so we 88718c2ecf20Sopenharmony_ci * need to wake up others, try to be fair and in case of 88728c2ecf20Sopenharmony_ci * other associations, let them have a go first instead 88738c2ecf20Sopenharmony_ci * of just doing a sctp_write_space() call. 88748c2ecf20Sopenharmony_ci * 88758c2ecf20Sopenharmony_ci * Note that we reach sctp_wake_up_waiters() only when 88768c2ecf20Sopenharmony_ci * associations free up queued chunks, thus we are under 88778c2ecf20Sopenharmony_ci * lock and the list of associations on a socket is 88788c2ecf20Sopenharmony_ci * guaranteed not to change. 88798c2ecf20Sopenharmony_ci */ 88808c2ecf20Sopenharmony_ci for (tmp = list_next_entry(tmp, asocs); 1; 88818c2ecf20Sopenharmony_ci tmp = list_next_entry(tmp, asocs)) { 88828c2ecf20Sopenharmony_ci /* Manually skip the head element. */ 88838c2ecf20Sopenharmony_ci if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs)) 88848c2ecf20Sopenharmony_ci continue; 88858c2ecf20Sopenharmony_ci /* Wake up association. */ 88868c2ecf20Sopenharmony_ci __sctp_write_space(tmp); 88878c2ecf20Sopenharmony_ci /* We've reached the end. */ 88888c2ecf20Sopenharmony_ci if (tmp == asoc) 88898c2ecf20Sopenharmony_ci break; 88908c2ecf20Sopenharmony_ci } 88918c2ecf20Sopenharmony_ci} 88928c2ecf20Sopenharmony_ci 88938c2ecf20Sopenharmony_ci/* Do accounting for the sndbuf space. 88948c2ecf20Sopenharmony_ci * Decrement the used sndbuf space of the corresponding association by the 88958c2ecf20Sopenharmony_ci * data size which was just transmitted(freed). 88968c2ecf20Sopenharmony_ci */ 88978c2ecf20Sopenharmony_cistatic void sctp_wfree(struct sk_buff *skb) 88988c2ecf20Sopenharmony_ci{ 88998c2ecf20Sopenharmony_ci struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg; 89008c2ecf20Sopenharmony_ci struct sctp_association *asoc = chunk->asoc; 89018c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 89028c2ecf20Sopenharmony_ci 89038c2ecf20Sopenharmony_ci sk_mem_uncharge(sk, skb->truesize); 89048c2ecf20Sopenharmony_ci sk_wmem_queued_add(sk, -(skb->truesize + sizeof(struct sctp_chunk))); 89058c2ecf20Sopenharmony_ci asoc->sndbuf_used -= skb->truesize + sizeof(struct sctp_chunk); 89068c2ecf20Sopenharmony_ci WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), 89078c2ecf20Sopenharmony_ci &sk->sk_wmem_alloc)); 89088c2ecf20Sopenharmony_ci 89098c2ecf20Sopenharmony_ci if (chunk->shkey) { 89108c2ecf20Sopenharmony_ci struct sctp_shared_key *shkey = chunk->shkey; 89118c2ecf20Sopenharmony_ci 89128c2ecf20Sopenharmony_ci /* refcnt == 2 and !list_empty mean after this release, it's 89138c2ecf20Sopenharmony_ci * not being used anywhere, and it's time to notify userland 89148c2ecf20Sopenharmony_ci * that this shkey can be freed if it's been deactivated. 89158c2ecf20Sopenharmony_ci */ 89168c2ecf20Sopenharmony_ci if (shkey->deactivated && !list_empty(&shkey->key_list) && 89178c2ecf20Sopenharmony_ci refcount_read(&shkey->refcnt) == 2) { 89188c2ecf20Sopenharmony_ci struct sctp_ulpevent *ev; 89198c2ecf20Sopenharmony_ci 89208c2ecf20Sopenharmony_ci ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id, 89218c2ecf20Sopenharmony_ci SCTP_AUTH_FREE_KEY, 89228c2ecf20Sopenharmony_ci GFP_KERNEL); 89238c2ecf20Sopenharmony_ci if (ev) 89248c2ecf20Sopenharmony_ci asoc->stream.si->enqueue_event(&asoc->ulpq, ev); 89258c2ecf20Sopenharmony_ci } 89268c2ecf20Sopenharmony_ci sctp_auth_shkey_release(chunk->shkey); 89278c2ecf20Sopenharmony_ci } 89288c2ecf20Sopenharmony_ci 89298c2ecf20Sopenharmony_ci sock_wfree(skb); 89308c2ecf20Sopenharmony_ci sctp_wake_up_waiters(sk, asoc); 89318c2ecf20Sopenharmony_ci 89328c2ecf20Sopenharmony_ci sctp_association_put(asoc); 89338c2ecf20Sopenharmony_ci} 89348c2ecf20Sopenharmony_ci 89358c2ecf20Sopenharmony_ci/* Do accounting for the receive space on the socket. 89368c2ecf20Sopenharmony_ci * Accounting for the association is done in ulpevent.c 89378c2ecf20Sopenharmony_ci * We set this as a destructor for the cloned data skbs so that 89388c2ecf20Sopenharmony_ci * accounting is done at the correct time. 89398c2ecf20Sopenharmony_ci */ 89408c2ecf20Sopenharmony_civoid sctp_sock_rfree(struct sk_buff *skb) 89418c2ecf20Sopenharmony_ci{ 89428c2ecf20Sopenharmony_ci struct sock *sk = skb->sk; 89438c2ecf20Sopenharmony_ci struct sctp_ulpevent *event = sctp_skb2event(skb); 89448c2ecf20Sopenharmony_ci 89458c2ecf20Sopenharmony_ci atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); 89468c2ecf20Sopenharmony_ci 89478c2ecf20Sopenharmony_ci /* 89488c2ecf20Sopenharmony_ci * Mimic the behavior of sock_rfree 89498c2ecf20Sopenharmony_ci */ 89508c2ecf20Sopenharmony_ci sk_mem_uncharge(sk, event->rmem_len); 89518c2ecf20Sopenharmony_ci} 89528c2ecf20Sopenharmony_ci 89538c2ecf20Sopenharmony_ci 89548c2ecf20Sopenharmony_ci/* Helper function to wait for space in the sndbuf. */ 89558c2ecf20Sopenharmony_cistatic int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 89568c2ecf20Sopenharmony_ci size_t msg_len) 89578c2ecf20Sopenharmony_ci{ 89588c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 89598c2ecf20Sopenharmony_ci long current_timeo = *timeo_p; 89608c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 89618c2ecf20Sopenharmony_ci int err = 0; 89628c2ecf20Sopenharmony_ci 89638c2ecf20Sopenharmony_ci pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc, 89648c2ecf20Sopenharmony_ci *timeo_p, msg_len); 89658c2ecf20Sopenharmony_ci 89668c2ecf20Sopenharmony_ci /* Increment the association's refcnt. */ 89678c2ecf20Sopenharmony_ci sctp_association_hold(asoc); 89688c2ecf20Sopenharmony_ci 89698c2ecf20Sopenharmony_ci /* Wait on the association specific sndbuf space. */ 89708c2ecf20Sopenharmony_ci for (;;) { 89718c2ecf20Sopenharmony_ci prepare_to_wait_exclusive(&asoc->wait, &wait, 89728c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE); 89738c2ecf20Sopenharmony_ci if (asoc->base.dead) 89748c2ecf20Sopenharmony_ci goto do_dead; 89758c2ecf20Sopenharmony_ci if (!*timeo_p) 89768c2ecf20Sopenharmony_ci goto do_nonblock; 89778c2ecf20Sopenharmony_ci if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING) 89788c2ecf20Sopenharmony_ci goto do_error; 89798c2ecf20Sopenharmony_ci if (signal_pending(current)) 89808c2ecf20Sopenharmony_ci goto do_interrupted; 89818c2ecf20Sopenharmony_ci if (sk_under_memory_pressure(sk)) 89828c2ecf20Sopenharmony_ci sk_mem_reclaim(sk); 89838c2ecf20Sopenharmony_ci if ((int)msg_len <= sctp_wspace(asoc) && 89848c2ecf20Sopenharmony_ci sk_wmem_schedule(sk, msg_len)) 89858c2ecf20Sopenharmony_ci break; 89868c2ecf20Sopenharmony_ci 89878c2ecf20Sopenharmony_ci /* Let another process have a go. Since we are going 89888c2ecf20Sopenharmony_ci * to sleep anyway. 89898c2ecf20Sopenharmony_ci */ 89908c2ecf20Sopenharmony_ci release_sock(sk); 89918c2ecf20Sopenharmony_ci current_timeo = schedule_timeout(current_timeo); 89928c2ecf20Sopenharmony_ci lock_sock(sk); 89938c2ecf20Sopenharmony_ci if (sk != asoc->base.sk) 89948c2ecf20Sopenharmony_ci goto do_error; 89958c2ecf20Sopenharmony_ci 89968c2ecf20Sopenharmony_ci *timeo_p = current_timeo; 89978c2ecf20Sopenharmony_ci } 89988c2ecf20Sopenharmony_ci 89998c2ecf20Sopenharmony_ciout: 90008c2ecf20Sopenharmony_ci finish_wait(&asoc->wait, &wait); 90018c2ecf20Sopenharmony_ci 90028c2ecf20Sopenharmony_ci /* Release the association's refcnt. */ 90038c2ecf20Sopenharmony_ci sctp_association_put(asoc); 90048c2ecf20Sopenharmony_ci 90058c2ecf20Sopenharmony_ci return err; 90068c2ecf20Sopenharmony_ci 90078c2ecf20Sopenharmony_cido_dead: 90088c2ecf20Sopenharmony_ci err = -ESRCH; 90098c2ecf20Sopenharmony_ci goto out; 90108c2ecf20Sopenharmony_ci 90118c2ecf20Sopenharmony_cido_error: 90128c2ecf20Sopenharmony_ci err = -EPIPE; 90138c2ecf20Sopenharmony_ci goto out; 90148c2ecf20Sopenharmony_ci 90158c2ecf20Sopenharmony_cido_interrupted: 90168c2ecf20Sopenharmony_ci err = sock_intr_errno(*timeo_p); 90178c2ecf20Sopenharmony_ci goto out; 90188c2ecf20Sopenharmony_ci 90198c2ecf20Sopenharmony_cido_nonblock: 90208c2ecf20Sopenharmony_ci err = -EAGAIN; 90218c2ecf20Sopenharmony_ci goto out; 90228c2ecf20Sopenharmony_ci} 90238c2ecf20Sopenharmony_ci 90248c2ecf20Sopenharmony_civoid sctp_data_ready(struct sock *sk) 90258c2ecf20Sopenharmony_ci{ 90268c2ecf20Sopenharmony_ci struct socket_wq *wq; 90278c2ecf20Sopenharmony_ci 90288c2ecf20Sopenharmony_ci rcu_read_lock(); 90298c2ecf20Sopenharmony_ci wq = rcu_dereference(sk->sk_wq); 90308c2ecf20Sopenharmony_ci if (skwq_has_sleeper(wq)) 90318c2ecf20Sopenharmony_ci wake_up_interruptible_sync_poll(&wq->wait, EPOLLIN | 90328c2ecf20Sopenharmony_ci EPOLLRDNORM | EPOLLRDBAND); 90338c2ecf20Sopenharmony_ci sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); 90348c2ecf20Sopenharmony_ci rcu_read_unlock(); 90358c2ecf20Sopenharmony_ci} 90368c2ecf20Sopenharmony_ci 90378c2ecf20Sopenharmony_ci/* If socket sndbuf has changed, wake up all per association waiters. */ 90388c2ecf20Sopenharmony_civoid sctp_write_space(struct sock *sk) 90398c2ecf20Sopenharmony_ci{ 90408c2ecf20Sopenharmony_ci struct sctp_association *asoc; 90418c2ecf20Sopenharmony_ci 90428c2ecf20Sopenharmony_ci /* Wake up the tasks in each wait queue. */ 90438c2ecf20Sopenharmony_ci list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) { 90448c2ecf20Sopenharmony_ci __sctp_write_space(asoc); 90458c2ecf20Sopenharmony_ci } 90468c2ecf20Sopenharmony_ci} 90478c2ecf20Sopenharmony_ci 90488c2ecf20Sopenharmony_ci/* Is there any sndbuf space available on the socket? 90498c2ecf20Sopenharmony_ci * 90508c2ecf20Sopenharmony_ci * Note that sk_wmem_alloc is the sum of the send buffers on all of the 90518c2ecf20Sopenharmony_ci * associations on the same socket. For a UDP-style socket with 90528c2ecf20Sopenharmony_ci * multiple associations, it is possible for it to be "unwriteable" 90538c2ecf20Sopenharmony_ci * prematurely. I assume that this is acceptable because 90548c2ecf20Sopenharmony_ci * a premature "unwriteable" is better than an accidental "writeable" which 90558c2ecf20Sopenharmony_ci * would cause an unwanted block under certain circumstances. For the 1-1 90568c2ecf20Sopenharmony_ci * UDP-style sockets or TCP-style sockets, this code should work. 90578c2ecf20Sopenharmony_ci * - Daisy 90588c2ecf20Sopenharmony_ci */ 90598c2ecf20Sopenharmony_cistatic bool sctp_writeable(const struct sock *sk) 90608c2ecf20Sopenharmony_ci{ 90618c2ecf20Sopenharmony_ci return READ_ONCE(sk->sk_sndbuf) > READ_ONCE(sk->sk_wmem_queued); 90628c2ecf20Sopenharmony_ci} 90638c2ecf20Sopenharmony_ci 90648c2ecf20Sopenharmony_ci/* Wait for an association to go into ESTABLISHED state. If timeout is 0, 90658c2ecf20Sopenharmony_ci * returns immediately with EINPROGRESS. 90668c2ecf20Sopenharmony_ci */ 90678c2ecf20Sopenharmony_cistatic int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) 90688c2ecf20Sopenharmony_ci{ 90698c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 90708c2ecf20Sopenharmony_ci int err = 0; 90718c2ecf20Sopenharmony_ci long current_timeo = *timeo_p; 90728c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 90738c2ecf20Sopenharmony_ci 90748c2ecf20Sopenharmony_ci pr_debug("%s: asoc:%p, timeo:%ld\n", __func__, asoc, *timeo_p); 90758c2ecf20Sopenharmony_ci 90768c2ecf20Sopenharmony_ci /* Increment the association's refcnt. */ 90778c2ecf20Sopenharmony_ci sctp_association_hold(asoc); 90788c2ecf20Sopenharmony_ci 90798c2ecf20Sopenharmony_ci for (;;) { 90808c2ecf20Sopenharmony_ci prepare_to_wait_exclusive(&asoc->wait, &wait, 90818c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE); 90828c2ecf20Sopenharmony_ci if (!*timeo_p) 90838c2ecf20Sopenharmony_ci goto do_nonblock; 90848c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) 90858c2ecf20Sopenharmony_ci break; 90868c2ecf20Sopenharmony_ci if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || 90878c2ecf20Sopenharmony_ci asoc->base.dead) 90888c2ecf20Sopenharmony_ci goto do_error; 90898c2ecf20Sopenharmony_ci if (signal_pending(current)) 90908c2ecf20Sopenharmony_ci goto do_interrupted; 90918c2ecf20Sopenharmony_ci 90928c2ecf20Sopenharmony_ci if (sctp_state(asoc, ESTABLISHED)) 90938c2ecf20Sopenharmony_ci break; 90948c2ecf20Sopenharmony_ci 90958c2ecf20Sopenharmony_ci /* Let another process have a go. Since we are going 90968c2ecf20Sopenharmony_ci * to sleep anyway. 90978c2ecf20Sopenharmony_ci */ 90988c2ecf20Sopenharmony_ci release_sock(sk); 90998c2ecf20Sopenharmony_ci current_timeo = schedule_timeout(current_timeo); 91008c2ecf20Sopenharmony_ci lock_sock(sk); 91018c2ecf20Sopenharmony_ci 91028c2ecf20Sopenharmony_ci *timeo_p = current_timeo; 91038c2ecf20Sopenharmony_ci } 91048c2ecf20Sopenharmony_ci 91058c2ecf20Sopenharmony_ciout: 91068c2ecf20Sopenharmony_ci finish_wait(&asoc->wait, &wait); 91078c2ecf20Sopenharmony_ci 91088c2ecf20Sopenharmony_ci /* Release the association's refcnt. */ 91098c2ecf20Sopenharmony_ci sctp_association_put(asoc); 91108c2ecf20Sopenharmony_ci 91118c2ecf20Sopenharmony_ci return err; 91128c2ecf20Sopenharmony_ci 91138c2ecf20Sopenharmony_cido_error: 91148c2ecf20Sopenharmony_ci if (asoc->init_err_counter + 1 > asoc->max_init_attempts) 91158c2ecf20Sopenharmony_ci err = -ETIMEDOUT; 91168c2ecf20Sopenharmony_ci else 91178c2ecf20Sopenharmony_ci err = -ECONNREFUSED; 91188c2ecf20Sopenharmony_ci goto out; 91198c2ecf20Sopenharmony_ci 91208c2ecf20Sopenharmony_cido_interrupted: 91218c2ecf20Sopenharmony_ci err = sock_intr_errno(*timeo_p); 91228c2ecf20Sopenharmony_ci goto out; 91238c2ecf20Sopenharmony_ci 91248c2ecf20Sopenharmony_cido_nonblock: 91258c2ecf20Sopenharmony_ci err = -EINPROGRESS; 91268c2ecf20Sopenharmony_ci goto out; 91278c2ecf20Sopenharmony_ci} 91288c2ecf20Sopenharmony_ci 91298c2ecf20Sopenharmony_cistatic int sctp_wait_for_accept(struct sock *sk, long timeo) 91308c2ecf20Sopenharmony_ci{ 91318c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 91328c2ecf20Sopenharmony_ci int err = 0; 91338c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 91348c2ecf20Sopenharmony_ci 91358c2ecf20Sopenharmony_ci ep = sctp_sk(sk)->ep; 91368c2ecf20Sopenharmony_ci 91378c2ecf20Sopenharmony_ci 91388c2ecf20Sopenharmony_ci for (;;) { 91398c2ecf20Sopenharmony_ci prepare_to_wait_exclusive(sk_sleep(sk), &wait, 91408c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE); 91418c2ecf20Sopenharmony_ci 91428c2ecf20Sopenharmony_ci if (list_empty(&ep->asocs)) { 91438c2ecf20Sopenharmony_ci release_sock(sk); 91448c2ecf20Sopenharmony_ci timeo = schedule_timeout(timeo); 91458c2ecf20Sopenharmony_ci lock_sock(sk); 91468c2ecf20Sopenharmony_ci } 91478c2ecf20Sopenharmony_ci 91488c2ecf20Sopenharmony_ci err = -EINVAL; 91498c2ecf20Sopenharmony_ci if (!sctp_sstate(sk, LISTENING)) 91508c2ecf20Sopenharmony_ci break; 91518c2ecf20Sopenharmony_ci 91528c2ecf20Sopenharmony_ci err = 0; 91538c2ecf20Sopenharmony_ci if (!list_empty(&ep->asocs)) 91548c2ecf20Sopenharmony_ci break; 91558c2ecf20Sopenharmony_ci 91568c2ecf20Sopenharmony_ci err = sock_intr_errno(timeo); 91578c2ecf20Sopenharmony_ci if (signal_pending(current)) 91588c2ecf20Sopenharmony_ci break; 91598c2ecf20Sopenharmony_ci 91608c2ecf20Sopenharmony_ci err = -EAGAIN; 91618c2ecf20Sopenharmony_ci if (!timeo) 91628c2ecf20Sopenharmony_ci break; 91638c2ecf20Sopenharmony_ci } 91648c2ecf20Sopenharmony_ci 91658c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 91668c2ecf20Sopenharmony_ci 91678c2ecf20Sopenharmony_ci return err; 91688c2ecf20Sopenharmony_ci} 91698c2ecf20Sopenharmony_ci 91708c2ecf20Sopenharmony_cistatic void sctp_wait_for_close(struct sock *sk, long timeout) 91718c2ecf20Sopenharmony_ci{ 91728c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 91738c2ecf20Sopenharmony_ci 91748c2ecf20Sopenharmony_ci do { 91758c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 91768c2ecf20Sopenharmony_ci if (list_empty(&sctp_sk(sk)->ep->asocs)) 91778c2ecf20Sopenharmony_ci break; 91788c2ecf20Sopenharmony_ci release_sock(sk); 91798c2ecf20Sopenharmony_ci timeout = schedule_timeout(timeout); 91808c2ecf20Sopenharmony_ci lock_sock(sk); 91818c2ecf20Sopenharmony_ci } while (!signal_pending(current) && timeout); 91828c2ecf20Sopenharmony_ci 91838c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 91848c2ecf20Sopenharmony_ci} 91858c2ecf20Sopenharmony_ci 91868c2ecf20Sopenharmony_cistatic void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) 91878c2ecf20Sopenharmony_ci{ 91888c2ecf20Sopenharmony_ci struct sk_buff *frag; 91898c2ecf20Sopenharmony_ci 91908c2ecf20Sopenharmony_ci if (!skb->data_len) 91918c2ecf20Sopenharmony_ci goto done; 91928c2ecf20Sopenharmony_ci 91938c2ecf20Sopenharmony_ci /* Don't forget the fragments. */ 91948c2ecf20Sopenharmony_ci skb_walk_frags(skb, frag) 91958c2ecf20Sopenharmony_ci sctp_skb_set_owner_r_frag(frag, sk); 91968c2ecf20Sopenharmony_ci 91978c2ecf20Sopenharmony_cidone: 91988c2ecf20Sopenharmony_ci sctp_skb_set_owner_r(skb, sk); 91998c2ecf20Sopenharmony_ci} 92008c2ecf20Sopenharmony_ci 92018c2ecf20Sopenharmony_civoid sctp_copy_sock(struct sock *newsk, struct sock *sk, 92028c2ecf20Sopenharmony_ci struct sctp_association *asoc) 92038c2ecf20Sopenharmony_ci{ 92048c2ecf20Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 92058c2ecf20Sopenharmony_ci struct inet_sock *newinet; 92068c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 92078c2ecf20Sopenharmony_ci struct sctp_endpoint *ep = sp->ep; 92088c2ecf20Sopenharmony_ci 92098c2ecf20Sopenharmony_ci newsk->sk_type = sk->sk_type; 92108c2ecf20Sopenharmony_ci newsk->sk_bound_dev_if = sk->sk_bound_dev_if; 92118c2ecf20Sopenharmony_ci newsk->sk_flags = sk->sk_flags; 92128c2ecf20Sopenharmony_ci newsk->sk_tsflags = sk->sk_tsflags; 92138c2ecf20Sopenharmony_ci newsk->sk_no_check_tx = sk->sk_no_check_tx; 92148c2ecf20Sopenharmony_ci newsk->sk_no_check_rx = sk->sk_no_check_rx; 92158c2ecf20Sopenharmony_ci newsk->sk_reuse = sk->sk_reuse; 92168c2ecf20Sopenharmony_ci sctp_sk(newsk)->reuse = sp->reuse; 92178c2ecf20Sopenharmony_ci 92188c2ecf20Sopenharmony_ci newsk->sk_shutdown = sk->sk_shutdown; 92198c2ecf20Sopenharmony_ci newsk->sk_destruct = sk->sk_destruct; 92208c2ecf20Sopenharmony_ci newsk->sk_family = sk->sk_family; 92218c2ecf20Sopenharmony_ci newsk->sk_protocol = IPPROTO_SCTP; 92228c2ecf20Sopenharmony_ci newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; 92238c2ecf20Sopenharmony_ci newsk->sk_sndbuf = sk->sk_sndbuf; 92248c2ecf20Sopenharmony_ci newsk->sk_rcvbuf = sk->sk_rcvbuf; 92258c2ecf20Sopenharmony_ci newsk->sk_lingertime = sk->sk_lingertime; 92268c2ecf20Sopenharmony_ci newsk->sk_rcvtimeo = sk->sk_rcvtimeo; 92278c2ecf20Sopenharmony_ci newsk->sk_sndtimeo = sk->sk_sndtimeo; 92288c2ecf20Sopenharmony_ci newsk->sk_rxhash = sk->sk_rxhash; 92298c2ecf20Sopenharmony_ci 92308c2ecf20Sopenharmony_ci newinet = inet_sk(newsk); 92318c2ecf20Sopenharmony_ci 92328c2ecf20Sopenharmony_ci /* Initialize sk's sport, dport, rcv_saddr and daddr for 92338c2ecf20Sopenharmony_ci * getsockname() and getpeername() 92348c2ecf20Sopenharmony_ci */ 92358c2ecf20Sopenharmony_ci newinet->inet_sport = inet->inet_sport; 92368c2ecf20Sopenharmony_ci newinet->inet_saddr = inet->inet_saddr; 92378c2ecf20Sopenharmony_ci newinet->inet_rcv_saddr = inet->inet_rcv_saddr; 92388c2ecf20Sopenharmony_ci newinet->inet_dport = htons(asoc->peer.port); 92398c2ecf20Sopenharmony_ci newinet->pmtudisc = inet->pmtudisc; 92408c2ecf20Sopenharmony_ci newinet->inet_id = prandom_u32(); 92418c2ecf20Sopenharmony_ci 92428c2ecf20Sopenharmony_ci newinet->uc_ttl = inet->uc_ttl; 92438c2ecf20Sopenharmony_ci newinet->mc_loop = 1; 92448c2ecf20Sopenharmony_ci newinet->mc_ttl = 1; 92458c2ecf20Sopenharmony_ci newinet->mc_index = 0; 92468c2ecf20Sopenharmony_ci newinet->mc_list = NULL; 92478c2ecf20Sopenharmony_ci 92488c2ecf20Sopenharmony_ci if (newsk->sk_flags & SK_FLAGS_TIMESTAMP) 92498c2ecf20Sopenharmony_ci net_enable_timestamp(); 92508c2ecf20Sopenharmony_ci 92518c2ecf20Sopenharmony_ci /* Set newsk security attributes from orginal sk and connection 92528c2ecf20Sopenharmony_ci * security attribute from ep. 92538c2ecf20Sopenharmony_ci */ 92548c2ecf20Sopenharmony_ci security_sctp_sk_clone(ep, sk, newsk); 92558c2ecf20Sopenharmony_ci} 92568c2ecf20Sopenharmony_ci 92578c2ecf20Sopenharmony_cistatic inline void sctp_copy_descendant(struct sock *sk_to, 92588c2ecf20Sopenharmony_ci const struct sock *sk_from) 92598c2ecf20Sopenharmony_ci{ 92608c2ecf20Sopenharmony_ci size_t ancestor_size = sizeof(struct inet_sock); 92618c2ecf20Sopenharmony_ci 92628c2ecf20Sopenharmony_ci ancestor_size += sk_from->sk_prot->obj_size; 92638c2ecf20Sopenharmony_ci ancestor_size -= offsetof(struct sctp_sock, pd_lobby); 92648c2ecf20Sopenharmony_ci __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); 92658c2ecf20Sopenharmony_ci} 92668c2ecf20Sopenharmony_ci 92678c2ecf20Sopenharmony_ci/* Populate the fields of the newsk from the oldsk and migrate the assoc 92688c2ecf20Sopenharmony_ci * and its messages to the newsk. 92698c2ecf20Sopenharmony_ci */ 92708c2ecf20Sopenharmony_cistatic int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, 92718c2ecf20Sopenharmony_ci struct sctp_association *assoc, 92728c2ecf20Sopenharmony_ci enum sctp_socket_type type) 92738c2ecf20Sopenharmony_ci{ 92748c2ecf20Sopenharmony_ci struct sctp_sock *oldsp = sctp_sk(oldsk); 92758c2ecf20Sopenharmony_ci struct sctp_sock *newsp = sctp_sk(newsk); 92768c2ecf20Sopenharmony_ci struct sctp_bind_bucket *pp; /* hash list port iterator */ 92778c2ecf20Sopenharmony_ci struct sctp_endpoint *newep = newsp->ep; 92788c2ecf20Sopenharmony_ci struct sk_buff *skb, *tmp; 92798c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 92808c2ecf20Sopenharmony_ci struct sctp_bind_hashbucket *head; 92818c2ecf20Sopenharmony_ci int err; 92828c2ecf20Sopenharmony_ci 92838c2ecf20Sopenharmony_ci /* Migrate socket buffer sizes and all the socket level options to the 92848c2ecf20Sopenharmony_ci * new socket. 92858c2ecf20Sopenharmony_ci */ 92868c2ecf20Sopenharmony_ci newsk->sk_sndbuf = oldsk->sk_sndbuf; 92878c2ecf20Sopenharmony_ci newsk->sk_rcvbuf = oldsk->sk_rcvbuf; 92888c2ecf20Sopenharmony_ci /* Brute force copy old sctp opt. */ 92898c2ecf20Sopenharmony_ci sctp_copy_descendant(newsk, oldsk); 92908c2ecf20Sopenharmony_ci 92918c2ecf20Sopenharmony_ci /* Restore the ep value that was overwritten with the above structure 92928c2ecf20Sopenharmony_ci * copy. 92938c2ecf20Sopenharmony_ci */ 92948c2ecf20Sopenharmony_ci newsp->ep = newep; 92958c2ecf20Sopenharmony_ci newsp->hmac = NULL; 92968c2ecf20Sopenharmony_ci 92978c2ecf20Sopenharmony_ci /* Hook this new socket in to the bind_hash list. */ 92988c2ecf20Sopenharmony_ci head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk), 92998c2ecf20Sopenharmony_ci inet_sk(oldsk)->inet_num)]; 93008c2ecf20Sopenharmony_ci spin_lock_bh(&head->lock); 93018c2ecf20Sopenharmony_ci pp = sctp_sk(oldsk)->bind_hash; 93028c2ecf20Sopenharmony_ci sk_add_bind_node(newsk, &pp->owner); 93038c2ecf20Sopenharmony_ci sctp_sk(newsk)->bind_hash = pp; 93048c2ecf20Sopenharmony_ci inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num; 93058c2ecf20Sopenharmony_ci spin_unlock_bh(&head->lock); 93068c2ecf20Sopenharmony_ci 93078c2ecf20Sopenharmony_ci /* Copy the bind_addr list from the original endpoint to the new 93088c2ecf20Sopenharmony_ci * endpoint so that we can handle restarts properly 93098c2ecf20Sopenharmony_ci */ 93108c2ecf20Sopenharmony_ci err = sctp_bind_addr_dup(&newsp->ep->base.bind_addr, 93118c2ecf20Sopenharmony_ci &oldsp->ep->base.bind_addr, GFP_KERNEL); 93128c2ecf20Sopenharmony_ci if (err) 93138c2ecf20Sopenharmony_ci return err; 93148c2ecf20Sopenharmony_ci 93158c2ecf20Sopenharmony_ci /* New ep's auth_hmacs should be set if old ep's is set, in case 93168c2ecf20Sopenharmony_ci * that net->sctp.auth_enable has been changed to 0 by users and 93178c2ecf20Sopenharmony_ci * new ep's auth_hmacs couldn't be set in sctp_endpoint_init(). 93188c2ecf20Sopenharmony_ci */ 93198c2ecf20Sopenharmony_ci if (oldsp->ep->auth_hmacs) { 93208c2ecf20Sopenharmony_ci err = sctp_auth_init_hmacs(newsp->ep, GFP_KERNEL); 93218c2ecf20Sopenharmony_ci if (err) 93228c2ecf20Sopenharmony_ci return err; 93238c2ecf20Sopenharmony_ci } 93248c2ecf20Sopenharmony_ci 93258c2ecf20Sopenharmony_ci sctp_auto_asconf_init(newsp); 93268c2ecf20Sopenharmony_ci 93278c2ecf20Sopenharmony_ci /* Move any messages in the old socket's receive queue that are for the 93288c2ecf20Sopenharmony_ci * peeled off association to the new socket's receive queue. 93298c2ecf20Sopenharmony_ci */ 93308c2ecf20Sopenharmony_ci sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { 93318c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 93328c2ecf20Sopenharmony_ci if (event->asoc == assoc) { 93338c2ecf20Sopenharmony_ci __skb_unlink(skb, &oldsk->sk_receive_queue); 93348c2ecf20Sopenharmony_ci __skb_queue_tail(&newsk->sk_receive_queue, skb); 93358c2ecf20Sopenharmony_ci sctp_skb_set_owner_r_frag(skb, newsk); 93368c2ecf20Sopenharmony_ci } 93378c2ecf20Sopenharmony_ci } 93388c2ecf20Sopenharmony_ci 93398c2ecf20Sopenharmony_ci /* Clean up any messages pending delivery due to partial 93408c2ecf20Sopenharmony_ci * delivery. Three cases: 93418c2ecf20Sopenharmony_ci * 1) No partial deliver; no work. 93428c2ecf20Sopenharmony_ci * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby. 93438c2ecf20Sopenharmony_ci * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue. 93448c2ecf20Sopenharmony_ci */ 93458c2ecf20Sopenharmony_ci atomic_set(&sctp_sk(newsk)->pd_mode, assoc->ulpq.pd_mode); 93468c2ecf20Sopenharmony_ci 93478c2ecf20Sopenharmony_ci if (atomic_read(&sctp_sk(oldsk)->pd_mode)) { 93488c2ecf20Sopenharmony_ci struct sk_buff_head *queue; 93498c2ecf20Sopenharmony_ci 93508c2ecf20Sopenharmony_ci /* Decide which queue to move pd_lobby skbs to. */ 93518c2ecf20Sopenharmony_ci if (assoc->ulpq.pd_mode) { 93528c2ecf20Sopenharmony_ci queue = &newsp->pd_lobby; 93538c2ecf20Sopenharmony_ci } else 93548c2ecf20Sopenharmony_ci queue = &newsk->sk_receive_queue; 93558c2ecf20Sopenharmony_ci 93568c2ecf20Sopenharmony_ci /* Walk through the pd_lobby, looking for skbs that 93578c2ecf20Sopenharmony_ci * need moved to the new socket. 93588c2ecf20Sopenharmony_ci */ 93598c2ecf20Sopenharmony_ci sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { 93608c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 93618c2ecf20Sopenharmony_ci if (event->asoc == assoc) { 93628c2ecf20Sopenharmony_ci __skb_unlink(skb, &oldsp->pd_lobby); 93638c2ecf20Sopenharmony_ci __skb_queue_tail(queue, skb); 93648c2ecf20Sopenharmony_ci sctp_skb_set_owner_r_frag(skb, newsk); 93658c2ecf20Sopenharmony_ci } 93668c2ecf20Sopenharmony_ci } 93678c2ecf20Sopenharmony_ci 93688c2ecf20Sopenharmony_ci /* Clear up any skbs waiting for the partial 93698c2ecf20Sopenharmony_ci * delivery to finish. 93708c2ecf20Sopenharmony_ci */ 93718c2ecf20Sopenharmony_ci if (assoc->ulpq.pd_mode) 93728c2ecf20Sopenharmony_ci sctp_clear_pd(oldsk, NULL); 93738c2ecf20Sopenharmony_ci 93748c2ecf20Sopenharmony_ci } 93758c2ecf20Sopenharmony_ci 93768c2ecf20Sopenharmony_ci sctp_for_each_rx_skb(assoc, newsk, sctp_skb_set_owner_r_frag); 93778c2ecf20Sopenharmony_ci 93788c2ecf20Sopenharmony_ci /* Set the type of socket to indicate that it is peeled off from the 93798c2ecf20Sopenharmony_ci * original UDP-style socket or created with the accept() call on a 93808c2ecf20Sopenharmony_ci * TCP-style socket.. 93818c2ecf20Sopenharmony_ci */ 93828c2ecf20Sopenharmony_ci newsp->type = type; 93838c2ecf20Sopenharmony_ci 93848c2ecf20Sopenharmony_ci /* Mark the new socket "in-use" by the user so that any packets 93858c2ecf20Sopenharmony_ci * that may arrive on the association after we've moved it are 93868c2ecf20Sopenharmony_ci * queued to the backlog. This prevents a potential race between 93878c2ecf20Sopenharmony_ci * backlog processing on the old socket and new-packet processing 93888c2ecf20Sopenharmony_ci * on the new socket. 93898c2ecf20Sopenharmony_ci * 93908c2ecf20Sopenharmony_ci * The caller has just allocated newsk so we can guarantee that other 93918c2ecf20Sopenharmony_ci * paths won't try to lock it and then oldsk. 93928c2ecf20Sopenharmony_ci */ 93938c2ecf20Sopenharmony_ci lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); 93948c2ecf20Sopenharmony_ci sctp_for_each_tx_datachunk(assoc, true, sctp_clear_owner_w); 93958c2ecf20Sopenharmony_ci sctp_assoc_migrate(assoc, newsk); 93968c2ecf20Sopenharmony_ci sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w); 93978c2ecf20Sopenharmony_ci 93988c2ecf20Sopenharmony_ci /* If the association on the newsk is already closed before accept() 93998c2ecf20Sopenharmony_ci * is called, set RCV_SHUTDOWN flag. 94008c2ecf20Sopenharmony_ci */ 94018c2ecf20Sopenharmony_ci if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) { 94028c2ecf20Sopenharmony_ci inet_sk_set_state(newsk, SCTP_SS_CLOSED); 94038c2ecf20Sopenharmony_ci newsk->sk_shutdown |= RCV_SHUTDOWN; 94048c2ecf20Sopenharmony_ci } else { 94058c2ecf20Sopenharmony_ci inet_sk_set_state(newsk, SCTP_SS_ESTABLISHED); 94068c2ecf20Sopenharmony_ci } 94078c2ecf20Sopenharmony_ci 94088c2ecf20Sopenharmony_ci release_sock(newsk); 94098c2ecf20Sopenharmony_ci 94108c2ecf20Sopenharmony_ci return 0; 94118c2ecf20Sopenharmony_ci} 94128c2ecf20Sopenharmony_ci 94138c2ecf20Sopenharmony_ci 94148c2ecf20Sopenharmony_ci/* This proto struct describes the ULP interface for SCTP. */ 94158c2ecf20Sopenharmony_cistruct proto sctp_prot = { 94168c2ecf20Sopenharmony_ci .name = "SCTP", 94178c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 94188c2ecf20Sopenharmony_ci .close = sctp_close, 94198c2ecf20Sopenharmony_ci .disconnect = sctp_disconnect, 94208c2ecf20Sopenharmony_ci .accept = sctp_accept, 94218c2ecf20Sopenharmony_ci .ioctl = sctp_ioctl, 94228c2ecf20Sopenharmony_ci .init = sctp_init_sock, 94238c2ecf20Sopenharmony_ci .destroy = sctp_destroy_sock, 94248c2ecf20Sopenharmony_ci .shutdown = sctp_shutdown, 94258c2ecf20Sopenharmony_ci .setsockopt = sctp_setsockopt, 94268c2ecf20Sopenharmony_ci .getsockopt = sctp_getsockopt, 94278c2ecf20Sopenharmony_ci .bpf_bypass_getsockopt = sctp_bpf_bypass_getsockopt, 94288c2ecf20Sopenharmony_ci .sendmsg = sctp_sendmsg, 94298c2ecf20Sopenharmony_ci .recvmsg = sctp_recvmsg, 94308c2ecf20Sopenharmony_ci .bind = sctp_bind, 94318c2ecf20Sopenharmony_ci .bind_add = sctp_bind_add, 94328c2ecf20Sopenharmony_ci .backlog_rcv = sctp_backlog_rcv, 94338c2ecf20Sopenharmony_ci .hash = sctp_hash, 94348c2ecf20Sopenharmony_ci .unhash = sctp_unhash, 94358c2ecf20Sopenharmony_ci .no_autobind = true, 94368c2ecf20Sopenharmony_ci .obj_size = sizeof(struct sctp_sock), 94378c2ecf20Sopenharmony_ci .useroffset = offsetof(struct sctp_sock, subscribe), 94388c2ecf20Sopenharmony_ci .usersize = offsetof(struct sctp_sock, initmsg) - 94398c2ecf20Sopenharmony_ci offsetof(struct sctp_sock, subscribe) + 94408c2ecf20Sopenharmony_ci sizeof_field(struct sctp_sock, initmsg), 94418c2ecf20Sopenharmony_ci .sysctl_mem = sysctl_sctp_mem, 94428c2ecf20Sopenharmony_ci .sysctl_rmem = sysctl_sctp_rmem, 94438c2ecf20Sopenharmony_ci .sysctl_wmem = sysctl_sctp_wmem, 94448c2ecf20Sopenharmony_ci .memory_pressure = &sctp_memory_pressure, 94458c2ecf20Sopenharmony_ci .enter_memory_pressure = sctp_enter_memory_pressure, 94468c2ecf20Sopenharmony_ci .memory_allocated = &sctp_memory_allocated, 94478c2ecf20Sopenharmony_ci .sockets_allocated = &sctp_sockets_allocated, 94488c2ecf20Sopenharmony_ci}; 94498c2ecf20Sopenharmony_ci 94508c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 94518c2ecf20Sopenharmony_ci 94528c2ecf20Sopenharmony_cistatic void sctp_v6_destruct_sock(struct sock *sk) 94538c2ecf20Sopenharmony_ci{ 94548c2ecf20Sopenharmony_ci sctp_destruct_common(sk); 94558c2ecf20Sopenharmony_ci inet6_sock_destruct(sk); 94568c2ecf20Sopenharmony_ci} 94578c2ecf20Sopenharmony_ci 94588c2ecf20Sopenharmony_cistatic int sctp_v6_init_sock(struct sock *sk) 94598c2ecf20Sopenharmony_ci{ 94608c2ecf20Sopenharmony_ci int ret = sctp_init_sock(sk); 94618c2ecf20Sopenharmony_ci 94628c2ecf20Sopenharmony_ci if (!ret) 94638c2ecf20Sopenharmony_ci sk->sk_destruct = sctp_v6_destruct_sock; 94648c2ecf20Sopenharmony_ci 94658c2ecf20Sopenharmony_ci return ret; 94668c2ecf20Sopenharmony_ci} 94678c2ecf20Sopenharmony_ci 94688c2ecf20Sopenharmony_cistruct proto sctpv6_prot = { 94698c2ecf20Sopenharmony_ci .name = "SCTPv6", 94708c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 94718c2ecf20Sopenharmony_ci .close = sctp_close, 94728c2ecf20Sopenharmony_ci .disconnect = sctp_disconnect, 94738c2ecf20Sopenharmony_ci .accept = sctp_accept, 94748c2ecf20Sopenharmony_ci .ioctl = sctp_ioctl, 94758c2ecf20Sopenharmony_ci .init = sctp_v6_init_sock, 94768c2ecf20Sopenharmony_ci .destroy = sctp_destroy_sock, 94778c2ecf20Sopenharmony_ci .shutdown = sctp_shutdown, 94788c2ecf20Sopenharmony_ci .setsockopt = sctp_setsockopt, 94798c2ecf20Sopenharmony_ci .getsockopt = sctp_getsockopt, 94808c2ecf20Sopenharmony_ci .bpf_bypass_getsockopt = sctp_bpf_bypass_getsockopt, 94818c2ecf20Sopenharmony_ci .sendmsg = sctp_sendmsg, 94828c2ecf20Sopenharmony_ci .recvmsg = sctp_recvmsg, 94838c2ecf20Sopenharmony_ci .bind = sctp_bind, 94848c2ecf20Sopenharmony_ci .bind_add = sctp_bind_add, 94858c2ecf20Sopenharmony_ci .backlog_rcv = sctp_backlog_rcv, 94868c2ecf20Sopenharmony_ci .hash = sctp_hash, 94878c2ecf20Sopenharmony_ci .unhash = sctp_unhash, 94888c2ecf20Sopenharmony_ci .no_autobind = true, 94898c2ecf20Sopenharmony_ci .obj_size = sizeof(struct sctp6_sock), 94908c2ecf20Sopenharmony_ci .useroffset = offsetof(struct sctp6_sock, sctp.subscribe), 94918c2ecf20Sopenharmony_ci .usersize = offsetof(struct sctp6_sock, sctp.initmsg) - 94928c2ecf20Sopenharmony_ci offsetof(struct sctp6_sock, sctp.subscribe) + 94938c2ecf20Sopenharmony_ci sizeof_field(struct sctp6_sock, sctp.initmsg), 94948c2ecf20Sopenharmony_ci .sysctl_mem = sysctl_sctp_mem, 94958c2ecf20Sopenharmony_ci .sysctl_rmem = sysctl_sctp_rmem, 94968c2ecf20Sopenharmony_ci .sysctl_wmem = sysctl_sctp_wmem, 94978c2ecf20Sopenharmony_ci .memory_pressure = &sctp_memory_pressure, 94988c2ecf20Sopenharmony_ci .enter_memory_pressure = sctp_enter_memory_pressure, 94998c2ecf20Sopenharmony_ci .memory_allocated = &sctp_memory_allocated, 95008c2ecf20Sopenharmony_ci .sockets_allocated = &sctp_sockets_allocated, 95018c2ecf20Sopenharmony_ci}; 95028c2ecf20Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_IPV6) */ 9503