160c778b2SVlad Yasevich /* SCTP kernel implementation 21da177e4SLinus Torvalds * (C) Copyright IBM Corp. 2001, 2004 31da177e4SLinus Torvalds * Copyright (c) 1999-2000 Cisco, Inc. 41da177e4SLinus Torvalds * Copyright (c) 1999-2001 Motorola, Inc. 51da177e4SLinus Torvalds * Copyright (c) 2001-2003 Intel Corp. 61da177e4SLinus Torvalds * Copyright (c) 2001-2002 Nokia, Inc. 71da177e4SLinus Torvalds * Copyright (c) 2001 La Monte H.P. Yarroll 81da177e4SLinus Torvalds * 960c778b2SVlad Yasevich * This file is part of the SCTP kernel implementation 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * These functions interface with the sockets layer to implement the 121da177e4SLinus Torvalds * SCTP Extensions for the Sockets API. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * Note that the descriptions from the specification are USER level 151da177e4SLinus Torvalds * functions--this file is the functions which populate the struct proto 161da177e4SLinus Torvalds * for SCTP which is the BOTTOM of the sockets interface. 171da177e4SLinus Torvalds * 1860c778b2SVlad Yasevich * This SCTP implementation is free software; 191da177e4SLinus Torvalds * you can redistribute it and/or modify it under the terms of 201da177e4SLinus Torvalds * the GNU General Public License as published by 211da177e4SLinus Torvalds * the Free Software Foundation; either version 2, or (at your option) 221da177e4SLinus Torvalds * any later version. 231da177e4SLinus Torvalds * 2460c778b2SVlad Yasevich * This SCTP implementation is distributed in the hope that it 251da177e4SLinus Torvalds * will be useful, but WITHOUT ANY WARRANTY; without even the implied 261da177e4SLinus Torvalds * ************************ 271da177e4SLinus Torvalds * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 281da177e4SLinus Torvalds * See the GNU General Public License for more details. 291da177e4SLinus Torvalds * 301da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 314b2f13a2SJeff Kirsher * along with GNU CC; see the file COPYING. If not, see 324b2f13a2SJeff Kirsher * <http://www.gnu.org/licenses/>. 331da177e4SLinus Torvalds * 341da177e4SLinus Torvalds * Please send any bug reports or fixes you make to the 351da177e4SLinus Torvalds * email address(es): 3691705c61SDaniel Borkmann * lksctp developers <linux-sctp@vger.kernel.org> 371da177e4SLinus Torvalds * 381da177e4SLinus Torvalds * Written or modified by: 391da177e4SLinus Torvalds * La Monte H.P. Yarroll <piggy@acm.org> 401da177e4SLinus Torvalds * Narasimha Budihal <narsi@refcode.org> 411da177e4SLinus Torvalds * Karl Knutson <karl@athena.chicago.il.us> 421da177e4SLinus Torvalds * Jon Grimm <jgrimm@us.ibm.com> 431da177e4SLinus Torvalds * Xingang Guo <xingang.guo@intel.com> 441da177e4SLinus Torvalds * Daisy Chang <daisyc@us.ibm.com> 451da177e4SLinus Torvalds * Sridhar Samudrala <samudrala@us.ibm.com> 461da177e4SLinus Torvalds * Inaky Perez-Gonzalez <inaky.gonzalez@intel.com> 471da177e4SLinus Torvalds * Ardelle Fan <ardelle.fan@intel.com> 481da177e4SLinus Torvalds * Ryan Layer <rmlayer@us.ibm.com> 491da177e4SLinus Torvalds * Anup Pemmaiah <pemmaiah@cc.usu.edu> 501da177e4SLinus Torvalds * Kevin Gao <kevin.gao@intel.com> 511da177e4SLinus Torvalds */ 521da177e4SLinus Torvalds 53145ce502SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 54145ce502SJoe Perches 555821c769SHerbert Xu #include <crypto/hash.h> 561da177e4SLinus Torvalds #include <linux/types.h> 571da177e4SLinus Torvalds #include <linux/kernel.h> 581da177e4SLinus Torvalds #include <linux/wait.h> 591da177e4SLinus Torvalds #include <linux/time.h> 603f07c014SIngo Molnar #include <linux/sched/signal.h> 611da177e4SLinus Torvalds #include <linux/ip.h> 624fc268d2SRandy Dunlap #include <linux/capability.h> 631da177e4SLinus Torvalds #include <linux/fcntl.h> 641da177e4SLinus Torvalds #include <linux/poll.h> 651da177e4SLinus Torvalds #include <linux/init.h> 665a0e3ad6STejun Heo #include <linux/slab.h> 6756b31d1cSAl Viro #include <linux/file.h> 68ffd59393SDaniel Borkmann #include <linux/compat.h> 690eb71a9dSNeilBrown #include <linux/rhashtable.h> 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds #include <net/ip.h> 721da177e4SLinus Torvalds #include <net/icmp.h> 731da177e4SLinus Torvalds #include <net/route.h> 741da177e4SLinus Torvalds #include <net/ipv6.h> 751da177e4SLinus Torvalds #include <net/inet_common.h> 768465a5fcSNeil Horman #include <net/busy_poll.h> 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds #include <linux/socket.h> /* for sa_family_t */ 79bc3b2d7fSPaul Gortmaker #include <linux/export.h> 801da177e4SLinus Torvalds #include <net/sock.h> 811da177e4SLinus Torvalds #include <net/sctp/sctp.h> 821da177e4SLinus Torvalds #include <net/sctp/sm.h> 8313aa8770SMarcelo Ricardo Leitner #include <net/sctp/stream_sched.h> 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* Forward declarations for internal helper functions. */ 861da177e4SLinus Torvalds static int sctp_writeable(struct sock *sk); 871da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb); 88cea0cc80SXin Long static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 89a0ff6600SXin Long size_t msg_len); 901da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p); 911da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); 921da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo); 931da177e4SLinus Torvalds static void sctp_wait_for_close(struct sock *sk, long timeo); 940a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk); 951da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, 961da177e4SLinus Torvalds union sctp_addr *addr, int len); 971da177e4SLinus Torvalds static int sctp_bindx_add(struct sock *, struct sockaddr *, int); 981da177e4SLinus Torvalds static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); 991da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); 1001da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int); 1011da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc, 1021da177e4SLinus Torvalds struct sctp_chunk *chunk); 1031da177e4SLinus Torvalds static int sctp_do_bind(struct sock *, union sctp_addr *, int); 1041da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk); 105b7ef2618SXin Long static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, 106b7ef2618SXin Long struct sctp_association *assoc, 107b7ef2618SXin Long enum sctp_socket_type type); 1081da177e4SLinus Torvalds 10906044751SEric Dumazet static unsigned long sctp_memory_pressure; 1108d987e5cSEric Dumazet static atomic_long_t sctp_memory_allocated; 1111748376bSEric Dumazet struct percpu_counter sctp_sockets_allocated; 1124d93df0aSNeil Horman 1135c52ba17SPavel Emelyanov static void sctp_enter_memory_pressure(struct sock *sk) 1144d93df0aSNeil Horman { 1154d93df0aSNeil Horman sctp_memory_pressure = 1; 1164d93df0aSNeil Horman } 1174d93df0aSNeil Horman 1184d93df0aSNeil Horman 1191da177e4SLinus Torvalds /* Get the sndbuf space available at the time on the association. */ 1201da177e4SLinus Torvalds static inline int sctp_wspace(struct sctp_association *asoc) 1211da177e4SLinus Torvalds { 1224d93df0aSNeil Horman int amt; 1231da177e4SLinus Torvalds 1244d93df0aSNeil Horman if (asoc->ep->sndbuf_policy) 1254d93df0aSNeil Horman amt = asoc->sndbuf_used; 1264d93df0aSNeil Horman else 12731e6d363SEric Dumazet amt = sk_wmem_alloc_get(asoc->base.sk); 1284eb701dfSNeil Horman 1294d93df0aSNeil Horman if (amt >= asoc->base.sk->sk_sndbuf) { 1304d93df0aSNeil Horman if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK) 1314d93df0aSNeil Horman amt = 0; 1324d93df0aSNeil Horman else { 1334d93df0aSNeil Horman amt = sk_stream_wspace(asoc->base.sk); 1341da177e4SLinus Torvalds if (amt < 0) 1351da177e4SLinus Torvalds amt = 0; 1364d93df0aSNeil Horman } 1374d93df0aSNeil Horman } else { 1384d93df0aSNeil Horman amt = asoc->base.sk->sk_sndbuf - amt; 1394d93df0aSNeil Horman } 1401da177e4SLinus Torvalds return amt; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds /* Increment the used sndbuf space count of the corresponding association by 1441da177e4SLinus Torvalds * the size of the outgoing data chunk. 1451da177e4SLinus Torvalds * Also, set the skb destructor for sndbuf accounting later. 1461da177e4SLinus Torvalds * 1471da177e4SLinus Torvalds * Since it is always 1-1 between chunk and skb, and also a new skb is always 1481da177e4SLinus Torvalds * allocated for chunk bundling in sctp_packet_transmit(), we can use the 1491da177e4SLinus Torvalds * destructor in the data chunk skb for the purpose of the sndbuf space 1501da177e4SLinus Torvalds * tracking. 1511da177e4SLinus Torvalds */ 1521da177e4SLinus Torvalds static inline void sctp_set_owner_w(struct sctp_chunk *chunk) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds struct sctp_association *asoc = chunk->asoc; 1551da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds /* The sndbuf space is tracked per association. */ 1581da177e4SLinus Torvalds sctp_association_hold(asoc); 1591da177e4SLinus Torvalds 1601b1e0bc9SXin Long if (chunk->shkey) 1611b1e0bc9SXin Long sctp_auth_shkey_hold(chunk->shkey); 1621b1e0bc9SXin Long 1634eb701dfSNeil Horman skb_set_owner_w(chunk->skb, sk); 1644eb701dfSNeil Horman 1651da177e4SLinus Torvalds chunk->skb->destructor = sctp_wfree; 1661da177e4SLinus Torvalds /* Save the chunk pointer in skb for sctp_wfree to use later. */ 167f869c912SDaniel Borkmann skb_shinfo(chunk->skb)->destructor_arg = chunk; 1681da177e4SLinus Torvalds 1694eb701dfSNeil Horman asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) + 1704eb701dfSNeil Horman sizeof(struct sk_buff) + 1714eb701dfSNeil Horman sizeof(struct sctp_chunk); 1724eb701dfSNeil Horman 17314afee4bSReshetova, Elena refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); 1743ab224beSHideo Aoki sk->sk_wmem_queued += chunk->skb->truesize; 1753ab224beSHideo Aoki sk_mem_charge(sk, chunk->skb->truesize); 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 178d04adf1bSXin Long static void sctp_clear_owner_w(struct sctp_chunk *chunk) 179d04adf1bSXin Long { 180d04adf1bSXin Long skb_orphan(chunk->skb); 181d04adf1bSXin Long } 182d04adf1bSXin Long 183d04adf1bSXin Long static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, 184d04adf1bSXin Long void (*cb)(struct sctp_chunk *)) 185d04adf1bSXin Long 186d04adf1bSXin Long { 187d04adf1bSXin Long struct sctp_outq *q = &asoc->outqueue; 188d04adf1bSXin Long struct sctp_transport *t; 189d04adf1bSXin Long struct sctp_chunk *chunk; 190d04adf1bSXin Long 191d04adf1bSXin Long list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) 192d04adf1bSXin Long list_for_each_entry(chunk, &t->transmitted, transmitted_list) 193d04adf1bSXin Long cb(chunk); 194d04adf1bSXin Long 195a8dd3979SXin Long list_for_each_entry(chunk, &q->retransmit, transmitted_list) 196d04adf1bSXin Long cb(chunk); 197d04adf1bSXin Long 198a8dd3979SXin Long list_for_each_entry(chunk, &q->sacked, transmitted_list) 199d04adf1bSXin Long cb(chunk); 200d04adf1bSXin Long 201a8dd3979SXin Long list_for_each_entry(chunk, &q->abandoned, transmitted_list) 202d04adf1bSXin Long cb(chunk); 203d04adf1bSXin Long 204d04adf1bSXin Long list_for_each_entry(chunk, &q->out_chunk_list, list) 205d04adf1bSXin Long cb(chunk); 206d04adf1bSXin Long } 207d04adf1bSXin Long 20813228238SXin Long static void sctp_for_each_rx_skb(struct sctp_association *asoc, struct sock *sk, 20913228238SXin Long void (*cb)(struct sk_buff *, struct sock *)) 21013228238SXin Long 21113228238SXin Long { 21213228238SXin Long struct sk_buff *skb, *tmp; 21313228238SXin Long 21413228238SXin Long sctp_skb_for_each(skb, &asoc->ulpq.lobby, tmp) 21513228238SXin Long cb(skb, sk); 21613228238SXin Long 21713228238SXin Long sctp_skb_for_each(skb, &asoc->ulpq.reasm, tmp) 21813228238SXin Long cb(skb, sk); 21913228238SXin Long 22013228238SXin Long sctp_skb_for_each(skb, &asoc->ulpq.reasm_uo, tmp) 22113228238SXin Long cb(skb, sk); 22213228238SXin Long } 22313228238SXin Long 2241da177e4SLinus Torvalds /* Verify that this is a valid address. */ 2251da177e4SLinus Torvalds static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, 2261da177e4SLinus Torvalds int len) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds struct sctp_af *af; 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds /* Verify basic sockaddr. */ 2311da177e4SLinus Torvalds af = sctp_sockaddr_af(sctp_sk(sk), addr, len); 2321da177e4SLinus Torvalds if (!af) 2331da177e4SLinus Torvalds return -EINVAL; 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds /* Is this a valid SCTP address? */ 2365636bef7SVlad Yasevich if (!af->addr_valid(addr, sctp_sk(sk), NULL)) 2371da177e4SLinus Torvalds return -EINVAL; 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) 2401da177e4SLinus Torvalds return -EINVAL; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds return 0; 2431da177e4SLinus Torvalds } 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds /* Look up the association by its id. If this is not a UDP-style 2461da177e4SLinus Torvalds * socket, the ID field is always ignored. 2471da177e4SLinus Torvalds */ 2481da177e4SLinus Torvalds struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) 2491da177e4SLinus Torvalds { 2501da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds /* If this is not a UDP-style socket, assoc id should be ignored. */ 2531da177e4SLinus Torvalds if (!sctp_style(sk, UDP)) { 2541da177e4SLinus Torvalds /* Return NULL if the socket state is not ESTABLISHED. It 2551da177e4SLinus Torvalds * could be a TCP-style listening socket or a socket which 2561da177e4SLinus Torvalds * hasn't yet called connect() to establish an association. 2571da177e4SLinus Torvalds */ 258e5b13f34SMarcelo Ricardo Leitner if (!sctp_sstate(sk, ESTABLISHED) && !sctp_sstate(sk, CLOSING)) 2591da177e4SLinus Torvalds return NULL; 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds /* Get the first and the only association from the list. */ 2621da177e4SLinus Torvalds if (!list_empty(&sctp_sk(sk)->ep->asocs)) 2631da177e4SLinus Torvalds asoc = list_entry(sctp_sk(sk)->ep->asocs.next, 2641da177e4SLinus Torvalds struct sctp_association, asocs); 2651da177e4SLinus Torvalds return asoc; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds /* Otherwise this is a UDP-style socket. */ 2691da177e4SLinus Torvalds if (!id || (id == (sctp_assoc_t)-1)) 2701da177e4SLinus Torvalds return NULL; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds spin_lock_bh(&sctp_assocs_id_lock); 2731da177e4SLinus Torvalds asoc = (struct sctp_association *)idr_find(&sctp_assocs_id, (int)id); 2741da177e4SLinus Torvalds spin_unlock_bh(&sctp_assocs_id_lock); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds if (!asoc || (asoc->base.sk != sk) || asoc->base.dead) 2771da177e4SLinus Torvalds return NULL; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds return asoc; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds /* Look up the transport from an address and an assoc id. If both address and 2831da177e4SLinus Torvalds * id are specified, the associations matching the address and the id should be 2841da177e4SLinus Torvalds * the same. 2851da177e4SLinus Torvalds */ 2861da177e4SLinus Torvalds static struct sctp_transport *sctp_addr_id2transport(struct sock *sk, 2871da177e4SLinus Torvalds struct sockaddr_storage *addr, 2881da177e4SLinus Torvalds sctp_assoc_t id) 2891da177e4SLinus Torvalds { 2901da177e4SLinus Torvalds struct sctp_association *addr_asoc = NULL, *id_asoc = NULL; 2916f29a130SXin Long struct sctp_af *af = sctp_get_af_specific(addr->ss_family); 2921da177e4SLinus Torvalds union sctp_addr *laddr = (union sctp_addr *)addr; 2936f29a130SXin Long struct sctp_transport *transport; 2946f29a130SXin Long 295912964eaSXin Long if (!af || sctp_verify_addr(sk, laddr, af->sockaddr_len)) 2966f29a130SXin Long return NULL; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep, 299cd4ff034SAl Viro laddr, 3001da177e4SLinus Torvalds &transport); 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds if (!addr_asoc) 3031da177e4SLinus Torvalds return NULL; 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds id_asoc = sctp_id2assoc(sk, id); 3061da177e4SLinus Torvalds if (id_asoc && (id_asoc != addr_asoc)) 3071da177e4SLinus Torvalds return NULL; 3081da177e4SLinus Torvalds 309299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), 3101da177e4SLinus Torvalds (union sctp_addr *)addr); 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds return transport; 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds /* API 3.1.2 bind() - UDP Style Syntax 3161da177e4SLinus Torvalds * The syntax of bind() is, 3171da177e4SLinus Torvalds * 3181da177e4SLinus Torvalds * ret = bind(int sd, struct sockaddr *addr, int addrlen); 3191da177e4SLinus Torvalds * 3201da177e4SLinus Torvalds * sd - the socket descriptor returned by socket(). 3211da177e4SLinus Torvalds * addr - the address structure (struct sockaddr_in or struct 3221da177e4SLinus Torvalds * sockaddr_in6 [RFC 2553]), 3231da177e4SLinus Torvalds * addr_len - the size of the address structure. 3241da177e4SLinus Torvalds */ 325dda91928SDaniel Borkmann static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len) 3261da177e4SLinus Torvalds { 3271da177e4SLinus Torvalds int retval = 0; 3281da177e4SLinus Torvalds 329048ed4b6Swangweidong lock_sock(sk); 3301da177e4SLinus Torvalds 331bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addr:%p, addr_len:%d\n", __func__, sk, 332bb33381dSDaniel Borkmann addr, addr_len); 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds /* Disallow binding twice. */ 3351da177e4SLinus Torvalds if (!sctp_sk(sk)->ep->base.bind_addr.port) 3363f7a87d2SFrank Filz retval = sctp_do_bind(sk, (union sctp_addr *)addr, 3371da177e4SLinus Torvalds addr_len); 3381da177e4SLinus Torvalds else 3391da177e4SLinus Torvalds retval = -EINVAL; 3401da177e4SLinus Torvalds 341048ed4b6Swangweidong release_sock(sk); 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds return retval; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds static long sctp_get_port_local(struct sock *, union sctp_addr *); 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds /* Verify this is a valid sockaddr. */ 3491da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, 3501da177e4SLinus Torvalds union sctp_addr *addr, int len) 3511da177e4SLinus Torvalds { 3521da177e4SLinus Torvalds struct sctp_af *af; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds /* Check minimum size. */ 3551da177e4SLinus Torvalds if (len < sizeof (struct sockaddr)) 3561da177e4SLinus Torvalds return NULL; 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds if (!opt->pf->af_supported(addr->sa.sa_family, opt)) 3591da177e4SLinus Torvalds return NULL; 360c5006b8aSXin Long 36181e98370SEric Dumazet if (addr->sa.sa_family == AF_INET6) { 36281e98370SEric Dumazet if (len < SIN6_LEN_RFC2133) 36381e98370SEric Dumazet return NULL; 364c5006b8aSXin Long /* V4 mapped address are really of AF_INET family */ 36581e98370SEric Dumazet if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) && 366c5006b8aSXin Long !opt->pf->af_supported(AF_INET, opt)) 367c5006b8aSXin Long return NULL; 36881e98370SEric Dumazet } 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds /* If we get this far, af is valid. */ 3711da177e4SLinus Torvalds af = sctp_get_af_specific(addr->sa.sa_family); 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds if (len < af->sockaddr_len) 3741da177e4SLinus Torvalds return NULL; 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds return af; 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds /* Bind a local address either to an endpoint or to an association. */ 380dda91928SDaniel Borkmann static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) 3811da177e4SLinus Torvalds { 3823594698aSEric W. Biederman struct net *net = sock_net(sk); 3831da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 3841da177e4SLinus Torvalds struct sctp_endpoint *ep = sp->ep; 3851da177e4SLinus Torvalds struct sctp_bind_addr *bp = &ep->base.bind_addr; 3861da177e4SLinus Torvalds struct sctp_af *af; 3871da177e4SLinus Torvalds unsigned short snum; 3881da177e4SLinus Torvalds int ret = 0; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds /* Common sockaddr verification. */ 3911da177e4SLinus Torvalds af = sctp_sockaddr_af(sp, addr, len); 3923f7a87d2SFrank Filz if (!af) { 393bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, newaddr:%p, len:%d EINVAL\n", 394bb33381dSDaniel Borkmann __func__, sk, addr, len); 3951da177e4SLinus Torvalds return -EINVAL; 3963f7a87d2SFrank Filz } 3973f7a87d2SFrank Filz 3983f7a87d2SFrank Filz snum = ntohs(addr->v4.sin_port); 3993f7a87d2SFrank Filz 400bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, new addr:%pISc, port:%d, new port:%d, len:%d\n", 401bb33381dSDaniel Borkmann __func__, sk, &addr->sa, bp->port, snum, len); 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds /* PF specific bind() address verification. */ 4041da177e4SLinus Torvalds if (!sp->pf->bind_verify(sp, addr)) 4051da177e4SLinus Torvalds return -EADDRNOTAVAIL; 4061da177e4SLinus Torvalds 4078b358056SVlad Yasevich /* We must either be unbound, or bind to the same port. 4088b358056SVlad Yasevich * It's OK to allow 0 ports if we are already bound. 4098b358056SVlad Yasevich * We'll just inhert an already bound port in this case 4108b358056SVlad Yasevich */ 4118b358056SVlad Yasevich if (bp->port) { 4128b358056SVlad Yasevich if (!snum) 4138b358056SVlad Yasevich snum = bp->port; 4148b358056SVlad Yasevich else if (snum != bp->port) { 415bb33381dSDaniel Borkmann pr_debug("%s: new port %d doesn't match existing port " 416bb33381dSDaniel Borkmann "%d\n", __func__, snum, bp->port); 4171da177e4SLinus Torvalds return -EINVAL; 4181da177e4SLinus Torvalds } 4198b358056SVlad Yasevich } 4201da177e4SLinus Torvalds 4214548b683SKrister Johansen if (snum && snum < inet_prot_sock(net) && 4223594698aSEric W. Biederman !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 4231da177e4SLinus Torvalds return -EACCES; 4241da177e4SLinus Torvalds 4254e54064eSVlad Yasevich /* See if the address matches any of the addresses we may have 4264e54064eSVlad Yasevich * already bound before checking against other endpoints. 4274e54064eSVlad Yasevich */ 4284e54064eSVlad Yasevich if (sctp_bind_addr_match(bp, addr, sp)) 4294e54064eSVlad Yasevich return -EINVAL; 4304e54064eSVlad Yasevich 4311da177e4SLinus Torvalds /* Make sure we are allowed to bind here. 4321da177e4SLinus Torvalds * The function sctp_get_port_local() does duplicate address 4331da177e4SLinus Torvalds * detection. 4341da177e4SLinus Torvalds */ 4352772b495SVlad Yasevich addr->v4.sin_port = htons(snum); 4361da177e4SLinus Torvalds if ((ret = sctp_get_port_local(sk, addr))) { 4371da177e4SLinus Torvalds return -EADDRINUSE; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds /* Refresh ephemeral port. */ 4411da177e4SLinus Torvalds if (!bp->port) 442c720c7e8SEric Dumazet bp->port = inet_sk(sk)->inet_num; 4431da177e4SLinus Torvalds 444559cf710SVlad Yasevich /* Add the address to the bind address list. 445559cf710SVlad Yasevich * Use GFP_ATOMIC since BHs will be disabled. 446559cf710SVlad Yasevich */ 447133800d1SMarcelo Ricardo Leitner ret = sctp_add_bind_addr(bp, addr, af->sockaddr_len, 448133800d1SMarcelo Ricardo Leitner SCTP_ADDR_SRC, GFP_ATOMIC); 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds /* Copy back into socket for getsockname() use. */ 4511da177e4SLinus Torvalds if (!ret) { 452c720c7e8SEric Dumazet inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num); 453299ee123SJason Gunthorpe sp->pf->to_sk_saddr(addr, sk); 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds return ret; 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks 4601da177e4SLinus Torvalds * 4611da177e4SLinus Torvalds * R1) One and only one ASCONF Chunk MAY be in transit and unacknowledged 4621da177e4SLinus Torvalds * at any one time. If a sender, after sending an ASCONF chunk, decides 4631da177e4SLinus Torvalds * it needs to transfer another ASCONF Chunk, it MUST wait until the 4641da177e4SLinus Torvalds * ASCONF-ACK Chunk returns from the previous ASCONF Chunk before sending a 4651da177e4SLinus Torvalds * subsequent ASCONF. Note this restriction binds each side, so at any 4661da177e4SLinus Torvalds * time two ASCONF may be in-transit on any given association (one sent 4671da177e4SLinus Torvalds * from each endpoint). 4681da177e4SLinus Torvalds */ 4691da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc, 4701da177e4SLinus Torvalds struct sctp_chunk *chunk) 4711da177e4SLinus Torvalds { 47255e26eb9SEric W. Biederman struct net *net = sock_net(asoc->base.sk); 4731da177e4SLinus Torvalds int retval = 0; 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds /* If there is an outstanding ASCONF chunk, queue it for later 4761da177e4SLinus Torvalds * transmission. 4771da177e4SLinus Torvalds */ 4781da177e4SLinus Torvalds if (asoc->addip_last_asconf) { 47979af02c2SDavid S. Miller list_add_tail(&chunk->list, &asoc->addip_chunk_list); 4801da177e4SLinus Torvalds goto out; 4811da177e4SLinus Torvalds } 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds /* Hold the chunk until an ASCONF_ACK is received. */ 4841da177e4SLinus Torvalds sctp_chunk_hold(chunk); 48555e26eb9SEric W. Biederman retval = sctp_primitive_ASCONF(net, asoc, chunk); 4861da177e4SLinus Torvalds if (retval) 4871da177e4SLinus Torvalds sctp_chunk_free(chunk); 4881da177e4SLinus Torvalds else 4891da177e4SLinus Torvalds asoc->addip_last_asconf = chunk; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds out: 4921da177e4SLinus Torvalds return retval; 4931da177e4SLinus Torvalds } 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds /* Add a list of addresses as bind addresses to local endpoint or 4961da177e4SLinus Torvalds * association. 4971da177e4SLinus Torvalds * 4981da177e4SLinus Torvalds * Basically run through each address specified in the addrs/addrcnt 4991da177e4SLinus Torvalds * array/length pair, determine if it is IPv6 or IPv4 and call 5001da177e4SLinus Torvalds * sctp_do_bind() on it. 5011da177e4SLinus Torvalds * 5021da177e4SLinus Torvalds * If any of them fails, then the operation will be reversed and the 5031da177e4SLinus Torvalds * ones that were added will be removed. 5041da177e4SLinus Torvalds * 5051da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 5061da177e4SLinus Torvalds */ 50704675210Ssebastian@breakpoint.cc static int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt) 5081da177e4SLinus Torvalds { 5091da177e4SLinus Torvalds int cnt; 5101da177e4SLinus Torvalds int retval = 0; 5111da177e4SLinus Torvalds void *addr_buf; 5121da177e4SLinus Torvalds struct sockaddr *sa_addr; 5131da177e4SLinus Torvalds struct sctp_af *af; 5141da177e4SLinus Torvalds 515bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", __func__, sk, 516bb33381dSDaniel Borkmann addrs, addrcnt); 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds addr_buf = addrs; 5191da177e4SLinus Torvalds for (cnt = 0; cnt < addrcnt; cnt++) { 5201da177e4SLinus Torvalds /* The list may contain either IPv4 or IPv6 address; 5211da177e4SLinus Torvalds * determine the address length for walking thru the list. 5221da177e4SLinus Torvalds */ 523ea110733SJoe Perches sa_addr = addr_buf; 5241da177e4SLinus Torvalds af = sctp_get_af_specific(sa_addr->sa_family); 5251da177e4SLinus Torvalds if (!af) { 5261da177e4SLinus Torvalds retval = -EINVAL; 5271da177e4SLinus Torvalds goto err_bindx_add; 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds retval = sctp_do_bind(sk, (union sctp_addr *)sa_addr, 5311da177e4SLinus Torvalds af->sockaddr_len); 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds err_bindx_add: 5361da177e4SLinus Torvalds if (retval < 0) { 5371da177e4SLinus Torvalds /* Failed. Cleanup the ones that have been added */ 5381da177e4SLinus Torvalds if (cnt > 0) 5391da177e4SLinus Torvalds sctp_bindx_rem(sk, addrs, cnt); 5401da177e4SLinus Torvalds return retval; 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds return retval; 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds /* Send an ASCONF chunk with Add IP address parameters to all the peers of the 5481da177e4SLinus Torvalds * associations that are part of the endpoint indicating that a list of local 5491da177e4SLinus Torvalds * addresses are added to the endpoint. 5501da177e4SLinus Torvalds * 5511da177e4SLinus Torvalds * If any of the addresses is already in the bind address list of the 5521da177e4SLinus Torvalds * association, we do not send the chunk for that association. But it will not 5531da177e4SLinus Torvalds * affect other associations. 5541da177e4SLinus Torvalds * 5551da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 5561da177e4SLinus Torvalds */ 5571da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock *sk, 5581da177e4SLinus Torvalds struct sockaddr *addrs, 5591da177e4SLinus Torvalds int addrcnt) 5601da177e4SLinus Torvalds { 561e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 5621da177e4SLinus Torvalds struct sctp_sock *sp; 5631da177e4SLinus Torvalds struct sctp_endpoint *ep; 5641da177e4SLinus Torvalds struct sctp_association *asoc; 5651da177e4SLinus Torvalds struct sctp_bind_addr *bp; 5661da177e4SLinus Torvalds struct sctp_chunk *chunk; 5671da177e4SLinus Torvalds struct sctp_sockaddr_entry *laddr; 5681da177e4SLinus Torvalds union sctp_addr *addr; 569dc022a98SSridhar Samudrala union sctp_addr saveaddr; 5701da177e4SLinus Torvalds void *addr_buf; 5711da177e4SLinus Torvalds struct sctp_af *af; 5721da177e4SLinus Torvalds struct list_head *p; 5731da177e4SLinus Torvalds int i; 5741da177e4SLinus Torvalds int retval = 0; 5751da177e4SLinus Torvalds 576e1fc3b14SEric W. Biederman if (!net->sctp.addip_enable) 5771da177e4SLinus Torvalds return retval; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds sp = sctp_sk(sk); 5801da177e4SLinus Torvalds ep = sp->ep; 5811da177e4SLinus Torvalds 582bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 5830dc47877SHarvey Harrison __func__, sk, addrs, addrcnt); 5841da177e4SLinus Torvalds 5859dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &ep->asocs, asocs) { 5861da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 5871da177e4SLinus Torvalds continue; 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_ADD_IP) 5901da177e4SLinus Torvalds continue; 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 5931da177e4SLinus Torvalds continue; 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds /* Check if any address in the packed array of addresses is 5961da177e4SLinus Torvalds * in the bind address list of the association. If so, 5971da177e4SLinus Torvalds * do not send the asconf chunk to its peer, but continue with 5981da177e4SLinus Torvalds * other associations. 5991da177e4SLinus Torvalds */ 6001da177e4SLinus Torvalds addr_buf = addrs; 6011da177e4SLinus Torvalds for (i = 0; i < addrcnt; i++) { 602ea110733SJoe Perches addr = addr_buf; 6031da177e4SLinus Torvalds af = sctp_get_af_specific(addr->v4.sin_family); 6041da177e4SLinus Torvalds if (!af) { 6051da177e4SLinus Torvalds retval = -EINVAL; 6061da177e4SLinus Torvalds goto out; 6071da177e4SLinus Torvalds } 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds if (sctp_assoc_lookup_laddr(asoc, addr)) 6101da177e4SLinus Torvalds break; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 6131da177e4SLinus Torvalds } 6141da177e4SLinus Torvalds if (i < addrcnt) 6151da177e4SLinus Torvalds continue; 6161da177e4SLinus Torvalds 617559cf710SVlad Yasevich /* Use the first valid address in bind addr list of 618559cf710SVlad Yasevich * association as Address Parameter of ASCONF CHUNK. 6191da177e4SLinus Torvalds */ 6201da177e4SLinus Torvalds bp = &asoc->base.bind_addr; 6211da177e4SLinus Torvalds p = bp->address_list.next; 6221da177e4SLinus Torvalds laddr = list_entry(p, struct sctp_sockaddr_entry, list); 6235ae955cfSAl Viro chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs, 6241da177e4SLinus Torvalds addrcnt, SCTP_PARAM_ADD_IP); 6251da177e4SLinus Torvalds if (!chunk) { 6261da177e4SLinus Torvalds retval = -ENOMEM; 6271da177e4SLinus Torvalds goto out; 6281da177e4SLinus Torvalds } 6291da177e4SLinus Torvalds 630dc022a98SSridhar Samudrala /* Add the new addresses to the bind address list with 631dc022a98SSridhar Samudrala * use_as_src set to 0. 6321da177e4SLinus Torvalds */ 633dc022a98SSridhar Samudrala addr_buf = addrs; 634dc022a98SSridhar Samudrala for (i = 0; i < addrcnt; i++) { 635ea110733SJoe Perches addr = addr_buf; 636dc022a98SSridhar Samudrala af = sctp_get_af_specific(addr->v4.sin_family); 637dc022a98SSridhar Samudrala memcpy(&saveaddr, addr, af->sockaddr_len); 638f57d96b2SVlad Yasevich retval = sctp_add_bind_addr(bp, &saveaddr, 639133800d1SMarcelo Ricardo Leitner sizeof(saveaddr), 640f57d96b2SVlad Yasevich SCTP_ADDR_NEW, GFP_ATOMIC); 641dc022a98SSridhar Samudrala addr_buf += af->sockaddr_len; 642dc022a98SSridhar Samudrala } 6438a07eb0aSMichio Honda if (asoc->src_out_of_asoc_ok) { 6448a07eb0aSMichio Honda struct sctp_transport *trans; 6458a07eb0aSMichio Honda 6468a07eb0aSMichio Honda list_for_each_entry(trans, 6478a07eb0aSMichio Honda &asoc->peer.transport_addr_list, transports) { 6488a07eb0aSMichio Honda trans->cwnd = min(4*asoc->pathmtu, max_t(__u32, 6498a07eb0aSMichio Honda 2*asoc->pathmtu, 4380)); 6508a07eb0aSMichio Honda trans->ssthresh = asoc->peer.i.a_rwnd; 6518a07eb0aSMichio Honda trans->rto = asoc->rto_initial; 652196d6759SMichele Baldessari sctp_max_rto(asoc, trans); 6538a07eb0aSMichio Honda trans->rtt = trans->srtt = trans->rttvar = 0; 6546e91b578SMarcelo Ricardo Leitner /* Clear the source and route cache */ 6558a07eb0aSMichio Honda sctp_transport_route(trans, NULL, 6568a07eb0aSMichio Honda sctp_sk(asoc->base.sk)); 6578a07eb0aSMichio Honda } 6588a07eb0aSMichio Honda } 6598a07eb0aSMichio Honda retval = sctp_send_asconf(asoc, chunk); 6601da177e4SLinus Torvalds } 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds out: 6631da177e4SLinus Torvalds return retval; 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds /* Remove a list of addresses from bind addresses list. Do not remove the 6671da177e4SLinus Torvalds * last address. 6681da177e4SLinus Torvalds * 6691da177e4SLinus Torvalds * Basically run through each address specified in the addrs/addrcnt 6701da177e4SLinus Torvalds * array/length pair, determine if it is IPv6 or IPv4 and call 6711da177e4SLinus Torvalds * sctp_del_bind() on it. 6721da177e4SLinus Torvalds * 6731da177e4SLinus Torvalds * If any of them fails, then the operation will be reversed and the 6741da177e4SLinus Torvalds * ones that were removed will be added back. 6751da177e4SLinus Torvalds * 6761da177e4SLinus Torvalds * At least one address has to be left; if only one address is 6771da177e4SLinus Torvalds * available, the operation will return -EBUSY. 6781da177e4SLinus Torvalds * 6791da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 6801da177e4SLinus Torvalds */ 68104675210Ssebastian@breakpoint.cc static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) 6821da177e4SLinus Torvalds { 6831da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 6841da177e4SLinus Torvalds struct sctp_endpoint *ep = sp->ep; 6851da177e4SLinus Torvalds int cnt; 6861da177e4SLinus Torvalds struct sctp_bind_addr *bp = &ep->base.bind_addr; 6871da177e4SLinus Torvalds int retval = 0; 6881da177e4SLinus Torvalds void *addr_buf; 689c9a08505SAl Viro union sctp_addr *sa_addr; 6901da177e4SLinus Torvalds struct sctp_af *af; 6911da177e4SLinus Torvalds 692bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 693bb33381dSDaniel Borkmann __func__, sk, addrs, addrcnt); 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds addr_buf = addrs; 6961da177e4SLinus Torvalds for (cnt = 0; cnt < addrcnt; cnt++) { 6971da177e4SLinus Torvalds /* If the bind address list is empty or if there is only one 6981da177e4SLinus Torvalds * bind address, there is nothing more to be removed (we need 6991da177e4SLinus Torvalds * at least one address here). 7001da177e4SLinus Torvalds */ 7011da177e4SLinus Torvalds if (list_empty(&bp->address_list) || 7021da177e4SLinus Torvalds (sctp_list_single_entry(&bp->address_list))) { 7031da177e4SLinus Torvalds retval = -EBUSY; 7041da177e4SLinus Torvalds goto err_bindx_rem; 7051da177e4SLinus Torvalds } 7061da177e4SLinus Torvalds 707ea110733SJoe Perches sa_addr = addr_buf; 708c9a08505SAl Viro af = sctp_get_af_specific(sa_addr->sa.sa_family); 7091da177e4SLinus Torvalds if (!af) { 7101da177e4SLinus Torvalds retval = -EINVAL; 7111da177e4SLinus Torvalds goto err_bindx_rem; 7121da177e4SLinus Torvalds } 7130304ff8aSPaolo Galtieri 7140304ff8aSPaolo Galtieri if (!af->addr_valid(sa_addr, sp, NULL)) { 7150304ff8aSPaolo Galtieri retval = -EADDRNOTAVAIL; 7160304ff8aSPaolo Galtieri goto err_bindx_rem; 7170304ff8aSPaolo Galtieri } 7180304ff8aSPaolo Galtieri 719ee9cbacaSVlad Yasevich if (sa_addr->v4.sin_port && 720ee9cbacaSVlad Yasevich sa_addr->v4.sin_port != htons(bp->port)) { 7211da177e4SLinus Torvalds retval = -EINVAL; 7221da177e4SLinus Torvalds goto err_bindx_rem; 7231da177e4SLinus Torvalds } 7241da177e4SLinus Torvalds 725ee9cbacaSVlad Yasevich if (!sa_addr->v4.sin_port) 726ee9cbacaSVlad Yasevich sa_addr->v4.sin_port = htons(bp->port); 727ee9cbacaSVlad Yasevich 7281da177e4SLinus Torvalds /* FIXME - There is probably a need to check if sk->sk_saddr and 7291da177e4SLinus Torvalds * sk->sk_rcv_addr are currently set to one of the addresses to 7301da177e4SLinus Torvalds * be removed. This is something which needs to be looked into 7311da177e4SLinus Torvalds * when we are fixing the outstanding issues with multi-homing 7321da177e4SLinus Torvalds * socket routing and failover schemes. Refer to comments in 7331da177e4SLinus Torvalds * sctp_do_bind(). -daisy 7341da177e4SLinus Torvalds */ 7350ed90fb0SVlad Yasevich retval = sctp_del_bind_addr(bp, sa_addr); 7361da177e4SLinus Torvalds 7371da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 7381da177e4SLinus Torvalds err_bindx_rem: 7391da177e4SLinus Torvalds if (retval < 0) { 7401da177e4SLinus Torvalds /* Failed. Add the ones that has been removed back */ 7411da177e4SLinus Torvalds if (cnt > 0) 7421da177e4SLinus Torvalds sctp_bindx_add(sk, addrs, cnt); 7431da177e4SLinus Torvalds return retval; 7441da177e4SLinus Torvalds } 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds return retval; 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds 7501da177e4SLinus Torvalds /* Send an ASCONF chunk with Delete IP address parameters to all the peers of 7511da177e4SLinus Torvalds * the associations that are part of the endpoint indicating that a list of 7521da177e4SLinus Torvalds * local addresses are removed from the endpoint. 7531da177e4SLinus Torvalds * 7541da177e4SLinus Torvalds * If any of the addresses is already in the bind address list of the 7551da177e4SLinus Torvalds * association, we do not send the chunk for that association. But it will not 7561da177e4SLinus Torvalds * affect other associations. 7571da177e4SLinus Torvalds * 7581da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 7591da177e4SLinus Torvalds */ 7601da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock *sk, 7611da177e4SLinus Torvalds struct sockaddr *addrs, 7621da177e4SLinus Torvalds int addrcnt) 7631da177e4SLinus Torvalds { 764e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 7651da177e4SLinus Torvalds struct sctp_sock *sp; 7661da177e4SLinus Torvalds struct sctp_endpoint *ep; 7671da177e4SLinus Torvalds struct sctp_association *asoc; 768dc022a98SSridhar Samudrala struct sctp_transport *transport; 7691da177e4SLinus Torvalds struct sctp_bind_addr *bp; 7701da177e4SLinus Torvalds struct sctp_chunk *chunk; 7711da177e4SLinus Torvalds union sctp_addr *laddr; 7721da177e4SLinus Torvalds void *addr_buf; 7731da177e4SLinus Torvalds struct sctp_af *af; 774dc022a98SSridhar Samudrala struct sctp_sockaddr_entry *saddr; 7751da177e4SLinus Torvalds int i; 7761da177e4SLinus Torvalds int retval = 0; 7778a07eb0aSMichio Honda int stored = 0; 7781da177e4SLinus Torvalds 7798a07eb0aSMichio Honda chunk = NULL; 780e1fc3b14SEric W. Biederman if (!net->sctp.addip_enable) 7811da177e4SLinus Torvalds return retval; 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds sp = sctp_sk(sk); 7841da177e4SLinus Torvalds ep = sp->ep; 7851da177e4SLinus Torvalds 786bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 7870dc47877SHarvey Harrison __func__, sk, addrs, addrcnt); 7881da177e4SLinus Torvalds 7899dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &ep->asocs, asocs) { 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 7921da177e4SLinus Torvalds continue; 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_DEL_IP) 7951da177e4SLinus Torvalds continue; 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 7981da177e4SLinus Torvalds continue; 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds /* Check if any address in the packed array of addresses is 8011da177e4SLinus Torvalds * not present in the bind address list of the association. 8021da177e4SLinus Torvalds * If so, do not send the asconf chunk to its peer, but 8031da177e4SLinus Torvalds * continue with other associations. 8041da177e4SLinus Torvalds */ 8051da177e4SLinus Torvalds addr_buf = addrs; 8061da177e4SLinus Torvalds for (i = 0; i < addrcnt; i++) { 807ea110733SJoe Perches laddr = addr_buf; 8081da177e4SLinus Torvalds af = sctp_get_af_specific(laddr->v4.sin_family); 8091da177e4SLinus Torvalds if (!af) { 8101da177e4SLinus Torvalds retval = -EINVAL; 8111da177e4SLinus Torvalds goto out; 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds if (!sctp_assoc_lookup_laddr(asoc, laddr)) 8151da177e4SLinus Torvalds break; 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 8181da177e4SLinus Torvalds } 8191da177e4SLinus Torvalds if (i < addrcnt) 8201da177e4SLinus Torvalds continue; 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds /* Find one address in the association's bind address list 8231da177e4SLinus Torvalds * that is not in the packed array of addresses. This is to 8241da177e4SLinus Torvalds * make sure that we do not delete all the addresses in the 8251da177e4SLinus Torvalds * association. 8261da177e4SLinus Torvalds */ 8271da177e4SLinus Torvalds bp = &asoc->base.bind_addr; 8281da177e4SLinus Torvalds laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, 8291da177e4SLinus Torvalds addrcnt, sp); 8308a07eb0aSMichio Honda if ((laddr == NULL) && (addrcnt == 1)) { 8318a07eb0aSMichio Honda if (asoc->asconf_addr_del_pending) 8321da177e4SLinus Torvalds continue; 8338a07eb0aSMichio Honda asoc->asconf_addr_del_pending = 8348a07eb0aSMichio Honda kzalloc(sizeof(union sctp_addr), GFP_ATOMIC); 8356d65e5eeSMichio Honda if (asoc->asconf_addr_del_pending == NULL) { 8366d65e5eeSMichio Honda retval = -ENOMEM; 8376d65e5eeSMichio Honda goto out; 8386d65e5eeSMichio Honda } 8398a07eb0aSMichio Honda asoc->asconf_addr_del_pending->sa.sa_family = 8408a07eb0aSMichio Honda addrs->sa_family; 8418a07eb0aSMichio Honda asoc->asconf_addr_del_pending->v4.sin_port = 8428a07eb0aSMichio Honda htons(bp->port); 8438a07eb0aSMichio Honda if (addrs->sa_family == AF_INET) { 8448a07eb0aSMichio Honda struct sockaddr_in *sin; 8458a07eb0aSMichio Honda 8468a07eb0aSMichio Honda sin = (struct sockaddr_in *)addrs; 8478a07eb0aSMichio Honda asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr; 8488a07eb0aSMichio Honda } else if (addrs->sa_family == AF_INET6) { 8498a07eb0aSMichio Honda struct sockaddr_in6 *sin6; 8508a07eb0aSMichio Honda 8518a07eb0aSMichio Honda sin6 = (struct sockaddr_in6 *)addrs; 8524e3fd7a0SAlexey Dobriyan asoc->asconf_addr_del_pending->v6.sin6_addr = sin6->sin6_addr; 8538a07eb0aSMichio Honda } 854bb33381dSDaniel Borkmann 855bb33381dSDaniel Borkmann pr_debug("%s: keep the last address asoc:%p %pISc at %p\n", 856bb33381dSDaniel Borkmann __func__, asoc, &asoc->asconf_addr_del_pending->sa, 8578a07eb0aSMichio Honda asoc->asconf_addr_del_pending); 858bb33381dSDaniel Borkmann 8598a07eb0aSMichio Honda asoc->src_out_of_asoc_ok = 1; 8608a07eb0aSMichio Honda stored = 1; 8618a07eb0aSMichio Honda goto skip_mkasconf; 8628a07eb0aSMichio Honda } 8631da177e4SLinus Torvalds 86488362ad8SDaniel Borkmann if (laddr == NULL) 86588362ad8SDaniel Borkmann return -EINVAL; 86688362ad8SDaniel Borkmann 867559cf710SVlad Yasevich /* We do not need RCU protection throughout this loop 868559cf710SVlad Yasevich * because this is done under a socket lock from the 869559cf710SVlad Yasevich * setsockopt call. 870559cf710SVlad Yasevich */ 8711da177e4SLinus Torvalds chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt, 8721da177e4SLinus Torvalds SCTP_PARAM_DEL_IP); 8731da177e4SLinus Torvalds if (!chunk) { 8741da177e4SLinus Torvalds retval = -ENOMEM; 8751da177e4SLinus Torvalds goto out; 8761da177e4SLinus Torvalds } 8771da177e4SLinus Torvalds 8788a07eb0aSMichio Honda skip_mkasconf: 879dc022a98SSridhar Samudrala /* Reset use_as_src flag for the addresses in the bind address 880dc022a98SSridhar Samudrala * list that are to be deleted. 8811da177e4SLinus Torvalds */ 882dc022a98SSridhar Samudrala addr_buf = addrs; 883dc022a98SSridhar Samudrala for (i = 0; i < addrcnt; i++) { 884ea110733SJoe Perches laddr = addr_buf; 885dc022a98SSridhar Samudrala af = sctp_get_af_specific(laddr->v4.sin_family); 886559cf710SVlad Yasevich list_for_each_entry(saddr, &bp->address_list, list) { 8875f242a13SAl Viro if (sctp_cmp_addr_exact(&saddr->a, laddr)) 888f57d96b2SVlad Yasevich saddr->state = SCTP_ADDR_DEL; 889dc022a98SSridhar Samudrala } 890dc022a98SSridhar Samudrala addr_buf += af->sockaddr_len; 891dc022a98SSridhar Samudrala } 892dc022a98SSridhar Samudrala 893dc022a98SSridhar Samudrala /* Update the route and saddr entries for all the transports 894dc022a98SSridhar Samudrala * as some of the addresses in the bind address list are 895dc022a98SSridhar Samudrala * about to be deleted and cannot be used as source addresses. 896dc022a98SSridhar Samudrala */ 8979dbc15f0SRobert P. J. Day list_for_each_entry(transport, &asoc->peer.transport_addr_list, 8989dbc15f0SRobert P. J. Day transports) { 899dc022a98SSridhar Samudrala sctp_transport_route(transport, NULL, 900dc022a98SSridhar Samudrala sctp_sk(asoc->base.sk)); 901dc022a98SSridhar Samudrala } 902dc022a98SSridhar Samudrala 9038a07eb0aSMichio Honda if (stored) 9048a07eb0aSMichio Honda /* We don't need to transmit ASCONF */ 9058a07eb0aSMichio Honda continue; 906dc022a98SSridhar Samudrala retval = sctp_send_asconf(asoc, chunk); 9071da177e4SLinus Torvalds } 9081da177e4SLinus Torvalds out: 9091da177e4SLinus Torvalds return retval; 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds 9129f7d653bSMichio Honda /* set addr events to assocs in the endpoint. ep and addr_wq must be locked */ 9139f7d653bSMichio Honda int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw) 9149f7d653bSMichio Honda { 9159f7d653bSMichio Honda struct sock *sk = sctp_opt2sk(sp); 9169f7d653bSMichio Honda union sctp_addr *addr; 9179f7d653bSMichio Honda struct sctp_af *af; 9189f7d653bSMichio Honda 9199f7d653bSMichio Honda /* It is safe to write port space in caller. */ 9209f7d653bSMichio Honda addr = &addrw->a; 9219f7d653bSMichio Honda addr->v4.sin_port = htons(sp->ep->base.bind_addr.port); 9229f7d653bSMichio Honda af = sctp_get_af_specific(addr->sa.sa_family); 9239f7d653bSMichio Honda if (!af) 9249f7d653bSMichio Honda return -EINVAL; 9259f7d653bSMichio Honda if (sctp_verify_addr(sk, addr, af->sockaddr_len)) 9269f7d653bSMichio Honda return -EINVAL; 9279f7d653bSMichio Honda 9289f7d653bSMichio Honda if (addrw->state == SCTP_ADDR_NEW) 9299f7d653bSMichio Honda return sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1); 9309f7d653bSMichio Honda else 9319f7d653bSMichio Honda return sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1); 9329f7d653bSMichio Honda } 9339f7d653bSMichio Honda 9341da177e4SLinus Torvalds /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt() 9351da177e4SLinus Torvalds * 9361da177e4SLinus Torvalds * API 8.1 9371da177e4SLinus Torvalds * int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, 9381da177e4SLinus Torvalds * int flags); 9391da177e4SLinus Torvalds * 9401da177e4SLinus Torvalds * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. 9411da177e4SLinus Torvalds * If the sd is an IPv6 socket, the addresses passed can either be IPv4 9421da177e4SLinus Torvalds * or IPv6 addresses. 9431da177e4SLinus Torvalds * 9441da177e4SLinus Torvalds * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see 9451da177e4SLinus Torvalds * Section 3.1.2 for this usage. 9461da177e4SLinus Torvalds * 9471da177e4SLinus Torvalds * addrs is a pointer to an array of one or more socket addresses. Each 9481da177e4SLinus Torvalds * address is contained in its appropriate structure (i.e. struct 9491da177e4SLinus Torvalds * sockaddr_in or struct sockaddr_in6) the family of the address type 95023c435f7SVille Nuorvala * must be used to distinguish the address length (note that this 9511da177e4SLinus Torvalds * representation is termed a "packed array" of addresses). The caller 9521da177e4SLinus Torvalds * specifies the number of addresses in the array with addrcnt. 9531da177e4SLinus Torvalds * 9541da177e4SLinus Torvalds * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns 9551da177e4SLinus Torvalds * -1, and sets errno to the appropriate error code. 9561da177e4SLinus Torvalds * 9571da177e4SLinus Torvalds * For SCTP, the port given in each socket address must be the same, or 9581da177e4SLinus Torvalds * sctp_bindx() will fail, setting errno to EINVAL. 9591da177e4SLinus Torvalds * 9601da177e4SLinus Torvalds * The flags parameter is formed from the bitwise OR of zero or more of 9611da177e4SLinus Torvalds * the following currently defined flags: 9621da177e4SLinus Torvalds * 9631da177e4SLinus Torvalds * SCTP_BINDX_ADD_ADDR 9641da177e4SLinus Torvalds * 9651da177e4SLinus Torvalds * SCTP_BINDX_REM_ADDR 9661da177e4SLinus Torvalds * 9671da177e4SLinus Torvalds * SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the 9681da177e4SLinus Torvalds * association, and SCTP_BINDX_REM_ADDR directs SCTP to remove the given 9691da177e4SLinus Torvalds * addresses from the association. The two flags are mutually exclusive; 9701da177e4SLinus Torvalds * if both are given, sctp_bindx() will fail with EINVAL. A caller may 9711da177e4SLinus Torvalds * not remove all addresses from an association; sctp_bindx() will 9721da177e4SLinus Torvalds * reject such an attempt with EINVAL. 9731da177e4SLinus Torvalds * 9741da177e4SLinus Torvalds * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate 9751da177e4SLinus Torvalds * additional addresses with an endpoint after calling bind(). Or use 9761da177e4SLinus Torvalds * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening 9771da177e4SLinus Torvalds * socket is associated with so that no new association accepted will be 9781da177e4SLinus Torvalds * associated with those addresses. If the endpoint supports dynamic 9791da177e4SLinus Torvalds * address a SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR may cause a 9801da177e4SLinus Torvalds * endpoint to send the appropriate message to the peer to change the 9811da177e4SLinus Torvalds * peers address lists. 9821da177e4SLinus Torvalds * 9831da177e4SLinus Torvalds * Adding and removing addresses from a connected association is 9841da177e4SLinus Torvalds * optional functionality. Implementations that do not support this 9851da177e4SLinus Torvalds * functionality should return EOPNOTSUPP. 9861da177e4SLinus Torvalds * 9871da177e4SLinus Torvalds * Basically do nothing but copying the addresses from user to kernel 9881da177e4SLinus Torvalds * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk. 9893f7a87d2SFrank Filz * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() 9903f7a87d2SFrank Filz * from userspace. 9911da177e4SLinus Torvalds * 9921da177e4SLinus Torvalds * On exit there is no need to do sockfd_put(), sys_setsockopt() does 9931da177e4SLinus Torvalds * it. 9941da177e4SLinus Torvalds * 9951da177e4SLinus Torvalds * sk The sk of the socket 9961da177e4SLinus Torvalds * addrs The pointer to the addresses in user land 9971da177e4SLinus Torvalds * addrssize Size of the addrs buffer 9981da177e4SLinus Torvalds * op Operation to perform (add or remove, see the flags of 9991da177e4SLinus Torvalds * sctp_bindx) 10001da177e4SLinus Torvalds * 10011da177e4SLinus Torvalds * Returns 0 if ok, <0 errno code on error. 10021da177e4SLinus Torvalds */ 1003dda91928SDaniel Borkmann static int sctp_setsockopt_bindx(struct sock *sk, 10041da177e4SLinus Torvalds struct sockaddr __user *addrs, 10051da177e4SLinus Torvalds int addrs_size, int op) 10061da177e4SLinus Torvalds { 10071da177e4SLinus Torvalds struct sockaddr *kaddrs; 10081da177e4SLinus Torvalds int err; 10091da177e4SLinus Torvalds int addrcnt = 0; 10101da177e4SLinus Torvalds int walk_size = 0; 10111da177e4SLinus Torvalds struct sockaddr *sa_addr; 10121da177e4SLinus Torvalds void *addr_buf; 10131da177e4SLinus Torvalds struct sctp_af *af; 10141da177e4SLinus Torvalds 1015bb33381dSDaniel Borkmann pr_debug("%s: sk:%p addrs:%p addrs_size:%d opt:%d\n", 1016bb33381dSDaniel Borkmann __func__, sk, addrs, addrs_size, op); 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds if (unlikely(addrs_size <= 0)) 10191da177e4SLinus Torvalds return -EINVAL; 10201da177e4SLinus Torvalds 1021c981f254SAl Viro kaddrs = vmemdup_user(addrs, addrs_size); 1022c981f254SAl Viro if (unlikely(IS_ERR(kaddrs))) 1023c981f254SAl Viro return PTR_ERR(kaddrs); 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds /* Walk through the addrs buffer and count the number of addresses. */ 10261da177e4SLinus Torvalds addr_buf = kaddrs; 10271da177e4SLinus Torvalds while (walk_size < addrs_size) { 1028d7e0d19aSDan Rosenberg if (walk_size + sizeof(sa_family_t) > addrs_size) { 1029c981f254SAl Viro kvfree(kaddrs); 1030d7e0d19aSDan Rosenberg return -EINVAL; 1031d7e0d19aSDan Rosenberg } 1032d7e0d19aSDan Rosenberg 1033ea110733SJoe Perches sa_addr = addr_buf; 10341da177e4SLinus Torvalds af = sctp_get_af_specific(sa_addr->sa_family); 10351da177e4SLinus Torvalds 10361da177e4SLinus Torvalds /* If the address family is not supported or if this address 10371da177e4SLinus Torvalds * causes the address buffer to overflow return EINVAL. 10381da177e4SLinus Torvalds */ 10391da177e4SLinus Torvalds if (!af || (walk_size + af->sockaddr_len) > addrs_size) { 1040c981f254SAl Viro kvfree(kaddrs); 10411da177e4SLinus Torvalds return -EINVAL; 10421da177e4SLinus Torvalds } 10431da177e4SLinus Torvalds addrcnt++; 10441da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 10451da177e4SLinus Torvalds walk_size += af->sockaddr_len; 10461da177e4SLinus Torvalds } 10471da177e4SLinus Torvalds 10481da177e4SLinus Torvalds /* Do the work. */ 10491da177e4SLinus Torvalds switch (op) { 10501da177e4SLinus Torvalds case SCTP_BINDX_ADD_ADDR: 10512277c7cdSRichard Haines /* Allow security module to validate bindx addresses. */ 10522277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_BINDX_ADD, 10532277c7cdSRichard Haines (struct sockaddr *)kaddrs, 10542277c7cdSRichard Haines addrs_size); 10552277c7cdSRichard Haines if (err) 10562277c7cdSRichard Haines goto out; 10571da177e4SLinus Torvalds err = sctp_bindx_add(sk, kaddrs, addrcnt); 10581da177e4SLinus Torvalds if (err) 10591da177e4SLinus Torvalds goto out; 10601da177e4SLinus Torvalds err = sctp_send_asconf_add_ip(sk, kaddrs, addrcnt); 10611da177e4SLinus Torvalds break; 10621da177e4SLinus Torvalds 10631da177e4SLinus Torvalds case SCTP_BINDX_REM_ADDR: 10641da177e4SLinus Torvalds err = sctp_bindx_rem(sk, kaddrs, addrcnt); 10651da177e4SLinus Torvalds if (err) 10661da177e4SLinus Torvalds goto out; 10671da177e4SLinus Torvalds err = sctp_send_asconf_del_ip(sk, kaddrs, addrcnt); 10681da177e4SLinus Torvalds break; 10691da177e4SLinus Torvalds 10701da177e4SLinus Torvalds default: 10711da177e4SLinus Torvalds err = -EINVAL; 10721da177e4SLinus Torvalds break; 10733ff50b79SStephen Hemminger } 10741da177e4SLinus Torvalds 10751da177e4SLinus Torvalds out: 1076c981f254SAl Viro kvfree(kaddrs); 10771da177e4SLinus Torvalds 10781da177e4SLinus Torvalds return err; 10791da177e4SLinus Torvalds } 10801da177e4SLinus Torvalds 10813f7a87d2SFrank Filz /* __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, int addrs_size) 10823f7a87d2SFrank Filz * 10833f7a87d2SFrank Filz * Common routine for handling connect() and sctp_connectx(). 10843f7a87d2SFrank Filz * Connect will come in with just a single address. 10853f7a87d2SFrank Filz */ 10863f7a87d2SFrank Filz static int __sctp_connect(struct sock *sk, 10873f7a87d2SFrank Filz struct sockaddr *kaddrs, 1088644fbdeaSXin Long int addrs_size, int flags, 108988a0a948SVlad Yasevich sctp_assoc_t *assoc_id) 10903f7a87d2SFrank Filz { 109155e26eb9SEric W. Biederman struct net *net = sock_net(sk); 10923f7a87d2SFrank Filz struct sctp_sock *sp; 10933f7a87d2SFrank Filz struct sctp_endpoint *ep; 10943f7a87d2SFrank Filz struct sctp_association *asoc = NULL; 10953f7a87d2SFrank Filz struct sctp_association *asoc2; 10963f7a87d2SFrank Filz struct sctp_transport *transport; 10973f7a87d2SFrank Filz union sctp_addr to; 10981c662018SXin Long enum sctp_scope scope; 10993f7a87d2SFrank Filz long timeo; 11003f7a87d2SFrank Filz int err = 0; 11013f7a87d2SFrank Filz int addrcnt = 0; 11023f7a87d2SFrank Filz int walk_size = 0; 1103e4d1feabSVlad Yasevich union sctp_addr *sa_addr = NULL; 11043f7a87d2SFrank Filz void *addr_buf; 110516d00fb7SVlad Yasevich unsigned short port; 11063f7a87d2SFrank Filz 11073f7a87d2SFrank Filz sp = sctp_sk(sk); 11083f7a87d2SFrank Filz ep = sp->ep; 11093f7a87d2SFrank Filz 11103f7a87d2SFrank Filz /* connect() cannot be done on a socket that is already in ESTABLISHED 11113f7a87d2SFrank Filz * state - UDP-style peeled off socket or a TCP-style socket that 11123f7a87d2SFrank Filz * is already connected. 11133f7a87d2SFrank Filz * It cannot be done even on a TCP-style listening socket. 11143f7a87d2SFrank Filz */ 1115e5b13f34SMarcelo Ricardo Leitner if (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING) || 11163f7a87d2SFrank Filz (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) { 11173f7a87d2SFrank Filz err = -EISCONN; 11183f7a87d2SFrank Filz goto out_free; 11193f7a87d2SFrank Filz } 11203f7a87d2SFrank Filz 11213f7a87d2SFrank Filz /* Walk through the addrs buffer and count the number of addresses. */ 11223f7a87d2SFrank Filz addr_buf = kaddrs; 11233f7a87d2SFrank Filz while (walk_size < addrs_size) { 1124299ee123SJason Gunthorpe struct sctp_af *af; 1125299ee123SJason Gunthorpe 1126d7e0d19aSDan Rosenberg if (walk_size + sizeof(sa_family_t) > addrs_size) { 1127d7e0d19aSDan Rosenberg err = -EINVAL; 1128d7e0d19aSDan Rosenberg goto out_free; 1129d7e0d19aSDan Rosenberg } 1130d7e0d19aSDan Rosenberg 1131ea110733SJoe Perches sa_addr = addr_buf; 11324bdf4b5fSAl Viro af = sctp_get_af_specific(sa_addr->sa.sa_family); 11333f7a87d2SFrank Filz 11343f7a87d2SFrank Filz /* If the address family is not supported or if this address 11353f7a87d2SFrank Filz * causes the address buffer to overflow return EINVAL. 11363f7a87d2SFrank Filz */ 11373f7a87d2SFrank Filz if (!af || (walk_size + af->sockaddr_len) > addrs_size) { 11383f7a87d2SFrank Filz err = -EINVAL; 11393f7a87d2SFrank Filz goto out_free; 11403f7a87d2SFrank Filz } 11413f7a87d2SFrank Filz 1142d7e0d19aSDan Rosenberg port = ntohs(sa_addr->v4.sin_port); 1143d7e0d19aSDan Rosenberg 1144e4d1feabSVlad Yasevich /* Save current address so we can work with it */ 1145e4d1feabSVlad Yasevich memcpy(&to, sa_addr, af->sockaddr_len); 1146e4d1feabSVlad Yasevich 1147e4d1feabSVlad Yasevich err = sctp_verify_addr(sk, &to, af->sockaddr_len); 11483f7a87d2SFrank Filz if (err) 11493f7a87d2SFrank Filz goto out_free; 11503f7a87d2SFrank Filz 115116d00fb7SVlad Yasevich /* Make sure the destination port is correctly set 115216d00fb7SVlad Yasevich * in all addresses. 115316d00fb7SVlad Yasevich */ 1154524fba6cSWei Yongjun if (asoc && asoc->peer.port && asoc->peer.port != port) { 1155524fba6cSWei Yongjun err = -EINVAL; 115616d00fb7SVlad Yasevich goto out_free; 1157524fba6cSWei Yongjun } 11583f7a87d2SFrank Filz 11593f7a87d2SFrank Filz /* Check if there already is a matching association on the 11603f7a87d2SFrank Filz * endpoint (other than the one created here). 11613f7a87d2SFrank Filz */ 1162e4d1feabSVlad Yasevich asoc2 = sctp_endpoint_lookup_assoc(ep, &to, &transport); 11633f7a87d2SFrank Filz if (asoc2 && asoc2 != asoc) { 11643f7a87d2SFrank Filz if (asoc2->state >= SCTP_STATE_ESTABLISHED) 11653f7a87d2SFrank Filz err = -EISCONN; 11663f7a87d2SFrank Filz else 11673f7a87d2SFrank Filz err = -EALREADY; 11683f7a87d2SFrank Filz goto out_free; 11693f7a87d2SFrank Filz } 11703f7a87d2SFrank Filz 11713f7a87d2SFrank Filz /* If we could not find a matching association on the endpoint, 11723f7a87d2SFrank Filz * make sure that there is no peeled-off association matching 11733f7a87d2SFrank Filz * the peer address even on another socket. 11743f7a87d2SFrank Filz */ 1175e4d1feabSVlad Yasevich if (sctp_endpoint_is_peeled_off(ep, &to)) { 11763f7a87d2SFrank Filz err = -EADDRNOTAVAIL; 11773f7a87d2SFrank Filz goto out_free; 11783f7a87d2SFrank Filz } 11793f7a87d2SFrank Filz 11803f7a87d2SFrank Filz if (!asoc) { 11813f7a87d2SFrank Filz /* If a bind() or sctp_bindx() is not called prior to 11823f7a87d2SFrank Filz * an sctp_connectx() call, the system picks an 11833f7a87d2SFrank Filz * ephemeral port and will choose an address set 11843f7a87d2SFrank Filz * equivalent to binding with a wildcard address. 11853f7a87d2SFrank Filz */ 11863f7a87d2SFrank Filz if (!ep->base.bind_addr.port) { 11873f7a87d2SFrank Filz if (sctp_autobind(sk)) { 11883f7a87d2SFrank Filz err = -EAGAIN; 11893f7a87d2SFrank Filz goto out_free; 11903f7a87d2SFrank Filz } 119164a0c1c8SIvan Skytte Jorgensen } else { 119264a0c1c8SIvan Skytte Jorgensen /* 119364a0c1c8SIvan Skytte Jorgensen * If an unprivileged user inherits a 1-many 119464a0c1c8SIvan Skytte Jorgensen * style socket with open associations on a 119564a0c1c8SIvan Skytte Jorgensen * privileged port, it MAY be permitted to 119664a0c1c8SIvan Skytte Jorgensen * accept new associations, but it SHOULD NOT 119764a0c1c8SIvan Skytte Jorgensen * be permitted to open new associations. 119864a0c1c8SIvan Skytte Jorgensen */ 11994548b683SKrister Johansen if (ep->base.bind_addr.port < 12004548b683SKrister Johansen inet_prot_sock(net) && 12014548b683SKrister Johansen !ns_capable(net->user_ns, 12024548b683SKrister Johansen CAP_NET_BIND_SERVICE)) { 120364a0c1c8SIvan Skytte Jorgensen err = -EACCES; 120464a0c1c8SIvan Skytte Jorgensen goto out_free; 120564a0c1c8SIvan Skytte Jorgensen } 12063f7a87d2SFrank Filz } 12073f7a87d2SFrank Filz 1208e4d1feabSVlad Yasevich scope = sctp_scope(&to); 12093f7a87d2SFrank Filz asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); 12103f7a87d2SFrank Filz if (!asoc) { 12113f7a87d2SFrank Filz err = -ENOMEM; 12123f7a87d2SFrank Filz goto out_free; 12133f7a87d2SFrank Filz } 1214409b95afSVlad Yasevich 1215409b95afSVlad Yasevich err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, 1216409b95afSVlad Yasevich GFP_KERNEL); 1217409b95afSVlad Yasevich if (err < 0) { 1218409b95afSVlad Yasevich goto out_free; 1219409b95afSVlad Yasevich } 1220409b95afSVlad Yasevich 12213f7a87d2SFrank Filz } 12223f7a87d2SFrank Filz 12233f7a87d2SFrank Filz /* Prime the peer's transport structures. */ 1224e4d1feabSVlad Yasevich transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, 12253f7a87d2SFrank Filz SCTP_UNKNOWN); 12263f7a87d2SFrank Filz if (!transport) { 12273f7a87d2SFrank Filz err = -ENOMEM; 12283f7a87d2SFrank Filz goto out_free; 12293f7a87d2SFrank Filz } 12303f7a87d2SFrank Filz 12313f7a87d2SFrank Filz addrcnt++; 12323f7a87d2SFrank Filz addr_buf += af->sockaddr_len; 12333f7a87d2SFrank Filz walk_size += af->sockaddr_len; 12343f7a87d2SFrank Filz } 12353f7a87d2SFrank Filz 1236c6ba68a2SVlad Yasevich /* In case the user of sctp_connectx() wants an association 1237c6ba68a2SVlad Yasevich * id back, assign one now. 1238c6ba68a2SVlad Yasevich */ 1239c6ba68a2SVlad Yasevich if (assoc_id) { 1240c6ba68a2SVlad Yasevich err = sctp_assoc_set_id(asoc, GFP_KERNEL); 1241c6ba68a2SVlad Yasevich if (err < 0) 1242c6ba68a2SVlad Yasevich goto out_free; 1243c6ba68a2SVlad Yasevich } 1244c6ba68a2SVlad Yasevich 124555e26eb9SEric W. Biederman err = sctp_primitive_ASSOCIATE(net, asoc, NULL); 12463f7a87d2SFrank Filz if (err < 0) { 12473f7a87d2SFrank Filz goto out_free; 12483f7a87d2SFrank Filz } 12493f7a87d2SFrank Filz 12503f7a87d2SFrank Filz /* Initialize sk's dport and daddr for getpeername() */ 1251c720c7e8SEric Dumazet inet_sk(sk)->inet_dport = htons(asoc->peer.port); 1252299ee123SJason Gunthorpe sp->pf->to_sk_daddr(sa_addr, sk); 12538de8c873SSridhar Samudrala sk->sk_err = 0; 12543f7a87d2SFrank Filz 1255644fbdeaSXin Long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); 1256f50f95caSVlad Yasevich 12577233bc84SMarcelo Ricardo Leitner if (assoc_id) 125888a0a948SVlad Yasevich *assoc_id = asoc->assoc_id; 12592277c7cdSRichard Haines 12607233bc84SMarcelo Ricardo Leitner err = sctp_wait_for_connect(asoc, &timeo); 12617233bc84SMarcelo Ricardo Leitner /* Note: the asoc may be freed after the return of 12627233bc84SMarcelo Ricardo Leitner * sctp_wait_for_connect. 12637233bc84SMarcelo Ricardo Leitner */ 12643f7a87d2SFrank Filz 12653f7a87d2SFrank Filz /* Don't free association on exit. */ 12663f7a87d2SFrank Filz asoc = NULL; 12673f7a87d2SFrank Filz 12683f7a87d2SFrank Filz out_free: 1269bb33381dSDaniel Borkmann pr_debug("%s: took out_free path with asoc:%p kaddrs:%p err:%d\n", 1270bb33381dSDaniel Borkmann __func__, asoc, kaddrs, err); 12713f7a87d2SFrank Filz 12722eebc1e1SNeil Horman if (asoc) { 12732eebc1e1SNeil Horman /* sctp_primitive_ASSOCIATE may have added this association 12742eebc1e1SNeil Horman * To the hash table, try to unhash it, just in case, its a noop 12752eebc1e1SNeil Horman * if it wasn't hashed so we're safe 12762eebc1e1SNeil Horman */ 12773f7a87d2SFrank Filz sctp_association_free(asoc); 12782eebc1e1SNeil Horman } 12793f7a87d2SFrank Filz return err; 12803f7a87d2SFrank Filz } 12813f7a87d2SFrank Filz 12823f7a87d2SFrank Filz /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt() 12833f7a87d2SFrank Filz * 12843f7a87d2SFrank Filz * API 8.9 128588a0a948SVlad Yasevich * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt, 128688a0a948SVlad Yasevich * sctp_assoc_t *asoc); 12873f7a87d2SFrank Filz * 12883f7a87d2SFrank Filz * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. 12893f7a87d2SFrank Filz * If the sd is an IPv6 socket, the addresses passed can either be IPv4 12903f7a87d2SFrank Filz * or IPv6 addresses. 12913f7a87d2SFrank Filz * 12923f7a87d2SFrank Filz * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see 12933f7a87d2SFrank Filz * Section 3.1.2 for this usage. 12943f7a87d2SFrank Filz * 12953f7a87d2SFrank Filz * addrs is a pointer to an array of one or more socket addresses. Each 12963f7a87d2SFrank Filz * address is contained in its appropriate structure (i.e. struct 12973f7a87d2SFrank Filz * sockaddr_in or struct sockaddr_in6) the family of the address type 12983f7a87d2SFrank Filz * must be used to distengish the address length (note that this 12993f7a87d2SFrank Filz * representation is termed a "packed array" of addresses). The caller 13003f7a87d2SFrank Filz * specifies the number of addresses in the array with addrcnt. 13013f7a87d2SFrank Filz * 130288a0a948SVlad Yasevich * On success, sctp_connectx() returns 0. It also sets the assoc_id to 130388a0a948SVlad Yasevich * the association id of the new association. On failure, sctp_connectx() 130488a0a948SVlad Yasevich * returns -1, and sets errno to the appropriate error code. The assoc_id 130588a0a948SVlad Yasevich * is not touched by the kernel. 13063f7a87d2SFrank Filz * 13073f7a87d2SFrank Filz * For SCTP, the port given in each socket address must be the same, or 13083f7a87d2SFrank Filz * sctp_connectx() will fail, setting errno to EINVAL. 13093f7a87d2SFrank Filz * 13103f7a87d2SFrank Filz * An application can use sctp_connectx to initiate an association with 13113f7a87d2SFrank Filz * an endpoint that is multi-homed. Much like sctp_bindx() this call 13123f7a87d2SFrank Filz * allows a caller to specify multiple addresses at which a peer can be 13133f7a87d2SFrank Filz * reached. The way the SCTP stack uses the list of addresses to set up 131425985edcSLucas De Marchi * the association is implementation dependent. This function only 13153f7a87d2SFrank Filz * specifies that the stack will try to make use of all the addresses in 13163f7a87d2SFrank Filz * the list when needed. 13173f7a87d2SFrank Filz * 13183f7a87d2SFrank Filz * Note that the list of addresses passed in is only used for setting up 13193f7a87d2SFrank Filz * the association. It does not necessarily equal the set of addresses 13203f7a87d2SFrank Filz * the peer uses for the resulting association. If the caller wants to 13213f7a87d2SFrank Filz * find out the set of peer addresses, it must use sctp_getpaddrs() to 13223f7a87d2SFrank Filz * retrieve them after the association has been set up. 13233f7a87d2SFrank Filz * 13243f7a87d2SFrank Filz * Basically do nothing but copying the addresses from user to kernel 13253f7a87d2SFrank Filz * land and invoking either sctp_connectx(). This is used for tunneling 13263f7a87d2SFrank Filz * the sctp_connectx() request through sctp_setsockopt() from userspace. 13273f7a87d2SFrank Filz * 13283f7a87d2SFrank Filz * On exit there is no need to do sockfd_put(), sys_setsockopt() does 13293f7a87d2SFrank Filz * it. 13303f7a87d2SFrank Filz * 13313f7a87d2SFrank Filz * sk The sk of the socket 13323f7a87d2SFrank Filz * addrs The pointer to the addresses in user land 13333f7a87d2SFrank Filz * addrssize Size of the addrs buffer 13343f7a87d2SFrank Filz * 133588a0a948SVlad Yasevich * Returns >=0 if ok, <0 errno code on error. 13363f7a87d2SFrank Filz */ 1337dda91928SDaniel Borkmann static int __sctp_setsockopt_connectx(struct sock *sk, 13383f7a87d2SFrank Filz struct sockaddr __user *addrs, 133988a0a948SVlad Yasevich int addrs_size, 134088a0a948SVlad Yasevich sctp_assoc_t *assoc_id) 13413f7a87d2SFrank Filz { 13423f7a87d2SFrank Filz struct sockaddr *kaddrs; 1343644fbdeaSXin Long int err = 0, flags = 0; 13443f7a87d2SFrank Filz 1345bb33381dSDaniel Borkmann pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n", 13460dc47877SHarvey Harrison __func__, sk, addrs, addrs_size); 13473f7a87d2SFrank Filz 13483f7a87d2SFrank Filz if (unlikely(addrs_size <= 0)) 13493f7a87d2SFrank Filz return -EINVAL; 13503f7a87d2SFrank Filz 1351c981f254SAl Viro kaddrs = vmemdup_user(addrs, addrs_size); 1352c981f254SAl Viro if (unlikely(IS_ERR(kaddrs))) 1353c981f254SAl Viro return PTR_ERR(kaddrs); 13543f7a87d2SFrank Filz 13552277c7cdSRichard Haines /* Allow security module to validate connectx addresses. */ 13562277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX, 13572277c7cdSRichard Haines (struct sockaddr *)kaddrs, 13582277c7cdSRichard Haines addrs_size); 13592277c7cdSRichard Haines if (err) 13602277c7cdSRichard Haines goto out_free; 13612277c7cdSRichard Haines 1362644fbdeaSXin Long /* in-kernel sockets don't generally have a file allocated to them 1363644fbdeaSXin Long * if all they do is call sock_create_kern(). 1364644fbdeaSXin Long */ 1365644fbdeaSXin Long if (sk->sk_socket->file) 1366644fbdeaSXin Long flags = sk->sk_socket->file->f_flags; 1367644fbdeaSXin Long 1368644fbdeaSXin Long err = __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id); 13692277c7cdSRichard Haines 13702277c7cdSRichard Haines out_free: 1371c981f254SAl Viro kvfree(kaddrs); 137288a0a948SVlad Yasevich 13733f7a87d2SFrank Filz return err; 13743f7a87d2SFrank Filz } 13753f7a87d2SFrank Filz 137688a0a948SVlad Yasevich /* 137788a0a948SVlad Yasevich * This is an older interface. It's kept for backward compatibility 137888a0a948SVlad Yasevich * to the option that doesn't provide association id. 137988a0a948SVlad Yasevich */ 1380dda91928SDaniel Borkmann static int sctp_setsockopt_connectx_old(struct sock *sk, 138188a0a948SVlad Yasevich struct sockaddr __user *addrs, 138288a0a948SVlad Yasevich int addrs_size) 138388a0a948SVlad Yasevich { 138488a0a948SVlad Yasevich return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL); 138588a0a948SVlad Yasevich } 138688a0a948SVlad Yasevich 138788a0a948SVlad Yasevich /* 138888a0a948SVlad Yasevich * New interface for the API. The since the API is done with a socket 138988a0a948SVlad Yasevich * option, to make it simple we feed back the association id is as a return 139088a0a948SVlad Yasevich * indication to the call. Error is always negative and association id is 139188a0a948SVlad Yasevich * always positive. 139288a0a948SVlad Yasevich */ 1393dda91928SDaniel Borkmann static int sctp_setsockopt_connectx(struct sock *sk, 139488a0a948SVlad Yasevich struct sockaddr __user *addrs, 139588a0a948SVlad Yasevich int addrs_size) 139688a0a948SVlad Yasevich { 139788a0a948SVlad Yasevich sctp_assoc_t assoc_id = 0; 139888a0a948SVlad Yasevich int err = 0; 139988a0a948SVlad Yasevich 140088a0a948SVlad Yasevich err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id); 140188a0a948SVlad Yasevich 140288a0a948SVlad Yasevich if (err) 140388a0a948SVlad Yasevich return err; 140488a0a948SVlad Yasevich else 140588a0a948SVlad Yasevich return assoc_id; 140688a0a948SVlad Yasevich } 140788a0a948SVlad Yasevich 1408c6ba68a2SVlad Yasevich /* 1409f9c67811SVlad Yasevich * New (hopefully final) interface for the API. 1410f9c67811SVlad Yasevich * We use the sctp_getaddrs_old structure so that use-space library 1411ffd59393SDaniel Borkmann * can avoid any unnecessary allocations. The only different part 1412f9c67811SVlad Yasevich * is that we store the actual length of the address buffer into the 1413f9c67811SVlad Yasevich * addrs_num structure member. That way we can re-use the existing 1414f9c67811SVlad Yasevich * code. 1415c6ba68a2SVlad Yasevich */ 1416ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT 1417ffd59393SDaniel Borkmann struct compat_sctp_getaddrs_old { 1418ffd59393SDaniel Borkmann sctp_assoc_t assoc_id; 1419ffd59393SDaniel Borkmann s32 addr_num; 1420ffd59393SDaniel Borkmann compat_uptr_t addrs; /* struct sockaddr * */ 1421ffd59393SDaniel Borkmann }; 1422ffd59393SDaniel Borkmann #endif 1423ffd59393SDaniel Borkmann 1424dda91928SDaniel Borkmann static int sctp_getsockopt_connectx3(struct sock *sk, int len, 1425c6ba68a2SVlad Yasevich char __user *optval, 1426c6ba68a2SVlad Yasevich int __user *optlen) 1427c6ba68a2SVlad Yasevich { 1428f9c67811SVlad Yasevich struct sctp_getaddrs_old param; 1429c6ba68a2SVlad Yasevich sctp_assoc_t assoc_id = 0; 1430c6ba68a2SVlad Yasevich int err = 0; 1431c6ba68a2SVlad Yasevich 1432ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT 143396c0e0a9SAndy Lutomirski if (in_compat_syscall()) { 1434ffd59393SDaniel Borkmann struct compat_sctp_getaddrs_old param32; 1435c6ba68a2SVlad Yasevich 1436ffd59393SDaniel Borkmann if (len < sizeof(param32)) 1437ffd59393SDaniel Borkmann return -EINVAL; 1438ffd59393SDaniel Borkmann if (copy_from_user(¶m32, optval, sizeof(param32))) 1439f9c67811SVlad Yasevich return -EFAULT; 1440f9c67811SVlad Yasevich 1441ffd59393SDaniel Borkmann param.assoc_id = param32.assoc_id; 1442ffd59393SDaniel Borkmann param.addr_num = param32.addr_num; 1443ffd59393SDaniel Borkmann param.addrs = compat_ptr(param32.addrs); 1444ffd59393SDaniel Borkmann } else 1445ffd59393SDaniel Borkmann #endif 1446ffd59393SDaniel Borkmann { 1447ffd59393SDaniel Borkmann if (len < sizeof(param)) 1448ffd59393SDaniel Borkmann return -EINVAL; 1449ffd59393SDaniel Borkmann if (copy_from_user(¶m, optval, sizeof(param))) 1450ffd59393SDaniel Borkmann return -EFAULT; 1451ffd59393SDaniel Borkmann } 1452c6ba68a2SVlad Yasevich 1453ffd59393SDaniel Borkmann err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *) 1454ffd59393SDaniel Borkmann param.addrs, param.addr_num, 1455ffd59393SDaniel Borkmann &assoc_id); 1456c6ba68a2SVlad Yasevich if (err == 0 || err == -EINPROGRESS) { 1457c6ba68a2SVlad Yasevich if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) 1458c6ba68a2SVlad Yasevich return -EFAULT; 1459c6ba68a2SVlad Yasevich if (put_user(sizeof(assoc_id), optlen)) 1460c6ba68a2SVlad Yasevich return -EFAULT; 1461c6ba68a2SVlad Yasevich } 1462c6ba68a2SVlad Yasevich 1463c6ba68a2SVlad Yasevich return err; 1464c6ba68a2SVlad Yasevich } 1465c6ba68a2SVlad Yasevich 14661da177e4SLinus Torvalds /* API 3.1.4 close() - UDP Style Syntax 14671da177e4SLinus Torvalds * Applications use close() to perform graceful shutdown (as described in 14681da177e4SLinus Torvalds * Section 10.1 of [SCTP]) on ALL the associations currently represented 14691da177e4SLinus Torvalds * by a UDP-style socket. 14701da177e4SLinus Torvalds * 14711da177e4SLinus Torvalds * The syntax is 14721da177e4SLinus Torvalds * 14731da177e4SLinus Torvalds * ret = close(int sd); 14741da177e4SLinus Torvalds * 14751da177e4SLinus Torvalds * sd - the socket descriptor of the associations to be closed. 14761da177e4SLinus Torvalds * 14771da177e4SLinus Torvalds * To gracefully shutdown a specific association represented by the 14781da177e4SLinus Torvalds * UDP-style socket, an application should use the sendmsg() call, 14791da177e4SLinus Torvalds * passing no user data, but including the appropriate flag in the 14801da177e4SLinus Torvalds * ancillary data (see Section xxxx). 14811da177e4SLinus Torvalds * 14821da177e4SLinus Torvalds * If sd in the close() call is a branched-off socket representing only 14831da177e4SLinus Torvalds * one association, the shutdown is performed on that association only. 14841da177e4SLinus Torvalds * 14851da177e4SLinus Torvalds * 4.1.6 close() - TCP Style Syntax 14861da177e4SLinus Torvalds * 14871da177e4SLinus Torvalds * Applications use close() to gracefully close down an association. 14881da177e4SLinus Torvalds * 14891da177e4SLinus Torvalds * The syntax is: 14901da177e4SLinus Torvalds * 14911da177e4SLinus Torvalds * int close(int sd); 14921da177e4SLinus Torvalds * 14931da177e4SLinus Torvalds * sd - the socket descriptor of the association to be closed. 14941da177e4SLinus Torvalds * 14951da177e4SLinus Torvalds * After an application calls close() on a socket descriptor, no further 14961da177e4SLinus Torvalds * socket operations will succeed on that descriptor. 14971da177e4SLinus Torvalds * 14981da177e4SLinus Torvalds * API 7.1.4 SO_LINGER 14991da177e4SLinus Torvalds * 15001da177e4SLinus Torvalds * An application using the TCP-style socket can use this option to 15011da177e4SLinus Torvalds * perform the SCTP ABORT primitive. The linger option structure is: 15021da177e4SLinus Torvalds * 15031da177e4SLinus Torvalds * struct linger { 15041da177e4SLinus Torvalds * int l_onoff; // option on/off 15051da177e4SLinus Torvalds * int l_linger; // linger time 15061da177e4SLinus Torvalds * }; 15071da177e4SLinus Torvalds * 15081da177e4SLinus Torvalds * To enable the option, set l_onoff to 1. If the l_linger value is set 15091da177e4SLinus Torvalds * to 0, calling close() is the same as the ABORT primitive. If the 15101da177e4SLinus Torvalds * value is set to a negative value, the setsockopt() call will return 15111da177e4SLinus Torvalds * an error. If the value is set to a positive value linger_time, the 15121da177e4SLinus Torvalds * close() can be blocked for at most linger_time ms. If the graceful 15131da177e4SLinus Torvalds * shutdown phase does not finish during this period, close() will 15141da177e4SLinus Torvalds * return but the graceful shutdown phase continues in the system. 15151da177e4SLinus Torvalds */ 1516dda91928SDaniel Borkmann static void sctp_close(struct sock *sk, long timeout) 15171da177e4SLinus Torvalds { 151855e26eb9SEric W. Biederman struct net *net = sock_net(sk); 15191da177e4SLinus Torvalds struct sctp_endpoint *ep; 15201da177e4SLinus Torvalds struct sctp_association *asoc; 15211da177e4SLinus Torvalds struct list_head *pos, *temp; 1522cd4fcc70SThomas Graf unsigned int data_was_unread; 15231da177e4SLinus Torvalds 1524bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout); 15251da177e4SLinus Torvalds 15266dfe4b97SXin Long lock_sock_nested(sk, SINGLE_DEPTH_NESTING); 15271da177e4SLinus Torvalds sk->sk_shutdown = SHUTDOWN_MASK; 1528cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_CLOSING); 15291da177e4SLinus Torvalds 15301da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 15311da177e4SLinus Torvalds 1532cd4fcc70SThomas Graf /* Clean up any skbs sitting on the receive queue. */ 1533cd4fcc70SThomas Graf data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue); 1534cd4fcc70SThomas Graf data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); 1535cd4fcc70SThomas Graf 153661c9fed4SVladislav Yasevich /* Walk all associations on an endpoint. */ 15371da177e4SLinus Torvalds list_for_each_safe(pos, temp, &ep->asocs) { 15381da177e4SLinus Torvalds asoc = list_entry(pos, struct sctp_association, asocs); 15391da177e4SLinus Torvalds 15401da177e4SLinus Torvalds if (sctp_style(sk, TCP)) { 15411da177e4SLinus Torvalds /* A closed association can still be in the list if 15421da177e4SLinus Torvalds * it belongs to a TCP-style listening socket that is 15431da177e4SLinus Torvalds * not yet accepted. If so, free it. If not, send an 15441da177e4SLinus Torvalds * ABORT or SHUTDOWN based on the linger options. 15451da177e4SLinus Torvalds */ 15461da177e4SLinus Torvalds if (sctp_state(asoc, CLOSED)) { 15471da177e4SLinus Torvalds sctp_association_free(asoc); 1548b89498a1SVladislav Yasevich continue; 1549b89498a1SVladislav Yasevich } 1550b89498a1SVladislav Yasevich } 15511da177e4SLinus Torvalds 1552cd4fcc70SThomas Graf if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) || 1553cd4fcc70SThomas Graf !skb_queue_empty(&asoc->ulpq.reasm) || 155413228238SXin Long !skb_queue_empty(&asoc->ulpq.reasm_uo) || 1555cd4fcc70SThomas Graf (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { 1556b9ac8672SSridhar Samudrala struct sctp_chunk *chunk; 1557b9ac8672SSridhar Samudrala 1558b9ac8672SSridhar Samudrala chunk = sctp_make_abort_user(asoc, NULL, 0); 155955e26eb9SEric W. Biederman sctp_primitive_ABORT(net, asoc, chunk); 1560b9ac8672SSridhar Samudrala } else 156155e26eb9SEric W. Biederman sctp_primitive_SHUTDOWN(net, asoc, NULL); 15621da177e4SLinus Torvalds } 15631da177e4SLinus Torvalds 15641da177e4SLinus Torvalds /* On a TCP-style socket, block for at most linger_time if set. */ 15651da177e4SLinus Torvalds if (sctp_style(sk, TCP) && timeout) 15661da177e4SLinus Torvalds sctp_wait_for_close(sk, timeout); 15671da177e4SLinus Torvalds 15681da177e4SLinus Torvalds /* This will run the backlog queue. */ 1569048ed4b6Swangweidong release_sock(sk); 15701da177e4SLinus Torvalds 15711da177e4SLinus Torvalds /* Supposedly, no process has access to the socket, but 15721da177e4SLinus Torvalds * the net layers still may. 15732d45a02dSMarcelo Ricardo Leitner * Also, sctp_destroy_sock() needs to be called with addr_wq_lock 15742d45a02dSMarcelo Ricardo Leitner * held and that should be grabbed before socket lock. 15751da177e4SLinus Torvalds */ 15762d45a02dSMarcelo Ricardo Leitner spin_lock_bh(&net->sctp.addr_wq_lock); 15776dfe4b97SXin Long bh_lock_sock_nested(sk); 15781da177e4SLinus Torvalds 15791da177e4SLinus Torvalds /* Hold the sock, since sk_common_release() will put sock_put() 15801da177e4SLinus Torvalds * and we have just a little more cleanup. 15811da177e4SLinus Torvalds */ 15821da177e4SLinus Torvalds sock_hold(sk); 15831da177e4SLinus Torvalds sk_common_release(sk); 15841da177e4SLinus Torvalds 15855bc1d1b4Swangweidong bh_unlock_sock(sk); 15862d45a02dSMarcelo Ricardo Leitner spin_unlock_bh(&net->sctp.addr_wq_lock); 15871da177e4SLinus Torvalds 15881da177e4SLinus Torvalds sock_put(sk); 15891da177e4SLinus Torvalds 15901da177e4SLinus Torvalds SCTP_DBG_OBJCNT_DEC(sock); 15911da177e4SLinus Torvalds } 15921da177e4SLinus Torvalds 15931da177e4SLinus Torvalds /* Handle EPIPE error. */ 15941da177e4SLinus Torvalds static int sctp_error(struct sock *sk, int flags, int err) 15951da177e4SLinus Torvalds { 15961da177e4SLinus Torvalds if (err == -EPIPE) 15971da177e4SLinus Torvalds err = sock_error(sk) ? : -EPIPE; 15981da177e4SLinus Torvalds if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) 15991da177e4SLinus Torvalds send_sig(SIGPIPE, current, 0); 16001da177e4SLinus Torvalds return err; 16011da177e4SLinus Torvalds } 16021da177e4SLinus Torvalds 16031da177e4SLinus Torvalds /* API 3.1.3 sendmsg() - UDP Style Syntax 16041da177e4SLinus Torvalds * 16051da177e4SLinus Torvalds * An application uses sendmsg() and recvmsg() calls to transmit data to 16061da177e4SLinus Torvalds * and receive data from its peer. 16071da177e4SLinus Torvalds * 16081da177e4SLinus Torvalds * ssize_t sendmsg(int socket, const struct msghdr *message, 16091da177e4SLinus Torvalds * int flags); 16101da177e4SLinus Torvalds * 16111da177e4SLinus Torvalds * socket - the socket descriptor of the endpoint. 16121da177e4SLinus Torvalds * message - pointer to the msghdr structure which contains a single 16131da177e4SLinus Torvalds * user message and possibly some ancillary data. 16141da177e4SLinus Torvalds * 16151da177e4SLinus Torvalds * See Section 5 for complete description of the data 16161da177e4SLinus Torvalds * structures. 16171da177e4SLinus Torvalds * 16181da177e4SLinus Torvalds * flags - flags sent or received with the user message, see Section 16191da177e4SLinus Torvalds * 5 for complete description of the flags. 16201da177e4SLinus Torvalds * 16211da177e4SLinus Torvalds * Note: This function could use a rewrite especially when explicit 16221da177e4SLinus Torvalds * connect support comes in. 16231da177e4SLinus Torvalds */ 16241da177e4SLinus Torvalds /* BUG: We do not implement the equivalent of sk_stream_wait_memory(). */ 16251da177e4SLinus Torvalds 1626a05437acSXin Long static int sctp_msghdr_parse(const struct msghdr *msg, 1627a05437acSXin Long struct sctp_cmsgs *cmsgs); 16281da177e4SLinus Torvalds 1629204f817fSXin Long static int sctp_sendmsg_parse(struct sock *sk, struct sctp_cmsgs *cmsgs, 1630204f817fSXin Long struct sctp_sndrcvinfo *srinfo, 1631204f817fSXin Long const struct msghdr *msg, size_t msg_len) 1632204f817fSXin Long { 1633204f817fSXin Long __u16 sflags; 1634204f817fSXin Long int err; 1635204f817fSXin Long 1636204f817fSXin Long if (sctp_sstate(sk, LISTENING) && sctp_style(sk, TCP)) 1637204f817fSXin Long return -EPIPE; 1638204f817fSXin Long 1639204f817fSXin Long if (msg_len > sk->sk_sndbuf) 1640204f817fSXin Long return -EMSGSIZE; 1641204f817fSXin Long 1642204f817fSXin Long memset(cmsgs, 0, sizeof(*cmsgs)); 1643204f817fSXin Long err = sctp_msghdr_parse(msg, cmsgs); 1644204f817fSXin Long if (err) { 1645204f817fSXin Long pr_debug("%s: msghdr parse err:%x\n", __func__, err); 1646204f817fSXin Long return err; 1647204f817fSXin Long } 1648204f817fSXin Long 1649204f817fSXin Long memset(srinfo, 0, sizeof(*srinfo)); 1650204f817fSXin Long if (cmsgs->srinfo) { 1651204f817fSXin Long srinfo->sinfo_stream = cmsgs->srinfo->sinfo_stream; 1652204f817fSXin Long srinfo->sinfo_flags = cmsgs->srinfo->sinfo_flags; 1653204f817fSXin Long srinfo->sinfo_ppid = cmsgs->srinfo->sinfo_ppid; 1654204f817fSXin Long srinfo->sinfo_context = cmsgs->srinfo->sinfo_context; 1655204f817fSXin Long srinfo->sinfo_assoc_id = cmsgs->srinfo->sinfo_assoc_id; 1656204f817fSXin Long srinfo->sinfo_timetolive = cmsgs->srinfo->sinfo_timetolive; 1657204f817fSXin Long } 1658204f817fSXin Long 1659204f817fSXin Long if (cmsgs->sinfo) { 1660204f817fSXin Long srinfo->sinfo_stream = cmsgs->sinfo->snd_sid; 1661204f817fSXin Long srinfo->sinfo_flags = cmsgs->sinfo->snd_flags; 1662204f817fSXin Long srinfo->sinfo_ppid = cmsgs->sinfo->snd_ppid; 1663204f817fSXin Long srinfo->sinfo_context = cmsgs->sinfo->snd_context; 1664204f817fSXin Long srinfo->sinfo_assoc_id = cmsgs->sinfo->snd_assoc_id; 1665204f817fSXin Long } 1666204f817fSXin Long 1667ed63afb8SXin Long if (cmsgs->prinfo) { 1668ed63afb8SXin Long srinfo->sinfo_timetolive = cmsgs->prinfo->pr_value; 1669ed63afb8SXin Long SCTP_PR_SET_POLICY(srinfo->sinfo_flags, 1670ed63afb8SXin Long cmsgs->prinfo->pr_policy); 1671ed63afb8SXin Long } 1672ed63afb8SXin Long 1673204f817fSXin Long sflags = srinfo->sinfo_flags; 1674204f817fSXin Long if (!sflags && msg_len) 1675204f817fSXin Long return 0; 1676204f817fSXin Long 1677204f817fSXin Long if (sctp_style(sk, TCP) && (sflags & (SCTP_EOF | SCTP_ABORT))) 1678204f817fSXin Long return -EINVAL; 1679204f817fSXin Long 1680204f817fSXin Long if (((sflags & SCTP_EOF) && msg_len > 0) || 1681204f817fSXin Long (!(sflags & (SCTP_EOF | SCTP_ABORT)) && msg_len == 0)) 1682204f817fSXin Long return -EINVAL; 1683204f817fSXin Long 1684204f817fSXin Long if ((sflags & SCTP_ADDR_OVER) && !msg->msg_name) 1685204f817fSXin Long return -EINVAL; 1686204f817fSXin Long 1687204f817fSXin Long return 0; 1688204f817fSXin Long } 1689204f817fSXin Long 16902bfd80f9SXin Long static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags, 16912bfd80f9SXin Long struct sctp_cmsgs *cmsgs, 16922bfd80f9SXin Long union sctp_addr *daddr, 16932bfd80f9SXin Long struct sctp_transport **tp) 16942bfd80f9SXin Long { 16952bfd80f9SXin Long struct sctp_endpoint *ep = sctp_sk(sk)->ep; 16962bfd80f9SXin Long struct net *net = sock_net(sk); 16972bfd80f9SXin Long struct sctp_association *asoc; 16982bfd80f9SXin Long enum sctp_scope scope; 16992c0dbaa0SXin Long struct cmsghdr *cmsg; 17004be4139fSXin Long __be32 flowinfo = 0; 17019eda2d2dSLinus Torvalds struct sctp_af *af; 1702d98985ddSWei Yongjun int err; 17032bfd80f9SXin Long 17042bfd80f9SXin Long *tp = NULL; 17052bfd80f9SXin Long 17062bfd80f9SXin Long if (sflags & (SCTP_EOF | SCTP_ABORT)) 17072bfd80f9SXin Long return -EINVAL; 17082bfd80f9SXin Long 17092bfd80f9SXin Long if (sctp_style(sk, TCP) && (sctp_sstate(sk, ESTABLISHED) || 17102bfd80f9SXin Long sctp_sstate(sk, CLOSING))) 17112bfd80f9SXin Long return -EADDRNOTAVAIL; 17122bfd80f9SXin Long 17132bfd80f9SXin Long if (sctp_endpoint_is_peeled_off(ep, daddr)) 17142bfd80f9SXin Long return -EADDRNOTAVAIL; 17152bfd80f9SXin Long 17162bfd80f9SXin Long if (!ep->base.bind_addr.port) { 17172bfd80f9SXin Long if (sctp_autobind(sk)) 17182bfd80f9SXin Long return -EAGAIN; 17192bfd80f9SXin Long } else { 17202bfd80f9SXin Long if (ep->base.bind_addr.port < inet_prot_sock(net) && 17212bfd80f9SXin Long !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 17222bfd80f9SXin Long return -EACCES; 17232bfd80f9SXin Long } 17242bfd80f9SXin Long 17252bfd80f9SXin Long scope = sctp_scope(daddr); 17262bfd80f9SXin Long 17272277c7cdSRichard Haines /* Label connection socket for first association 1-to-many 17282277c7cdSRichard Haines * style for client sequence socket()->sendmsg(). This 17292277c7cdSRichard Haines * needs to be done before sctp_assoc_add_peer() as that will 17302277c7cdSRichard Haines * set up the initial packet that needs to account for any 17312277c7cdSRichard Haines * security ip options (CIPSO/CALIPSO) added to the packet. 17322277c7cdSRichard Haines */ 17339eda2d2dSLinus Torvalds af = sctp_get_af_specific(daddr->sa.sa_family); 17349eda2d2dSLinus Torvalds if (!af) 17359eda2d2dSLinus Torvalds return -EINVAL; 17362277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_SENDMSG_CONNECT, 17379eda2d2dSLinus Torvalds (struct sockaddr *)daddr, 17382277c7cdSRichard Haines af->sockaddr_len); 17392277c7cdSRichard Haines if (err < 0) 17409eda2d2dSLinus Torvalds return err; 17412277c7cdSRichard Haines 17422bfd80f9SXin Long asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); 17432bfd80f9SXin Long if (!asoc) 17442bfd80f9SXin Long return -ENOMEM; 17452bfd80f9SXin Long 17462bfd80f9SXin Long if (sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL) < 0) { 17472bfd80f9SXin Long err = -ENOMEM; 17482bfd80f9SXin Long goto free; 17492bfd80f9SXin Long } 17502bfd80f9SXin Long 17512bfd80f9SXin Long if (cmsgs->init) { 17522bfd80f9SXin Long struct sctp_initmsg *init = cmsgs->init; 17532bfd80f9SXin Long 17542bfd80f9SXin Long if (init->sinit_num_ostreams) { 17552bfd80f9SXin Long __u16 outcnt = init->sinit_num_ostreams; 17562bfd80f9SXin Long 17572bfd80f9SXin Long asoc->c.sinit_num_ostreams = outcnt; 17582bfd80f9SXin Long /* outcnt has been changed, need to re-init stream */ 17592bfd80f9SXin Long err = sctp_stream_init(&asoc->stream, outcnt, 0, 17602bfd80f9SXin Long GFP_KERNEL); 17612bfd80f9SXin Long if (err) 17622bfd80f9SXin Long goto free; 17632bfd80f9SXin Long } 17642bfd80f9SXin Long 17652bfd80f9SXin Long if (init->sinit_max_instreams) 17662bfd80f9SXin Long asoc->c.sinit_max_instreams = init->sinit_max_instreams; 17672bfd80f9SXin Long 17682bfd80f9SXin Long if (init->sinit_max_attempts) 17692bfd80f9SXin Long asoc->max_init_attempts = init->sinit_max_attempts; 17702bfd80f9SXin Long 17712bfd80f9SXin Long if (init->sinit_max_init_timeo) 17722bfd80f9SXin Long asoc->max_init_timeo = 17732bfd80f9SXin Long msecs_to_jiffies(init->sinit_max_init_timeo); 17742bfd80f9SXin Long } 17752bfd80f9SXin Long 17762bfd80f9SXin Long *tp = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN); 17772bfd80f9SXin Long if (!*tp) { 17782bfd80f9SXin Long err = -ENOMEM; 17792bfd80f9SXin Long goto free; 17802bfd80f9SXin Long } 17812bfd80f9SXin Long 17822c0dbaa0SXin Long if (!cmsgs->addrs_msg) 17832c0dbaa0SXin Long return 0; 17842c0dbaa0SXin Long 17854be4139fSXin Long if (daddr->sa.sa_family == AF_INET6) 17864be4139fSXin Long flowinfo = daddr->v6.sin6_flowinfo; 17874be4139fSXin Long 17882c0dbaa0SXin Long /* sendv addr list parse */ 17892c0dbaa0SXin Long for_each_cmsghdr(cmsg, cmsgs->addrs_msg) { 17902c0dbaa0SXin Long struct sctp_transport *transport; 17912c0dbaa0SXin Long struct sctp_association *old; 17922c0dbaa0SXin Long union sctp_addr _daddr; 17932c0dbaa0SXin Long int dlen; 17942c0dbaa0SXin Long 17952c0dbaa0SXin Long if (cmsg->cmsg_level != IPPROTO_SCTP || 17962c0dbaa0SXin Long (cmsg->cmsg_type != SCTP_DSTADDRV4 && 17972c0dbaa0SXin Long cmsg->cmsg_type != SCTP_DSTADDRV6)) 17982c0dbaa0SXin Long continue; 17992c0dbaa0SXin Long 18002c0dbaa0SXin Long daddr = &_daddr; 18012c0dbaa0SXin Long memset(daddr, 0, sizeof(*daddr)); 18022c0dbaa0SXin Long dlen = cmsg->cmsg_len - sizeof(struct cmsghdr); 18032c0dbaa0SXin Long if (cmsg->cmsg_type == SCTP_DSTADDRV4) { 1804d98985ddSWei Yongjun if (dlen < sizeof(struct in_addr)) { 1805d98985ddSWei Yongjun err = -EINVAL; 18062c0dbaa0SXin Long goto free; 1807d98985ddSWei Yongjun } 18082c0dbaa0SXin Long 18092c0dbaa0SXin Long dlen = sizeof(struct in_addr); 18102c0dbaa0SXin Long daddr->v4.sin_family = AF_INET; 18112c0dbaa0SXin Long daddr->v4.sin_port = htons(asoc->peer.port); 18122c0dbaa0SXin Long memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen); 18132c0dbaa0SXin Long } else { 1814d98985ddSWei Yongjun if (dlen < sizeof(struct in6_addr)) { 1815d98985ddSWei Yongjun err = -EINVAL; 18162c0dbaa0SXin Long goto free; 1817d98985ddSWei Yongjun } 18182c0dbaa0SXin Long 18192c0dbaa0SXin Long dlen = sizeof(struct in6_addr); 18204be4139fSXin Long daddr->v6.sin6_flowinfo = flowinfo; 18212c0dbaa0SXin Long daddr->v6.sin6_family = AF_INET6; 18222c0dbaa0SXin Long daddr->v6.sin6_port = htons(asoc->peer.port); 18232c0dbaa0SXin Long memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen); 18242c0dbaa0SXin Long } 18252c0dbaa0SXin Long err = sctp_verify_addr(sk, daddr, sizeof(*daddr)); 18262c0dbaa0SXin Long if (err) 18272c0dbaa0SXin Long goto free; 18282c0dbaa0SXin Long 18292c0dbaa0SXin Long old = sctp_endpoint_lookup_assoc(ep, daddr, &transport); 18302c0dbaa0SXin Long if (old && old != asoc) { 18312c0dbaa0SXin Long if (old->state >= SCTP_STATE_ESTABLISHED) 18322c0dbaa0SXin Long err = -EISCONN; 18332c0dbaa0SXin Long else 18342c0dbaa0SXin Long err = -EALREADY; 18352c0dbaa0SXin Long goto free; 18362c0dbaa0SXin Long } 18372c0dbaa0SXin Long 18382c0dbaa0SXin Long if (sctp_endpoint_is_peeled_off(ep, daddr)) { 18392c0dbaa0SXin Long err = -EADDRNOTAVAIL; 18402c0dbaa0SXin Long goto free; 18412c0dbaa0SXin Long } 18422c0dbaa0SXin Long 18432c0dbaa0SXin Long transport = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, 18442c0dbaa0SXin Long SCTP_UNKNOWN); 18452c0dbaa0SXin Long if (!transport) { 18462c0dbaa0SXin Long err = -ENOMEM; 18472c0dbaa0SXin Long goto free; 18482c0dbaa0SXin Long } 18492c0dbaa0SXin Long } 18502c0dbaa0SXin Long 18512bfd80f9SXin Long return 0; 18522bfd80f9SXin Long 18532bfd80f9SXin Long free: 18542bfd80f9SXin Long sctp_association_free(asoc); 18552bfd80f9SXin Long return err; 18562bfd80f9SXin Long } 18572bfd80f9SXin Long 1858c2666de1SXin Long static int sctp_sendmsg_check_sflags(struct sctp_association *asoc, 1859c2666de1SXin Long __u16 sflags, struct msghdr *msg, 1860c2666de1SXin Long size_t msg_len) 1861c2666de1SXin Long { 1862c2666de1SXin Long struct sock *sk = asoc->base.sk; 1863c2666de1SXin Long struct net *net = sock_net(sk); 1864c2666de1SXin Long 1865c2666de1SXin Long if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) 1866c2666de1SXin Long return -EPIPE; 1867c2666de1SXin Long 186849102805SXin Long if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP) && 186949102805SXin Long !sctp_state(asoc, ESTABLISHED)) 187049102805SXin Long return 0; 187149102805SXin Long 1872c2666de1SXin Long if (sflags & SCTP_EOF) { 1873c2666de1SXin Long pr_debug("%s: shutting down association:%p\n", __func__, asoc); 1874c2666de1SXin Long sctp_primitive_SHUTDOWN(net, asoc, NULL); 1875c2666de1SXin Long 1876c2666de1SXin Long return 0; 1877c2666de1SXin Long } 1878c2666de1SXin Long 1879c2666de1SXin Long if (sflags & SCTP_ABORT) { 1880c2666de1SXin Long struct sctp_chunk *chunk; 1881c2666de1SXin Long 1882c2666de1SXin Long chunk = sctp_make_abort_user(asoc, msg, msg_len); 1883c2666de1SXin Long if (!chunk) 1884c2666de1SXin Long return -ENOMEM; 1885c2666de1SXin Long 1886c2666de1SXin Long pr_debug("%s: aborting association:%p\n", __func__, asoc); 1887c2666de1SXin Long sctp_primitive_ABORT(net, asoc, chunk); 1888c2666de1SXin Long 1889c2666de1SXin Long return 0; 1890c2666de1SXin Long } 1891c2666de1SXin Long 1892c2666de1SXin Long return 1; 1893c2666de1SXin Long } 1894c2666de1SXin Long 1895f84af331SXin Long static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, 1896f84af331SXin Long struct msghdr *msg, size_t msg_len, 1897f84af331SXin Long struct sctp_transport *transport, 1898f84af331SXin Long struct sctp_sndrcvinfo *sinfo) 1899f84af331SXin Long { 1900f84af331SXin Long struct sock *sk = asoc->base.sk; 190163d01330SMarcelo Ricardo Leitner struct sctp_sock *sp = sctp_sk(sk); 1902f84af331SXin Long struct net *net = sock_net(sk); 1903f84af331SXin Long struct sctp_datamsg *datamsg; 1904f84af331SXin Long bool wait_connect = false; 1905f84af331SXin Long struct sctp_chunk *chunk; 1906f84af331SXin Long long timeo; 1907f84af331SXin Long int err; 1908f84af331SXin Long 1909f84af331SXin Long if (sinfo->sinfo_stream >= asoc->stream.outcnt) { 1910f84af331SXin Long err = -EINVAL; 1911f84af331SXin Long goto err; 1912f84af331SXin Long } 1913f84af331SXin Long 191405364ca0SKonstantin Khorenko if (unlikely(!SCTP_SO(&asoc->stream, sinfo->sinfo_stream)->ext)) { 1915f84af331SXin Long err = sctp_stream_init_ext(&asoc->stream, sinfo->sinfo_stream); 1916f84af331SXin Long if (err) 1917f84af331SXin Long goto err; 1918f84af331SXin Long } 1919f84af331SXin Long 192063d01330SMarcelo Ricardo Leitner if (sp->disable_fragments && msg_len > asoc->frag_point) { 1921f84af331SXin Long err = -EMSGSIZE; 1922f84af331SXin Long goto err; 1923f84af331SXin Long } 1924f84af331SXin Long 19252521680eSMarcelo Ricardo Leitner if (asoc->pmtu_pending) { 192663d01330SMarcelo Ricardo Leitner if (sp->param_flags & SPP_PMTUD_ENABLE) 19272521680eSMarcelo Ricardo Leitner sctp_assoc_sync_pmtu(asoc); 19282521680eSMarcelo Ricardo Leitner asoc->pmtu_pending = 0; 19292521680eSMarcelo Ricardo Leitner } 19300aee4c25SNeil Horman 19310aee4c25SNeil Horman if (sctp_wspace(asoc) < msg_len) 19320aee4c25SNeil Horman sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc)); 19330aee4c25SNeil Horman 19340aee4c25SNeil Horman if (!sctp_wspace(asoc)) { 19350aee4c25SNeil Horman timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 19360aee4c25SNeil Horman err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); 19370aee4c25SNeil Horman if (err) 19380aee4c25SNeil Horman goto err; 19390aee4c25SNeil Horman } 19400aee4c25SNeil Horman 1941f84af331SXin Long if (sctp_state(asoc, CLOSED)) { 1942f84af331SXin Long err = sctp_primitive_ASSOCIATE(net, asoc, NULL); 1943f84af331SXin Long if (err) 1944f84af331SXin Long goto err; 1945f84af331SXin Long 194663d01330SMarcelo Ricardo Leitner if (sp->strm_interleave) { 1947f84af331SXin Long timeo = sock_sndtimeo(sk, 0); 1948f84af331SXin Long err = sctp_wait_for_connect(asoc, &timeo); 1949f84af331SXin Long if (err) 1950f84af331SXin Long goto err; 1951f84af331SXin Long } else { 1952f84af331SXin Long wait_connect = true; 1953f84af331SXin Long } 1954f84af331SXin Long 1955f84af331SXin Long pr_debug("%s: we associated primitively\n", __func__); 1956f84af331SXin Long } 1957f84af331SXin Long 1958f84af331SXin Long datamsg = sctp_datamsg_from_user(asoc, sinfo, &msg->msg_iter); 1959f84af331SXin Long if (IS_ERR(datamsg)) { 1960f84af331SXin Long err = PTR_ERR(datamsg); 1961f84af331SXin Long goto err; 1962f84af331SXin Long } 1963f84af331SXin Long 1964f84af331SXin Long asoc->force_delay = !!(msg->msg_flags & MSG_MORE); 1965f84af331SXin Long 1966f84af331SXin Long list_for_each_entry(chunk, &datamsg->chunks, frag_list) { 1967f84af331SXin Long sctp_chunk_hold(chunk); 1968f84af331SXin Long sctp_set_owner_w(chunk); 1969f84af331SXin Long chunk->transport = transport; 1970f84af331SXin Long } 1971f84af331SXin Long 1972f84af331SXin Long err = sctp_primitive_SEND(net, asoc, datamsg); 1973f84af331SXin Long if (err) { 1974f84af331SXin Long sctp_datamsg_free(datamsg); 1975f84af331SXin Long goto err; 1976f84af331SXin Long } 1977f84af331SXin Long 1978f84af331SXin Long pr_debug("%s: we sent primitively\n", __func__); 1979f84af331SXin Long 1980f84af331SXin Long sctp_datamsg_put(datamsg); 1981f84af331SXin Long 1982f84af331SXin Long if (unlikely(wait_connect)) { 1983f84af331SXin Long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 1984f84af331SXin Long sctp_wait_for_connect(asoc, &timeo); 1985f84af331SXin Long } 1986f84af331SXin Long 1987f84af331SXin Long err = msg_len; 1988f84af331SXin Long 1989f84af331SXin Long err: 1990f84af331SXin Long return err; 1991f84af331SXin Long } 1992f84af331SXin Long 1993becef9b1SXin Long static union sctp_addr *sctp_sendmsg_get_daddr(struct sock *sk, 1994becef9b1SXin Long const struct msghdr *msg, 1995becef9b1SXin Long struct sctp_cmsgs *cmsgs) 1996becef9b1SXin Long { 1997becef9b1SXin Long union sctp_addr *daddr = NULL; 1998becef9b1SXin Long int err; 1999becef9b1SXin Long 2000becef9b1SXin Long if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) { 2001becef9b1SXin Long int len = msg->msg_namelen; 2002becef9b1SXin Long 2003becef9b1SXin Long if (len > sizeof(*daddr)) 2004becef9b1SXin Long len = sizeof(*daddr); 2005becef9b1SXin Long 2006becef9b1SXin Long daddr = (union sctp_addr *)msg->msg_name; 2007becef9b1SXin Long 2008becef9b1SXin Long err = sctp_verify_addr(sk, daddr, len); 2009becef9b1SXin Long if (err) 2010becef9b1SXin Long return ERR_PTR(err); 2011becef9b1SXin Long } 2012becef9b1SXin Long 2013becef9b1SXin Long return daddr; 2014becef9b1SXin Long } 2015becef9b1SXin Long 2016d42cb06eSXin Long static void sctp_sendmsg_update_sinfo(struct sctp_association *asoc, 2017d42cb06eSXin Long struct sctp_sndrcvinfo *sinfo, 2018d42cb06eSXin Long struct sctp_cmsgs *cmsgs) 2019d42cb06eSXin Long { 2020d42cb06eSXin Long if (!cmsgs->srinfo && !cmsgs->sinfo) { 2021d42cb06eSXin Long sinfo->sinfo_stream = asoc->default_stream; 2022d42cb06eSXin Long sinfo->sinfo_ppid = asoc->default_ppid; 2023d42cb06eSXin Long sinfo->sinfo_context = asoc->default_context; 2024d42cb06eSXin Long sinfo->sinfo_assoc_id = sctp_assoc2id(asoc); 2025ed63afb8SXin Long 2026ed63afb8SXin Long if (!cmsgs->prinfo) 2027ed63afb8SXin Long sinfo->sinfo_flags = asoc->default_flags; 2028d42cb06eSXin Long } 2029d42cb06eSXin Long 2030ed63afb8SXin Long if (!cmsgs->srinfo && !cmsgs->prinfo) 2031d42cb06eSXin Long sinfo->sinfo_timetolive = asoc->default_timetolive; 20323ff547c0SXin Long 20333ff547c0SXin Long if (cmsgs->authinfo) { 20343ff547c0SXin Long /* Reuse sinfo_tsn to indicate that authinfo was set and 20353ff547c0SXin Long * sinfo_ssn to save the keyid on tx path. 20363ff547c0SXin Long */ 20373ff547c0SXin Long sinfo->sinfo_tsn = 1; 20383ff547c0SXin Long sinfo->sinfo_ssn = cmsgs->authinfo->auth_keynumber; 20393ff547c0SXin Long } 2040d42cb06eSXin Long } 2041d42cb06eSXin Long 20421b784140SYing Xue static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) 20431da177e4SLinus Torvalds { 2044204f817fSXin Long struct sctp_endpoint *ep = sctp_sk(sk)->ep; 20458e87c6ebSXin Long struct sctp_transport *transport = NULL; 2046204f817fSXin Long struct sctp_sndrcvinfo _sinfo, *sinfo; 2047007b7e18SXin Long struct sctp_association *asoc; 2048007b7e18SXin Long struct sctp_cmsgs cmsgs; 2049becef9b1SXin Long union sctp_addr *daddr; 2050007b7e18SXin Long bool new = false; 2051007b7e18SXin Long __u16 sflags; 205263b94938SGeir Ola Vaagland int err; 20531da177e4SLinus Torvalds 2054204f817fSXin Long /* Parse and get snd_info */ 2055204f817fSXin Long err = sctp_sendmsg_parse(sk, &cmsgs, &_sinfo, msg, msg_len); 2056204f817fSXin Long if (err) 2057007b7e18SXin Long goto out; 20581da177e4SLinus Torvalds 2059204f817fSXin Long sinfo = &_sinfo; 2060007b7e18SXin Long sflags = sinfo->sinfo_flags; 20611da177e4SLinus Torvalds 2062becef9b1SXin Long /* Get daddr from msg */ 2063becef9b1SXin Long daddr = sctp_sendmsg_get_daddr(sk, msg, &cmsgs); 2064becef9b1SXin Long if (IS_ERR(daddr)) { 2065becef9b1SXin Long err = PTR_ERR(daddr); 2066007b7e18SXin Long goto out; 20671da177e4SLinus Torvalds } 20681da177e4SLinus Torvalds 2069048ed4b6Swangweidong lock_sock(sk); 20701da177e4SLinus Torvalds 207149102805SXin Long /* SCTP_SENDALL process */ 207249102805SXin Long if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) { 207349102805SXin Long list_for_each_entry(asoc, &ep->asocs, asocs) { 207449102805SXin Long err = sctp_sendmsg_check_sflags(asoc, sflags, msg, 207549102805SXin Long msg_len); 207649102805SXin Long if (err == 0) 207749102805SXin Long continue; 207849102805SXin Long if (err < 0) 207949102805SXin Long goto out_unlock; 208049102805SXin Long 208149102805SXin Long sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs); 208249102805SXin Long 208349102805SXin Long err = sctp_sendmsg_to_asoc(asoc, msg, msg_len, 208449102805SXin Long NULL, sinfo); 208549102805SXin Long if (err < 0) 208649102805SXin Long goto out_unlock; 208749102805SXin Long 208849102805SXin Long iov_iter_revert(&msg->msg_iter, err); 208949102805SXin Long } 209049102805SXin Long 209149102805SXin Long goto out_unlock; 209249102805SXin Long } 209349102805SXin Long 20940a3920d2SXin Long /* Get and check or create asoc */ 2095becef9b1SXin Long if (daddr) { 2096becef9b1SXin Long asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport); 20971da177e4SLinus Torvalds if (asoc) { 20980a3920d2SXin Long err = sctp_sendmsg_check_sflags(asoc, sflags, msg, 20990a3920d2SXin Long msg_len); 2100c2666de1SXin Long if (err <= 0) 21011da177e4SLinus Torvalds goto out_unlock; 21020a3920d2SXin Long } else { 2103007b7e18SXin Long err = sctp_sendmsg_new_asoc(sk, sflags, &cmsgs, daddr, 21042bfd80f9SXin Long &transport); 2105625637bfSXin Long if (err) 21062bfd80f9SXin Long goto out_unlock; 21071da177e4SLinus Torvalds 21082bfd80f9SXin Long asoc = transport->asoc; 2109007b7e18SXin Long new = true; 21101da177e4SLinus Torvalds } 21111da177e4SLinus Torvalds 2112007b7e18SXin Long if (!sctp_style(sk, TCP) && !(sflags & SCTP_ADDR_OVER)) 21138e87c6ebSXin Long transport = NULL; 21140a3920d2SXin Long } else { 21150a3920d2SXin Long asoc = sctp_id2assoc(sk, sinfo->sinfo_assoc_id); 21160a3920d2SXin Long if (!asoc) { 21170a3920d2SXin Long err = -EPIPE; 21180a3920d2SXin Long goto out_unlock; 21190a3920d2SXin Long } 21200a3920d2SXin Long 21210a3920d2SXin Long err = sctp_sendmsg_check_sflags(asoc, sflags, msg, msg_len); 21220a3920d2SXin Long if (err <= 0) 21230a3920d2SXin Long goto out_unlock; 21240a3920d2SXin Long } 21258e87c6ebSXin Long 2126d42cb06eSXin Long /* Update snd_info with the asoc */ 2127d42cb06eSXin Long sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs); 21281da177e4SLinus Torvalds 2129f84af331SXin Long /* Send msg to the asoc */ 21308e87c6ebSXin Long err = sctp_sendmsg_to_asoc(asoc, msg, msg_len, transport, sinfo); 2131007b7e18SXin Long if (err < 0 && err != -ESRCH && new) 21321da177e4SLinus Torvalds sctp_association_free(asoc); 21338e87c6ebSXin Long 21341da177e4SLinus Torvalds out_unlock: 2135048ed4b6Swangweidong release_sock(sk); 2136007b7e18SXin Long out: 2137f84af331SXin Long return sctp_error(sk, msg->msg_flags, err); 21381da177e4SLinus Torvalds } 21391da177e4SLinus Torvalds 21401da177e4SLinus Torvalds /* This is an extended version of skb_pull() that removes the data from the 21411da177e4SLinus Torvalds * start of a skb even when data is spread across the list of skb's in the 21421da177e4SLinus Torvalds * frag_list. len specifies the total amount of data that needs to be removed. 21431da177e4SLinus Torvalds * when 'len' bytes could be removed from the skb, it returns 0. 21441da177e4SLinus Torvalds * If 'len' exceeds the total skb length, it returns the no. of bytes that 21451da177e4SLinus Torvalds * could not be removed. 21461da177e4SLinus Torvalds */ 21471da177e4SLinus Torvalds static int sctp_skb_pull(struct sk_buff *skb, int len) 21481da177e4SLinus Torvalds { 21491da177e4SLinus Torvalds struct sk_buff *list; 21501da177e4SLinus Torvalds int skb_len = skb_headlen(skb); 21511da177e4SLinus Torvalds int rlen; 21521da177e4SLinus Torvalds 21531da177e4SLinus Torvalds if (len <= skb_len) { 21541da177e4SLinus Torvalds __skb_pull(skb, len); 21551da177e4SLinus Torvalds return 0; 21561da177e4SLinus Torvalds } 21571da177e4SLinus Torvalds len -= skb_len; 21581da177e4SLinus Torvalds __skb_pull(skb, skb_len); 21591da177e4SLinus Torvalds 21601b003be3SDavid S. Miller skb_walk_frags(skb, list) { 21611da177e4SLinus Torvalds rlen = sctp_skb_pull(list, len); 21621da177e4SLinus Torvalds skb->len -= (len-rlen); 21631da177e4SLinus Torvalds skb->data_len -= (len-rlen); 21641da177e4SLinus Torvalds 21651da177e4SLinus Torvalds if (!rlen) 21661da177e4SLinus Torvalds return 0; 21671da177e4SLinus Torvalds 21681da177e4SLinus Torvalds len = rlen; 21691da177e4SLinus Torvalds } 21701da177e4SLinus Torvalds 21711da177e4SLinus Torvalds return len; 21721da177e4SLinus Torvalds } 21731da177e4SLinus Torvalds 21741da177e4SLinus Torvalds /* API 3.1.3 recvmsg() - UDP Style Syntax 21751da177e4SLinus Torvalds * 21761da177e4SLinus Torvalds * ssize_t recvmsg(int socket, struct msghdr *message, 21771da177e4SLinus Torvalds * int flags); 21781da177e4SLinus Torvalds * 21791da177e4SLinus Torvalds * socket - the socket descriptor of the endpoint. 21801da177e4SLinus Torvalds * message - pointer to the msghdr structure which contains a single 21811da177e4SLinus Torvalds * user message and possibly some ancillary data. 21821da177e4SLinus Torvalds * 21831da177e4SLinus Torvalds * See Section 5 for complete description of the data 21841da177e4SLinus Torvalds * structures. 21851da177e4SLinus Torvalds * 21861da177e4SLinus Torvalds * flags - flags sent or received with the user message, see Section 21871da177e4SLinus Torvalds * 5 for complete description of the flags. 21881da177e4SLinus Torvalds */ 21891b784140SYing Xue static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 21901b784140SYing Xue int noblock, int flags, int *addr_len) 21911da177e4SLinus Torvalds { 21921da177e4SLinus Torvalds struct sctp_ulpevent *event = NULL; 21931da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 21941f45f78fSMarcelo Ricardo Leitner struct sk_buff *skb, *head_skb; 21951da177e4SLinus Torvalds int copied; 21961da177e4SLinus Torvalds int err = 0; 21971da177e4SLinus Torvalds int skb_len; 21981da177e4SLinus Torvalds 2199bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, msghdr:%p, len:%zd, noblock:%d, flags:0x%x, " 2200bb33381dSDaniel Borkmann "addr_len:%p)\n", __func__, sk, msg, len, noblock, flags, 2201bb33381dSDaniel Borkmann addr_len); 22021da177e4SLinus Torvalds 2203048ed4b6Swangweidong lock_sock(sk); 22041da177e4SLinus Torvalds 2205e5b13f34SMarcelo Ricardo Leitner if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED) && 2206e0878694SXin Long !sctp_sstate(sk, CLOSING) && !sctp_sstate(sk, CLOSED)) { 22071da177e4SLinus Torvalds err = -ENOTCONN; 22081da177e4SLinus Torvalds goto out; 22091da177e4SLinus Torvalds } 22101da177e4SLinus Torvalds 22111da177e4SLinus Torvalds skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); 22121da177e4SLinus Torvalds if (!skb) 22131da177e4SLinus Torvalds goto out; 22141da177e4SLinus Torvalds 22151da177e4SLinus Torvalds /* Get the total length of the skb including any skb's in the 22161da177e4SLinus Torvalds * frag_list. 22171da177e4SLinus Torvalds */ 22181da177e4SLinus Torvalds skb_len = skb->len; 22191da177e4SLinus Torvalds 22201da177e4SLinus Torvalds copied = skb_len; 22211da177e4SLinus Torvalds if (copied > len) 22221da177e4SLinus Torvalds copied = len; 22231da177e4SLinus Torvalds 222451f3d02bSDavid S. Miller err = skb_copy_datagram_msg(skb, 0, msg, copied); 22251da177e4SLinus Torvalds 22261da177e4SLinus Torvalds event = sctp_skb2event(skb); 22271da177e4SLinus Torvalds 22281da177e4SLinus Torvalds if (err) 22291da177e4SLinus Torvalds goto out_free; 22301da177e4SLinus Torvalds 22311f45f78fSMarcelo Ricardo Leitner if (event->chunk && event->chunk->head_skb) 22321f45f78fSMarcelo Ricardo Leitner head_skb = event->chunk->head_skb; 22331f45f78fSMarcelo Ricardo Leitner else 22341f45f78fSMarcelo Ricardo Leitner head_skb = skb; 22351f45f78fSMarcelo Ricardo Leitner sock_recv_ts_and_drops(msg, sk, head_skb); 22361da177e4SLinus Torvalds if (sctp_ulpevent_is_notification(event)) { 22371da177e4SLinus Torvalds msg->msg_flags |= MSG_NOTIFICATION; 22381da177e4SLinus Torvalds sp->pf->event_msgname(event, msg->msg_name, addr_len); 22391da177e4SLinus Torvalds } else { 22401f45f78fSMarcelo Ricardo Leitner sp->pf->skb_msgname(head_skb, msg->msg_name, addr_len); 22411da177e4SLinus Torvalds } 22421da177e4SLinus Torvalds 22432347c80fSGeir Ola Vaagland /* Check if we allow SCTP_NXTINFO. */ 22442347c80fSGeir Ola Vaagland if (sp->recvnxtinfo) 22452347c80fSGeir Ola Vaagland sctp_ulpevent_read_nxtinfo(event, msg, sk); 22460d3a421dSGeir Ola Vaagland /* Check if we allow SCTP_RCVINFO. */ 22470d3a421dSGeir Ola Vaagland if (sp->recvrcvinfo) 22480d3a421dSGeir Ola Vaagland sctp_ulpevent_read_rcvinfo(event, msg); 22491da177e4SLinus Torvalds /* Check if we allow SCTP_SNDRCVINFO. */ 22501da177e4SLinus Torvalds if (sp->subscribe.sctp_data_io_event) 22511da177e4SLinus Torvalds sctp_ulpevent_read_sndrcvinfo(event, msg); 22520d3a421dSGeir Ola Vaagland 22531da177e4SLinus Torvalds err = copied; 22541da177e4SLinus Torvalds 22551da177e4SLinus Torvalds /* If skb's length exceeds the user's buffer, update the skb and 22561da177e4SLinus Torvalds * push it back to the receive_queue so that the next call to 22571da177e4SLinus Torvalds * recvmsg() will return the remaining data. Don't set MSG_EOR. 22581da177e4SLinus Torvalds */ 22591da177e4SLinus Torvalds if (skb_len > copied) { 22601da177e4SLinus Torvalds msg->msg_flags &= ~MSG_EOR; 22611da177e4SLinus Torvalds if (flags & MSG_PEEK) 22621da177e4SLinus Torvalds goto out_free; 22631da177e4SLinus Torvalds sctp_skb_pull(skb, copied); 22641da177e4SLinus Torvalds skb_queue_head(&sk->sk_receive_queue, skb); 22651da177e4SLinus Torvalds 2266362d5204SDaniel Borkmann /* When only partial message is copied to the user, increase 2267362d5204SDaniel Borkmann * rwnd by that amount. If all the data in the skb is read, 2268362d5204SDaniel Borkmann * rwnd is updated when the event is freed. 2269362d5204SDaniel Borkmann */ 2270362d5204SDaniel Borkmann if (!sctp_ulpevent_is_notification(event)) 2271362d5204SDaniel Borkmann sctp_assoc_rwnd_increase(event->asoc, copied); 22721da177e4SLinus Torvalds goto out; 22731da177e4SLinus Torvalds } else if ((event->msg_flags & MSG_NOTIFICATION) || 22741da177e4SLinus Torvalds (event->msg_flags & MSG_EOR)) 22751da177e4SLinus Torvalds msg->msg_flags |= MSG_EOR; 22761da177e4SLinus Torvalds else 22771da177e4SLinus Torvalds msg->msg_flags &= ~MSG_EOR; 22781da177e4SLinus Torvalds 22791da177e4SLinus Torvalds out_free: 22801da177e4SLinus Torvalds if (flags & MSG_PEEK) { 22811da177e4SLinus Torvalds /* Release the skb reference acquired after peeking the skb in 22821da177e4SLinus Torvalds * sctp_skb_recv_datagram(). 22831da177e4SLinus Torvalds */ 22841da177e4SLinus Torvalds kfree_skb(skb); 22851da177e4SLinus Torvalds } else { 22861da177e4SLinus Torvalds /* Free the event which includes releasing the reference to 22871da177e4SLinus Torvalds * the owner of the skb, freeing the skb and updating the 22881da177e4SLinus Torvalds * rwnd. 22891da177e4SLinus Torvalds */ 22901da177e4SLinus Torvalds sctp_ulpevent_free(event); 22911da177e4SLinus Torvalds } 22921da177e4SLinus Torvalds out: 2293048ed4b6Swangweidong release_sock(sk); 22941da177e4SLinus Torvalds return err; 22951da177e4SLinus Torvalds } 22961da177e4SLinus Torvalds 22971da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) 22981da177e4SLinus Torvalds * 22991da177e4SLinus Torvalds * This option is a on/off flag. If enabled no SCTP message 23001da177e4SLinus Torvalds * fragmentation will be performed. Instead if a message being sent 23011da177e4SLinus Torvalds * exceeds the current PMTU size, the message will NOT be sent and 23021da177e4SLinus Torvalds * instead a error will be indicated to the user. 23031da177e4SLinus Torvalds */ 23041da177e4SLinus Torvalds static int sctp_setsockopt_disable_fragments(struct sock *sk, 2305b7058842SDavid S. Miller char __user *optval, 2306b7058842SDavid S. Miller unsigned int optlen) 23071da177e4SLinus Torvalds { 23081da177e4SLinus Torvalds int val; 23091da177e4SLinus Torvalds 23101da177e4SLinus Torvalds if (optlen < sizeof(int)) 23111da177e4SLinus Torvalds return -EINVAL; 23121da177e4SLinus Torvalds 23131da177e4SLinus Torvalds if (get_user(val, (int __user *)optval)) 23141da177e4SLinus Torvalds return -EFAULT; 23151da177e4SLinus Torvalds 23161da177e4SLinus Torvalds sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1; 23171da177e4SLinus Torvalds 23181da177e4SLinus Torvalds return 0; 23191da177e4SLinus Torvalds } 23201da177e4SLinus Torvalds 23211da177e4SLinus Torvalds static int sctp_setsockopt_events(struct sock *sk, char __user *optval, 2322b7058842SDavid S. Miller unsigned int optlen) 23231da177e4SLinus Torvalds { 232494912301SWei Yongjun struct sctp_association *asoc; 232594912301SWei Yongjun struct sctp_ulpevent *event; 232694912301SWei Yongjun 23277e8616d8SVlad Yasevich if (optlen > sizeof(struct sctp_event_subscribe)) 23281da177e4SLinus Torvalds return -EINVAL; 23291da177e4SLinus Torvalds if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) 23301da177e4SLinus Torvalds return -EFAULT; 233194912301SWei Yongjun 2332bbbea41dSDaniel Borkmann /* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, 233394912301SWei Yongjun * if there is no data to be sent or retransmit, the stack will 233494912301SWei Yongjun * immediately send up this notification. 233594912301SWei Yongjun */ 233694912301SWei Yongjun if (sctp_ulpevent_type_enabled(SCTP_SENDER_DRY_EVENT, 233794912301SWei Yongjun &sctp_sk(sk)->subscribe)) { 233894912301SWei Yongjun asoc = sctp_id2assoc(sk, 0); 233994912301SWei Yongjun 234094912301SWei Yongjun if (asoc && sctp_outq_is_empty(&asoc->outqueue)) { 234194912301SWei Yongjun event = sctp_ulpevent_make_sender_dry_event(asoc, 23422e83acb9SMarcelo Ricardo Leitner GFP_USER | __GFP_NOWARN); 234394912301SWei Yongjun if (!event) 234494912301SWei Yongjun return -ENOMEM; 234594912301SWei Yongjun 23469162e0edSXin Long asoc->stream.si->enqueue_event(&asoc->ulpq, event); 234794912301SWei Yongjun } 234894912301SWei Yongjun } 234994912301SWei Yongjun 23501da177e4SLinus Torvalds return 0; 23511da177e4SLinus Torvalds } 23521da177e4SLinus Torvalds 23531da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) 23541da177e4SLinus Torvalds * 23551da177e4SLinus Torvalds * This socket option is applicable to the UDP-style socket only. When 23561da177e4SLinus Torvalds * set it will cause associations that are idle for more than the 23571da177e4SLinus Torvalds * specified number of seconds to automatically close. An association 23581da177e4SLinus Torvalds * being idle is defined an association that has NOT sent or received 23591da177e4SLinus Torvalds * user data. The special value of '0' indicates that no automatic 23601da177e4SLinus Torvalds * close of any associations should be performed. The option expects an 23611da177e4SLinus Torvalds * integer defining the number of seconds of idle time before an 23621da177e4SLinus Torvalds * association is closed. 23631da177e4SLinus Torvalds */ 23641da177e4SLinus Torvalds static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, 2365b7058842SDavid S. Miller unsigned int optlen) 23661da177e4SLinus Torvalds { 23671da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 23689f70f46bSNeil Horman struct net *net = sock_net(sk); 23691da177e4SLinus Torvalds 23701da177e4SLinus Torvalds /* Applicable to UDP-style socket only */ 23711da177e4SLinus Torvalds if (sctp_style(sk, TCP)) 23721da177e4SLinus Torvalds return -EOPNOTSUPP; 23731da177e4SLinus Torvalds if (optlen != sizeof(int)) 23741da177e4SLinus Torvalds return -EINVAL; 23751da177e4SLinus Torvalds if (copy_from_user(&sp->autoclose, optval, optlen)) 23761da177e4SLinus Torvalds return -EFAULT; 23771da177e4SLinus Torvalds 23789f70f46bSNeil Horman if (sp->autoclose > net->sctp.max_autoclose) 23799f70f46bSNeil Horman sp->autoclose = net->sctp.max_autoclose; 23809f70f46bSNeil Horman 23811da177e4SLinus Torvalds return 0; 23821da177e4SLinus Torvalds } 23831da177e4SLinus Torvalds 23841da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) 23851da177e4SLinus Torvalds * 23861da177e4SLinus Torvalds * Applications can enable or disable heartbeats for any peer address of 23871da177e4SLinus Torvalds * an association, modify an address's heartbeat interval, force a 23881da177e4SLinus Torvalds * heartbeat to be sent immediately, and adjust the address's maximum 23891da177e4SLinus Torvalds * number of retransmissions sent before an address is considered 23901da177e4SLinus Torvalds * unreachable. The following structure is used to access and modify an 23911da177e4SLinus Torvalds * address's parameters: 23921da177e4SLinus Torvalds * 23931da177e4SLinus Torvalds * struct sctp_paddrparams { 23941da177e4SLinus Torvalds * sctp_assoc_t spp_assoc_id; 23951da177e4SLinus Torvalds * struct sockaddr_storage spp_address; 23961da177e4SLinus Torvalds * uint32_t spp_hbinterval; 23971da177e4SLinus Torvalds * uint16_t spp_pathmaxrxt; 239852ccb8e9SFrank Filz * uint32_t spp_pathmtu; 239952ccb8e9SFrank Filz * uint32_t spp_sackdelay; 240052ccb8e9SFrank Filz * uint32_t spp_flags; 24010b0dce7aSXin Long * uint32_t spp_ipv6_flowlabel; 24020b0dce7aSXin Long * uint8_t spp_dscp; 24031da177e4SLinus Torvalds * }; 24041da177e4SLinus Torvalds * 240552ccb8e9SFrank Filz * spp_assoc_id - (one-to-many style socket) This is filled in the 240652ccb8e9SFrank Filz * application, and identifies the association for 240752ccb8e9SFrank Filz * this query. 24081da177e4SLinus Torvalds * spp_address - This specifies which address is of interest. 24091da177e4SLinus Torvalds * spp_hbinterval - This contains the value of the heartbeat interval, 241052ccb8e9SFrank Filz * in milliseconds. If a value of zero 241152ccb8e9SFrank Filz * is present in this field then no changes are to 241252ccb8e9SFrank Filz * be made to this parameter. 24131da177e4SLinus Torvalds * spp_pathmaxrxt - This contains the maximum number of 24141da177e4SLinus Torvalds * retransmissions before this address shall be 241552ccb8e9SFrank Filz * considered unreachable. If a value of zero 241652ccb8e9SFrank Filz * is present in this field then no changes are to 241752ccb8e9SFrank Filz * be made to this parameter. 241852ccb8e9SFrank Filz * spp_pathmtu - When Path MTU discovery is disabled the value 241952ccb8e9SFrank Filz * specified here will be the "fixed" path mtu. 242052ccb8e9SFrank Filz * Note that if the spp_address field is empty 242152ccb8e9SFrank Filz * then all associations on this address will 242252ccb8e9SFrank Filz * have this fixed path mtu set upon them. 242352ccb8e9SFrank Filz * 242452ccb8e9SFrank Filz * spp_sackdelay - When delayed sack is enabled, this value specifies 242552ccb8e9SFrank Filz * the number of milliseconds that sacks will be delayed 242652ccb8e9SFrank Filz * for. This value will apply to all addresses of an 242752ccb8e9SFrank Filz * association if the spp_address field is empty. Note 242852ccb8e9SFrank Filz * also, that if delayed sack is enabled and this 242952ccb8e9SFrank Filz * value is set to 0, no change is made to the last 243052ccb8e9SFrank Filz * recorded delayed sack timer value. 243152ccb8e9SFrank Filz * 243252ccb8e9SFrank Filz * spp_flags - These flags are used to control various features 243352ccb8e9SFrank Filz * on an association. The flag field may contain 243452ccb8e9SFrank Filz * zero or more of the following options. 243552ccb8e9SFrank Filz * 243652ccb8e9SFrank Filz * SPP_HB_ENABLE - Enable heartbeats on the 243752ccb8e9SFrank Filz * specified address. Note that if the address 243852ccb8e9SFrank Filz * field is empty all addresses for the association 243952ccb8e9SFrank Filz * have heartbeats enabled upon them. 244052ccb8e9SFrank Filz * 244152ccb8e9SFrank Filz * SPP_HB_DISABLE - Disable heartbeats on the 244252ccb8e9SFrank Filz * speicifed address. Note that if the address 244352ccb8e9SFrank Filz * field is empty all addresses for the association 244452ccb8e9SFrank Filz * will have their heartbeats disabled. Note also 244552ccb8e9SFrank Filz * that SPP_HB_ENABLE and SPP_HB_DISABLE are 244652ccb8e9SFrank Filz * mutually exclusive, only one of these two should 244752ccb8e9SFrank Filz * be specified. Enabling both fields will have 244852ccb8e9SFrank Filz * undetermined results. 244952ccb8e9SFrank Filz * 245052ccb8e9SFrank Filz * SPP_HB_DEMAND - Request a user initiated heartbeat 245152ccb8e9SFrank Filz * to be made immediately. 245252ccb8e9SFrank Filz * 2453bdf3092aSVlad Yasevich * SPP_HB_TIME_IS_ZERO - Specify's that the time for 2454bdf3092aSVlad Yasevich * heartbeat delayis to be set to the value of 0 2455bdf3092aSVlad Yasevich * milliseconds. 2456bdf3092aSVlad Yasevich * 245752ccb8e9SFrank Filz * SPP_PMTUD_ENABLE - This field will enable PMTU 245852ccb8e9SFrank Filz * discovery upon the specified address. Note that 245952ccb8e9SFrank Filz * if the address feild is empty then all addresses 246052ccb8e9SFrank Filz * on the association are effected. 246152ccb8e9SFrank Filz * 246252ccb8e9SFrank Filz * SPP_PMTUD_DISABLE - This field will disable PMTU 246352ccb8e9SFrank Filz * discovery upon the specified address. Note that 246452ccb8e9SFrank Filz * if the address feild is empty then all addresses 246552ccb8e9SFrank Filz * on the association are effected. Not also that 246652ccb8e9SFrank Filz * SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually 246752ccb8e9SFrank Filz * exclusive. Enabling both will have undetermined 246852ccb8e9SFrank Filz * results. 246952ccb8e9SFrank Filz * 247052ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE - Setting this flag turns 247152ccb8e9SFrank Filz * on delayed sack. The time specified in spp_sackdelay 247252ccb8e9SFrank Filz * is used to specify the sack delay for this address. Note 247352ccb8e9SFrank Filz * that if spp_address is empty then all addresses will 247452ccb8e9SFrank Filz * enable delayed sack and take on the sack delay 247552ccb8e9SFrank Filz * value specified in spp_sackdelay. 247652ccb8e9SFrank Filz * SPP_SACKDELAY_DISABLE - Setting this flag turns 247752ccb8e9SFrank Filz * off delayed sack. If the spp_address field is blank then 247852ccb8e9SFrank Filz * delayed sack is disabled for the entire association. Note 247952ccb8e9SFrank Filz * also that this field is mutually exclusive to 248052ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE, setting both will have undefined 248152ccb8e9SFrank Filz * results. 24820b0dce7aSXin Long * 24830b0dce7aSXin Long * SPP_IPV6_FLOWLABEL: Setting this flag enables the 24840b0dce7aSXin Long * setting of the IPV6 flow label value. The value is 24850b0dce7aSXin Long * contained in the spp_ipv6_flowlabel field. 24860b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 24870b0dce7aSXin Long * the spp_ipv6_flowlabel field has a valid value returned. 24880b0dce7aSXin Long * If a specific destination address is set (in the 24890b0dce7aSXin Long * spp_address field), then the value returned is that of 24900b0dce7aSXin Long * the address. If just an association is specified (and 24910b0dce7aSXin Long * no address), then the association's default flow label 24920b0dce7aSXin Long * is returned. If neither an association nor a destination 24930b0dce7aSXin Long * is specified, then the socket's default flow label is 24940b0dce7aSXin Long * returned. For non-IPv6 sockets, this flag will be left 24950b0dce7aSXin Long * cleared. 24960b0dce7aSXin Long * 24970b0dce7aSXin Long * SPP_DSCP: Setting this flag enables the setting of the 24980b0dce7aSXin Long * Differentiated Services Code Point (DSCP) value 24990b0dce7aSXin Long * associated with either the association or a specific 25000b0dce7aSXin Long * address. The value is obtained in the spp_dscp field. 25010b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 25020b0dce7aSXin Long * the spp_dscp field has a valid value returned. If a 25030b0dce7aSXin Long * specific destination address is set when called (in the 25040b0dce7aSXin Long * spp_address field), then that specific destination 25050b0dce7aSXin Long * address's DSCP value is returned. If just an association 25060b0dce7aSXin Long * is specified, then the association's default DSCP is 25070b0dce7aSXin Long * returned. If neither an association nor a destination is 25080b0dce7aSXin Long * specified, then the socket's default DSCP is returned. 25090b0dce7aSXin Long * 25100b0dce7aSXin Long * spp_ipv6_flowlabel 25110b0dce7aSXin Long * - This field is used in conjunction with the 25120b0dce7aSXin Long * SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label. 25130b0dce7aSXin Long * The 20 least significant bits are used for the flow 25140b0dce7aSXin Long * label. This setting has precedence over any IPv6-layer 25150b0dce7aSXin Long * setting. 25160b0dce7aSXin Long * 25170b0dce7aSXin Long * spp_dscp - This field is used in conjunction with the SPP_DSCP flag 25180b0dce7aSXin Long * and contains the DSCP. The 6 most significant bits are 25190b0dce7aSXin Long * used for the DSCP. This setting has precedence over any 25200b0dce7aSXin Long * IPv4- or IPv6- layer setting. 25211da177e4SLinus Torvalds */ 252216164366SAdrian Bunk static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, 252352ccb8e9SFrank Filz struct sctp_transport *trans, 252452ccb8e9SFrank Filz struct sctp_association *asoc, 252552ccb8e9SFrank Filz struct sctp_sock *sp, 252652ccb8e9SFrank Filz int hb_change, 252752ccb8e9SFrank Filz int pmtud_change, 252852ccb8e9SFrank Filz int sackdelay_change) 252952ccb8e9SFrank Filz { 253052ccb8e9SFrank Filz int error; 253152ccb8e9SFrank Filz 253252ccb8e9SFrank Filz if (params->spp_flags & SPP_HB_DEMAND && trans) { 253355e26eb9SEric W. Biederman struct net *net = sock_net(trans->asoc->base.sk); 253455e26eb9SEric W. Biederman 253555e26eb9SEric W. Biederman error = sctp_primitive_REQUESTHEARTBEAT(net, trans->asoc, trans); 253652ccb8e9SFrank Filz if (error) 253752ccb8e9SFrank Filz return error; 253852ccb8e9SFrank Filz } 253952ccb8e9SFrank Filz 2540bdf3092aSVlad Yasevich /* Note that unless the spp_flag is set to SPP_HB_ENABLE the value of 2541bdf3092aSVlad Yasevich * this field is ignored. Note also that a value of zero indicates 2542bdf3092aSVlad Yasevich * the current setting should be left unchanged. 2543bdf3092aSVlad Yasevich */ 2544bdf3092aSVlad Yasevich if (params->spp_flags & SPP_HB_ENABLE) { 2545bdf3092aSVlad Yasevich 2546bdf3092aSVlad Yasevich /* Re-zero the interval if the SPP_HB_TIME_IS_ZERO is 2547bdf3092aSVlad Yasevich * set. This lets us use 0 value when this flag 2548bdf3092aSVlad Yasevich * is set. 2549bdf3092aSVlad Yasevich */ 2550bdf3092aSVlad Yasevich if (params->spp_flags & SPP_HB_TIME_IS_ZERO) 2551bdf3092aSVlad Yasevich params->spp_hbinterval = 0; 2552bdf3092aSVlad Yasevich 2553bdf3092aSVlad Yasevich if (params->spp_hbinterval || 2554bdf3092aSVlad Yasevich (params->spp_flags & SPP_HB_TIME_IS_ZERO)) { 255552ccb8e9SFrank Filz if (trans) { 2556bdf3092aSVlad Yasevich trans->hbinterval = 2557bdf3092aSVlad Yasevich msecs_to_jiffies(params->spp_hbinterval); 255852ccb8e9SFrank Filz } else if (asoc) { 2559bdf3092aSVlad Yasevich asoc->hbinterval = 2560bdf3092aSVlad Yasevich msecs_to_jiffies(params->spp_hbinterval); 256152ccb8e9SFrank Filz } else { 256252ccb8e9SFrank Filz sp->hbinterval = params->spp_hbinterval; 256352ccb8e9SFrank Filz } 256452ccb8e9SFrank Filz } 2565bdf3092aSVlad Yasevich } 256652ccb8e9SFrank Filz 256752ccb8e9SFrank Filz if (hb_change) { 256852ccb8e9SFrank Filz if (trans) { 256952ccb8e9SFrank Filz trans->param_flags = 257052ccb8e9SFrank Filz (trans->param_flags & ~SPP_HB) | hb_change; 257152ccb8e9SFrank Filz } else if (asoc) { 257252ccb8e9SFrank Filz asoc->param_flags = 257352ccb8e9SFrank Filz (asoc->param_flags & ~SPP_HB) | hb_change; 257452ccb8e9SFrank Filz } else { 257552ccb8e9SFrank Filz sp->param_flags = 257652ccb8e9SFrank Filz (sp->param_flags & ~SPP_HB) | hb_change; 257752ccb8e9SFrank Filz } 257852ccb8e9SFrank Filz } 257952ccb8e9SFrank Filz 2580bdf3092aSVlad Yasevich /* When Path MTU discovery is disabled the value specified here will 2581bdf3092aSVlad Yasevich * be the "fixed" path mtu (i.e. the value of the spp_flags field must 2582bdf3092aSVlad Yasevich * include the flag SPP_PMTUD_DISABLE for this field to have any 2583bdf3092aSVlad Yasevich * effect). 2584bdf3092aSVlad Yasevich */ 2585bdf3092aSVlad Yasevich if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { 258652ccb8e9SFrank Filz if (trans) { 258752ccb8e9SFrank Filz trans->pathmtu = params->spp_pathmtu; 25883ebfdf08SXin Long sctp_assoc_sync_pmtu(asoc); 258952ccb8e9SFrank Filz } else if (asoc) { 2590c4b2893dSMarcelo Ricardo Leitner sctp_assoc_set_pmtu(asoc, params->spp_pathmtu); 259152ccb8e9SFrank Filz } else { 259252ccb8e9SFrank Filz sp->pathmtu = params->spp_pathmtu; 259352ccb8e9SFrank Filz } 259452ccb8e9SFrank Filz } 259552ccb8e9SFrank Filz 259652ccb8e9SFrank Filz if (pmtud_change) { 259752ccb8e9SFrank Filz if (trans) { 259852ccb8e9SFrank Filz int update = (trans->param_flags & SPP_PMTUD_DISABLE) && 259952ccb8e9SFrank Filz (params->spp_flags & SPP_PMTUD_ENABLE); 260052ccb8e9SFrank Filz trans->param_flags = 260152ccb8e9SFrank Filz (trans->param_flags & ~SPP_PMTUD) | pmtud_change; 260252ccb8e9SFrank Filz if (update) { 26039914ae3cSVlad Yasevich sctp_transport_pmtu(trans, sctp_opt2sk(sp)); 26043ebfdf08SXin Long sctp_assoc_sync_pmtu(asoc); 260552ccb8e9SFrank Filz } 260652ccb8e9SFrank Filz } else if (asoc) { 260752ccb8e9SFrank Filz asoc->param_flags = 260852ccb8e9SFrank Filz (asoc->param_flags & ~SPP_PMTUD) | pmtud_change; 260952ccb8e9SFrank Filz } else { 261052ccb8e9SFrank Filz sp->param_flags = 261152ccb8e9SFrank Filz (sp->param_flags & ~SPP_PMTUD) | pmtud_change; 261252ccb8e9SFrank Filz } 261352ccb8e9SFrank Filz } 261452ccb8e9SFrank Filz 2615bdf3092aSVlad Yasevich /* Note that unless the spp_flag is set to SPP_SACKDELAY_ENABLE the 2616bdf3092aSVlad Yasevich * value of this field is ignored. Note also that a value of zero 2617bdf3092aSVlad Yasevich * indicates the current setting should be left unchanged. 2618bdf3092aSVlad Yasevich */ 2619bdf3092aSVlad Yasevich if ((params->spp_flags & SPP_SACKDELAY_ENABLE) && params->spp_sackdelay) { 262052ccb8e9SFrank Filz if (trans) { 262152ccb8e9SFrank Filz trans->sackdelay = 262252ccb8e9SFrank Filz msecs_to_jiffies(params->spp_sackdelay); 262352ccb8e9SFrank Filz } else if (asoc) { 262452ccb8e9SFrank Filz asoc->sackdelay = 262552ccb8e9SFrank Filz msecs_to_jiffies(params->spp_sackdelay); 262652ccb8e9SFrank Filz } else { 262752ccb8e9SFrank Filz sp->sackdelay = params->spp_sackdelay; 262852ccb8e9SFrank Filz } 262952ccb8e9SFrank Filz } 263052ccb8e9SFrank Filz 263152ccb8e9SFrank Filz if (sackdelay_change) { 263252ccb8e9SFrank Filz if (trans) { 263352ccb8e9SFrank Filz trans->param_flags = 263452ccb8e9SFrank Filz (trans->param_flags & ~SPP_SACKDELAY) | 263552ccb8e9SFrank Filz sackdelay_change; 263652ccb8e9SFrank Filz } else if (asoc) { 263752ccb8e9SFrank Filz asoc->param_flags = 263852ccb8e9SFrank Filz (asoc->param_flags & ~SPP_SACKDELAY) | 263952ccb8e9SFrank Filz sackdelay_change; 264052ccb8e9SFrank Filz } else { 264152ccb8e9SFrank Filz sp->param_flags = 264252ccb8e9SFrank Filz (sp->param_flags & ~SPP_SACKDELAY) | 264352ccb8e9SFrank Filz sackdelay_change; 264452ccb8e9SFrank Filz } 264552ccb8e9SFrank Filz } 264652ccb8e9SFrank Filz 264737051f73SAndrei Pelinescu-Onciul /* Note that a value of zero indicates the current setting should be 264837051f73SAndrei Pelinescu-Onciul left unchanged. 2649bdf3092aSVlad Yasevich */ 265037051f73SAndrei Pelinescu-Onciul if (params->spp_pathmaxrxt) { 265152ccb8e9SFrank Filz if (trans) { 265252ccb8e9SFrank Filz trans->pathmaxrxt = params->spp_pathmaxrxt; 265352ccb8e9SFrank Filz } else if (asoc) { 265452ccb8e9SFrank Filz asoc->pathmaxrxt = params->spp_pathmaxrxt; 265552ccb8e9SFrank Filz } else { 265652ccb8e9SFrank Filz sp->pathmaxrxt = params->spp_pathmaxrxt; 265752ccb8e9SFrank Filz } 265852ccb8e9SFrank Filz } 265952ccb8e9SFrank Filz 26600b0dce7aSXin Long if (params->spp_flags & SPP_IPV6_FLOWLABEL) { 2661741880e1SXin Long if (trans) { 2662741880e1SXin Long if (trans->ipaddr.sa.sa_family == AF_INET6) { 26630b0dce7aSXin Long trans->flowlabel = params->spp_ipv6_flowlabel & 26640b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 26650b0dce7aSXin Long trans->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 2666741880e1SXin Long } 26670b0dce7aSXin Long } else if (asoc) { 2668af8a2b8bSXin Long struct sctp_transport *t; 2669af8a2b8bSXin Long 2670af8a2b8bSXin Long list_for_each_entry(t, &asoc->peer.transport_addr_list, 26710b0dce7aSXin Long transports) { 2672af8a2b8bSXin Long if (t->ipaddr.sa.sa_family != AF_INET6) 26730b0dce7aSXin Long continue; 2674af8a2b8bSXin Long t->flowlabel = params->spp_ipv6_flowlabel & 26750b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 2676af8a2b8bSXin Long t->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 26770b0dce7aSXin Long } 26780b0dce7aSXin Long asoc->flowlabel = params->spp_ipv6_flowlabel & 26790b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 26800b0dce7aSXin Long asoc->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 26810b0dce7aSXin Long } else if (sctp_opt2sk(sp)->sk_family == AF_INET6) { 26820b0dce7aSXin Long sp->flowlabel = params->spp_ipv6_flowlabel & 26830b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 26840b0dce7aSXin Long sp->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 26850b0dce7aSXin Long } 26860b0dce7aSXin Long } 26870b0dce7aSXin Long 26880b0dce7aSXin Long if (params->spp_flags & SPP_DSCP) { 26890b0dce7aSXin Long if (trans) { 26900b0dce7aSXin Long trans->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK; 26910b0dce7aSXin Long trans->dscp |= SCTP_DSCP_SET_MASK; 26920b0dce7aSXin Long } else if (asoc) { 2693af8a2b8bSXin Long struct sctp_transport *t; 2694af8a2b8bSXin Long 2695af8a2b8bSXin Long list_for_each_entry(t, &asoc->peer.transport_addr_list, 26960b0dce7aSXin Long transports) { 2697af8a2b8bSXin Long t->dscp = params->spp_dscp & 26980b0dce7aSXin Long SCTP_DSCP_VAL_MASK; 2699af8a2b8bSXin Long t->dscp |= SCTP_DSCP_SET_MASK; 27000b0dce7aSXin Long } 27010b0dce7aSXin Long asoc->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK; 27020b0dce7aSXin Long asoc->dscp |= SCTP_DSCP_SET_MASK; 27030b0dce7aSXin Long } else { 27040b0dce7aSXin Long sp->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK; 27050b0dce7aSXin Long sp->dscp |= SCTP_DSCP_SET_MASK; 27060b0dce7aSXin Long } 27070b0dce7aSXin Long } 27080b0dce7aSXin Long 270952ccb8e9SFrank Filz return 0; 271052ccb8e9SFrank Filz } 271152ccb8e9SFrank Filz 27121da177e4SLinus Torvalds static int sctp_setsockopt_peer_addr_params(struct sock *sk, 2713b7058842SDavid S. Miller char __user *optval, 2714b7058842SDavid S. Miller unsigned int optlen) 27151da177e4SLinus Torvalds { 27161da177e4SLinus Torvalds struct sctp_paddrparams params; 271752ccb8e9SFrank Filz struct sctp_transport *trans = NULL; 271852ccb8e9SFrank Filz struct sctp_association *asoc = NULL; 271952ccb8e9SFrank Filz struct sctp_sock *sp = sctp_sk(sk); 27201da177e4SLinus Torvalds int error; 272152ccb8e9SFrank Filz int hb_change, pmtud_change, sackdelay_change; 27221da177e4SLinus Torvalds 27230b0dce7aSXin Long if (optlen == sizeof(params)) { 27241da177e4SLinus Torvalds if (copy_from_user(¶ms, optval, optlen)) 27251da177e4SLinus Torvalds return -EFAULT; 27260b0dce7aSXin Long } else if (optlen == ALIGN(offsetof(struct sctp_paddrparams, 27270b0dce7aSXin Long spp_ipv6_flowlabel), 4)) { 27280b0dce7aSXin Long if (copy_from_user(¶ms, optval, optlen)) 27290b0dce7aSXin Long return -EFAULT; 27300b0dce7aSXin Long if (params.spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL)) 27310b0dce7aSXin Long return -EINVAL; 27320b0dce7aSXin Long } else { 27330b0dce7aSXin Long return -EINVAL; 27340b0dce7aSXin Long } 27351da177e4SLinus Torvalds 273652ccb8e9SFrank Filz /* Validate flags and value parameters. */ 273752ccb8e9SFrank Filz hb_change = params.spp_flags & SPP_HB; 273852ccb8e9SFrank Filz pmtud_change = params.spp_flags & SPP_PMTUD; 273952ccb8e9SFrank Filz sackdelay_change = params.spp_flags & SPP_SACKDELAY; 27401da177e4SLinus Torvalds 274152ccb8e9SFrank Filz if (hb_change == SPP_HB || 274252ccb8e9SFrank Filz pmtud_change == SPP_PMTUD || 274352ccb8e9SFrank Filz sackdelay_change == SPP_SACKDELAY || 274452ccb8e9SFrank Filz params.spp_sackdelay > 500 || 2745f64f9e71SJoe Perches (params.spp_pathmtu && 2746f64f9e71SJoe Perches params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT)) 27471da177e4SLinus Torvalds return -EINVAL; 27481da177e4SLinus Torvalds 274952ccb8e9SFrank Filz /* If an address other than INADDR_ANY is specified, and 275052ccb8e9SFrank Filz * no transport is found, then the request is invalid. 275152ccb8e9SFrank Filz */ 275252cae8f0SVlad Yasevich if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { 27531da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, ¶ms.spp_address, 27541da177e4SLinus Torvalds params.spp_assoc_id); 27551da177e4SLinus Torvalds if (!trans) 27561da177e4SLinus Torvalds return -EINVAL; 27571da177e4SLinus Torvalds } 27581da177e4SLinus Torvalds 275952ccb8e9SFrank Filz /* Get association, if assoc_id != 0 and the socket is a one 276052ccb8e9SFrank Filz * to many style socket, and an association was not found, then 276152ccb8e9SFrank Filz * the id was invalid. 27621da177e4SLinus Torvalds */ 276352ccb8e9SFrank Filz asoc = sctp_id2assoc(sk, params.spp_assoc_id); 276452ccb8e9SFrank Filz if (!asoc && params.spp_assoc_id && sctp_style(sk, UDP)) 276552ccb8e9SFrank Filz return -EINVAL; 276652ccb8e9SFrank Filz 276752ccb8e9SFrank Filz /* Heartbeat demand can only be sent on a transport or 276852ccb8e9SFrank Filz * association, but not a socket. 276952ccb8e9SFrank Filz */ 277052ccb8e9SFrank Filz if (params.spp_flags & SPP_HB_DEMAND && !trans && !asoc) 277152ccb8e9SFrank Filz return -EINVAL; 277252ccb8e9SFrank Filz 277352ccb8e9SFrank Filz /* Process parameters. */ 277452ccb8e9SFrank Filz error = sctp_apply_peer_addr_params(¶ms, trans, asoc, sp, 277552ccb8e9SFrank Filz hb_change, pmtud_change, 277652ccb8e9SFrank Filz sackdelay_change); 277752ccb8e9SFrank Filz 277852ccb8e9SFrank Filz if (error) 277952ccb8e9SFrank Filz return error; 278052ccb8e9SFrank Filz 278152ccb8e9SFrank Filz /* If changes are for association, also apply parameters to each 278252ccb8e9SFrank Filz * transport. 278352ccb8e9SFrank Filz */ 278452ccb8e9SFrank Filz if (!trans && asoc) { 27859dbc15f0SRobert P. J. Day list_for_each_entry(trans, &asoc->peer.transport_addr_list, 27869dbc15f0SRobert P. J. Day transports) { 278752ccb8e9SFrank Filz sctp_apply_peer_addr_params(¶ms, trans, asoc, sp, 278852ccb8e9SFrank Filz hb_change, pmtud_change, 278952ccb8e9SFrank Filz sackdelay_change); 279052ccb8e9SFrank Filz } 279152ccb8e9SFrank Filz } 27921da177e4SLinus Torvalds 27931da177e4SLinus Torvalds return 0; 27941da177e4SLinus Torvalds } 27951da177e4SLinus Torvalds 27960ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags) 27970ea5e4dfSwangweidong { 27980ea5e4dfSwangweidong return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; 27990ea5e4dfSwangweidong } 28000ea5e4dfSwangweidong 28010ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags) 28020ea5e4dfSwangweidong { 28030ea5e4dfSwangweidong return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; 28040ea5e4dfSwangweidong } 28050ea5e4dfSwangweidong 2806d364d927SWei Yongjun /* 2807d364d927SWei Yongjun * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 28087708610bSFrank Filz * 2809d364d927SWei Yongjun * This option will effect the way delayed acks are performed. This 2810d364d927SWei Yongjun * option allows you to get or set the delayed ack time, in 2811d364d927SWei Yongjun * milliseconds. It also allows changing the delayed ack frequency. 2812d364d927SWei Yongjun * Changing the frequency to 1 disables the delayed sack algorithm. If 2813d364d927SWei Yongjun * the assoc_id is 0, then this sets or gets the endpoints default 2814d364d927SWei Yongjun * values. If the assoc_id field is non-zero, then the set or get 2815d364d927SWei Yongjun * effects the specified association for the one to many model (the 2816d364d927SWei Yongjun * assoc_id field is ignored by the one to one model). Note that if 2817d364d927SWei Yongjun * sack_delay or sack_freq are 0 when setting this option, then the 2818d364d927SWei Yongjun * current values will remain unchanged. 28197708610bSFrank Filz * 2820d364d927SWei Yongjun * struct sctp_sack_info { 2821d364d927SWei Yongjun * sctp_assoc_t sack_assoc_id; 2822d364d927SWei Yongjun * uint32_t sack_delay; 2823d364d927SWei Yongjun * uint32_t sack_freq; 28247708610bSFrank Filz * }; 28257708610bSFrank Filz * 2826d364d927SWei Yongjun * sack_assoc_id - This parameter, indicates which association the user 2827d364d927SWei Yongjun * is performing an action upon. Note that if this field's value is 2828d364d927SWei Yongjun * zero then the endpoints default value is changed (effecting future 28297708610bSFrank Filz * associations only). 28307708610bSFrank Filz * 2831d364d927SWei Yongjun * sack_delay - This parameter contains the number of milliseconds that 2832d364d927SWei Yongjun * the user is requesting the delayed ACK timer be set to. Note that 2833d364d927SWei Yongjun * this value is defined in the standard to be between 200 and 500 2834d364d927SWei Yongjun * milliseconds. 28357708610bSFrank Filz * 2836d364d927SWei Yongjun * sack_freq - This parameter contains the number of packets that must 2837d364d927SWei Yongjun * be received before a sack is sent without waiting for the delay 2838d364d927SWei Yongjun * timer to expire. The default value for this is 2, setting this 2839d364d927SWei Yongjun * value to 1 will disable the delayed sack algorithm. 28407708610bSFrank Filz */ 28417708610bSFrank Filz 2842d364d927SWei Yongjun static int sctp_setsockopt_delayed_ack(struct sock *sk, 2843b7058842SDavid S. Miller char __user *optval, unsigned int optlen) 28447708610bSFrank Filz { 2845d364d927SWei Yongjun struct sctp_sack_info params; 28467708610bSFrank Filz struct sctp_transport *trans = NULL; 28477708610bSFrank Filz struct sctp_association *asoc = NULL; 28487708610bSFrank Filz struct sctp_sock *sp = sctp_sk(sk); 28497708610bSFrank Filz 2850d364d927SWei Yongjun if (optlen == sizeof(struct sctp_sack_info)) { 28517708610bSFrank Filz if (copy_from_user(¶ms, optval, optlen)) 28527708610bSFrank Filz return -EFAULT; 28537708610bSFrank Filz 2854d364d927SWei Yongjun if (params.sack_delay == 0 && params.sack_freq == 0) 2855d364d927SWei Yongjun return 0; 2856d364d927SWei Yongjun } else if (optlen == sizeof(struct sctp_assoc_value)) { 285794f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 2858f916ec96SNeil Horman "%s (pid %d) " 285994f65193SNeil Horman "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 2860f916ec96SNeil Horman "Use struct sctp_sack_info instead\n", 2861f916ec96SNeil Horman current->comm, task_pid_nr(current)); 2862d364d927SWei Yongjun if (copy_from_user(¶ms, optval, optlen)) 2863d364d927SWei Yongjun return -EFAULT; 2864d364d927SWei Yongjun 2865d364d927SWei Yongjun if (params.sack_delay == 0) 2866d364d927SWei Yongjun params.sack_freq = 1; 2867d364d927SWei Yongjun else 2868d364d927SWei Yongjun params.sack_freq = 0; 2869d364d927SWei Yongjun } else 28707708610bSFrank Filz return -EINVAL; 28717708610bSFrank Filz 2872d364d927SWei Yongjun /* Validate value parameter. */ 2873d364d927SWei Yongjun if (params.sack_delay > 500) 2874d364d927SWei Yongjun return -EINVAL; 2875d364d927SWei Yongjun 2876d364d927SWei Yongjun /* Get association, if sack_assoc_id != 0 and the socket is a one 28777708610bSFrank Filz * to many style socket, and an association was not found, then 28787708610bSFrank Filz * the id was invalid. 28797708610bSFrank Filz */ 2880d364d927SWei Yongjun asoc = sctp_id2assoc(sk, params.sack_assoc_id); 2881d364d927SWei Yongjun if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP)) 28827708610bSFrank Filz return -EINVAL; 28837708610bSFrank Filz 2884d364d927SWei Yongjun if (params.sack_delay) { 28857708610bSFrank Filz if (asoc) { 28867708610bSFrank Filz asoc->sackdelay = 2887d364d927SWei Yongjun msecs_to_jiffies(params.sack_delay); 28887708610bSFrank Filz asoc->param_flags = 28890ea5e4dfSwangweidong sctp_spp_sackdelay_enable(asoc->param_flags); 28907708610bSFrank Filz } else { 2891d364d927SWei Yongjun sp->sackdelay = params.sack_delay; 28927708610bSFrank Filz sp->param_flags = 28930ea5e4dfSwangweidong sctp_spp_sackdelay_enable(sp->param_flags); 28947708610bSFrank Filz } 2895d364d927SWei Yongjun } 2896d364d927SWei Yongjun 2897d364d927SWei Yongjun if (params.sack_freq == 1) { 28987708610bSFrank Filz if (asoc) { 28997708610bSFrank Filz asoc->param_flags = 29000ea5e4dfSwangweidong sctp_spp_sackdelay_disable(asoc->param_flags); 29017708610bSFrank Filz } else { 29027708610bSFrank Filz sp->param_flags = 29030ea5e4dfSwangweidong sctp_spp_sackdelay_disable(sp->param_flags); 29047708610bSFrank Filz } 2905d364d927SWei Yongjun } else if (params.sack_freq > 1) { 2906d364d927SWei Yongjun if (asoc) { 2907d364d927SWei Yongjun asoc->sackfreq = params.sack_freq; 2908d364d927SWei Yongjun asoc->param_flags = 29090ea5e4dfSwangweidong sctp_spp_sackdelay_enable(asoc->param_flags); 2910d364d927SWei Yongjun } else { 2911d364d927SWei Yongjun sp->sackfreq = params.sack_freq; 2912d364d927SWei Yongjun sp->param_flags = 29130ea5e4dfSwangweidong sctp_spp_sackdelay_enable(sp->param_flags); 2914d364d927SWei Yongjun } 29157708610bSFrank Filz } 29167708610bSFrank Filz 29177708610bSFrank Filz /* If change is for association, also apply to each transport. */ 29187708610bSFrank Filz if (asoc) { 29199dbc15f0SRobert P. J. Day list_for_each_entry(trans, &asoc->peer.transport_addr_list, 29209dbc15f0SRobert P. J. Day transports) { 2921d364d927SWei Yongjun if (params.sack_delay) { 29227708610bSFrank Filz trans->sackdelay = 2923d364d927SWei Yongjun msecs_to_jiffies(params.sack_delay); 29247708610bSFrank Filz trans->param_flags = 29250ea5e4dfSwangweidong sctp_spp_sackdelay_enable(trans->param_flags); 2926d364d927SWei Yongjun } 29277bfe8bdbSVlad Yasevich if (params.sack_freq == 1) { 29287708610bSFrank Filz trans->param_flags = 29290ea5e4dfSwangweidong sctp_spp_sackdelay_disable(trans->param_flags); 2930d364d927SWei Yongjun } else if (params.sack_freq > 1) { 2931d364d927SWei Yongjun trans->sackfreq = params.sack_freq; 2932d364d927SWei Yongjun trans->param_flags = 29330ea5e4dfSwangweidong sctp_spp_sackdelay_enable(trans->param_flags); 29347708610bSFrank Filz } 29357708610bSFrank Filz } 29367708610bSFrank Filz } 29377708610bSFrank Filz 29387708610bSFrank Filz return 0; 29397708610bSFrank Filz } 29407708610bSFrank Filz 29411da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG) 29421da177e4SLinus Torvalds * 29431da177e4SLinus Torvalds * Applications can specify protocol parameters for the default association 29441da177e4SLinus Torvalds * initialization. The option name argument to setsockopt() and getsockopt() 29451da177e4SLinus Torvalds * is SCTP_INITMSG. 29461da177e4SLinus Torvalds * 29471da177e4SLinus Torvalds * Setting initialization parameters is effective only on an unconnected 29481da177e4SLinus Torvalds * socket (for UDP-style sockets only future associations are effected 29491da177e4SLinus Torvalds * by the change). With TCP-style sockets, this option is inherited by 29501da177e4SLinus Torvalds * sockets derived from a listener socket. 29511da177e4SLinus Torvalds */ 2952b7058842SDavid S. Miller static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen) 29531da177e4SLinus Torvalds { 29541da177e4SLinus Torvalds struct sctp_initmsg sinit; 29551da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 29561da177e4SLinus Torvalds 29571da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_initmsg)) 29581da177e4SLinus Torvalds return -EINVAL; 29591da177e4SLinus Torvalds if (copy_from_user(&sinit, optval, optlen)) 29601da177e4SLinus Torvalds return -EFAULT; 29611da177e4SLinus Torvalds 29621da177e4SLinus Torvalds if (sinit.sinit_num_ostreams) 29631da177e4SLinus Torvalds sp->initmsg.sinit_num_ostreams = sinit.sinit_num_ostreams; 29641da177e4SLinus Torvalds if (sinit.sinit_max_instreams) 29651da177e4SLinus Torvalds sp->initmsg.sinit_max_instreams = sinit.sinit_max_instreams; 29661da177e4SLinus Torvalds if (sinit.sinit_max_attempts) 29671da177e4SLinus Torvalds sp->initmsg.sinit_max_attempts = sinit.sinit_max_attempts; 29681da177e4SLinus Torvalds if (sinit.sinit_max_init_timeo) 29691da177e4SLinus Torvalds sp->initmsg.sinit_max_init_timeo = sinit.sinit_max_init_timeo; 29701da177e4SLinus Torvalds 29711da177e4SLinus Torvalds return 0; 29721da177e4SLinus Torvalds } 29731da177e4SLinus Torvalds 29741da177e4SLinus Torvalds /* 29751da177e4SLinus Torvalds * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 29761da177e4SLinus Torvalds * 29771da177e4SLinus Torvalds * Applications that wish to use the sendto() system call may wish to 29781da177e4SLinus Torvalds * specify a default set of parameters that would normally be supplied 29791da177e4SLinus Torvalds * through the inclusion of ancillary data. This socket option allows 29801da177e4SLinus Torvalds * such an application to set the default sctp_sndrcvinfo structure. 29811da177e4SLinus Torvalds * The application that wishes to use this socket option simply passes 29821da177e4SLinus Torvalds * in to this call the sctp_sndrcvinfo structure defined in Section 29831da177e4SLinus Torvalds * 5.2.2) The input parameters accepted by this call include 29841da177e4SLinus Torvalds * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 29851da177e4SLinus Torvalds * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 29861da177e4SLinus Torvalds * to this call if the caller is using the UDP model. 29871da177e4SLinus Torvalds */ 29881da177e4SLinus Torvalds static int sctp_setsockopt_default_send_param(struct sock *sk, 2989b7058842SDavid S. Miller char __user *optval, 2990b7058842SDavid S. Miller unsigned int optlen) 29911da177e4SLinus Torvalds { 29921da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 29936b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 29946b3fd5f3SGeir Ola Vaagland struct sctp_sndrcvinfo info; 29951da177e4SLinus Torvalds 29966b3fd5f3SGeir Ola Vaagland if (optlen != sizeof(info)) 29971da177e4SLinus Torvalds return -EINVAL; 29981da177e4SLinus Torvalds if (copy_from_user(&info, optval, optlen)) 29991da177e4SLinus Torvalds return -EFAULT; 30006b3fd5f3SGeir Ola Vaagland if (info.sinfo_flags & 30016b3fd5f3SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 30026b3fd5f3SGeir Ola Vaagland SCTP_ABORT | SCTP_EOF)) 30036b3fd5f3SGeir Ola Vaagland return -EINVAL; 30041da177e4SLinus Torvalds 30051da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); 30061da177e4SLinus Torvalds if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) 30071da177e4SLinus Torvalds return -EINVAL; 30081da177e4SLinus Torvalds if (asoc) { 30091da177e4SLinus Torvalds asoc->default_stream = info.sinfo_stream; 30101da177e4SLinus Torvalds asoc->default_flags = info.sinfo_flags; 30111da177e4SLinus Torvalds asoc->default_ppid = info.sinfo_ppid; 30121da177e4SLinus Torvalds asoc->default_context = info.sinfo_context; 30131da177e4SLinus Torvalds asoc->default_timetolive = info.sinfo_timetolive; 30141da177e4SLinus Torvalds } else { 30151da177e4SLinus Torvalds sp->default_stream = info.sinfo_stream; 30161da177e4SLinus Torvalds sp->default_flags = info.sinfo_flags; 30171da177e4SLinus Torvalds sp->default_ppid = info.sinfo_ppid; 30181da177e4SLinus Torvalds sp->default_context = info.sinfo_context; 30191da177e4SLinus Torvalds sp->default_timetolive = info.sinfo_timetolive; 30201da177e4SLinus Torvalds } 30211da177e4SLinus Torvalds 30221da177e4SLinus Torvalds return 0; 30231da177e4SLinus Torvalds } 30241da177e4SLinus Torvalds 30256b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters 30266b3fd5f3SGeir Ola Vaagland * (SCTP_DEFAULT_SNDINFO) 30276b3fd5f3SGeir Ola Vaagland */ 30286b3fd5f3SGeir Ola Vaagland static int sctp_setsockopt_default_sndinfo(struct sock *sk, 30296b3fd5f3SGeir Ola Vaagland char __user *optval, 30306b3fd5f3SGeir Ola Vaagland unsigned int optlen) 30316b3fd5f3SGeir Ola Vaagland { 30326b3fd5f3SGeir Ola Vaagland struct sctp_sock *sp = sctp_sk(sk); 30336b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 30346b3fd5f3SGeir Ola Vaagland struct sctp_sndinfo info; 30356b3fd5f3SGeir Ola Vaagland 30366b3fd5f3SGeir Ola Vaagland if (optlen != sizeof(info)) 30376b3fd5f3SGeir Ola Vaagland return -EINVAL; 30386b3fd5f3SGeir Ola Vaagland if (copy_from_user(&info, optval, optlen)) 30396b3fd5f3SGeir Ola Vaagland return -EFAULT; 30406b3fd5f3SGeir Ola Vaagland if (info.snd_flags & 30416b3fd5f3SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 30426b3fd5f3SGeir Ola Vaagland SCTP_ABORT | SCTP_EOF)) 30436b3fd5f3SGeir Ola Vaagland return -EINVAL; 30446b3fd5f3SGeir Ola Vaagland 30456b3fd5f3SGeir Ola Vaagland asoc = sctp_id2assoc(sk, info.snd_assoc_id); 30466b3fd5f3SGeir Ola Vaagland if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) 30476b3fd5f3SGeir Ola Vaagland return -EINVAL; 30486b3fd5f3SGeir Ola Vaagland if (asoc) { 30496b3fd5f3SGeir Ola Vaagland asoc->default_stream = info.snd_sid; 30506b3fd5f3SGeir Ola Vaagland asoc->default_flags = info.snd_flags; 30516b3fd5f3SGeir Ola Vaagland asoc->default_ppid = info.snd_ppid; 30526b3fd5f3SGeir Ola Vaagland asoc->default_context = info.snd_context; 30536b3fd5f3SGeir Ola Vaagland } else { 30546b3fd5f3SGeir Ola Vaagland sp->default_stream = info.snd_sid; 30556b3fd5f3SGeir Ola Vaagland sp->default_flags = info.snd_flags; 30566b3fd5f3SGeir Ola Vaagland sp->default_ppid = info.snd_ppid; 30576b3fd5f3SGeir Ola Vaagland sp->default_context = info.snd_context; 30586b3fd5f3SGeir Ola Vaagland } 30596b3fd5f3SGeir Ola Vaagland 30606b3fd5f3SGeir Ola Vaagland return 0; 30616b3fd5f3SGeir Ola Vaagland } 30626b3fd5f3SGeir Ola Vaagland 30631da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 30641da177e4SLinus Torvalds * 30651da177e4SLinus Torvalds * Requests that the local SCTP stack use the enclosed peer address as 30661da177e4SLinus Torvalds * the association primary. The enclosed address must be one of the 30671da177e4SLinus Torvalds * association peer's addresses. 30681da177e4SLinus Torvalds */ 30691da177e4SLinus Torvalds static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, 3070b7058842SDavid S. Miller unsigned int optlen) 30711da177e4SLinus Torvalds { 30721da177e4SLinus Torvalds struct sctp_prim prim; 30731da177e4SLinus Torvalds struct sctp_transport *trans; 30742277c7cdSRichard Haines struct sctp_af *af; 30752277c7cdSRichard Haines int err; 30761da177e4SLinus Torvalds 30771da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_prim)) 30781da177e4SLinus Torvalds return -EINVAL; 30791da177e4SLinus Torvalds 30801da177e4SLinus Torvalds if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) 30811da177e4SLinus Torvalds return -EFAULT; 30821da177e4SLinus Torvalds 30832277c7cdSRichard Haines /* Allow security module to validate address but need address len. */ 30842277c7cdSRichard Haines af = sctp_get_af_specific(prim.ssp_addr.ss_family); 30852277c7cdSRichard Haines if (!af) 30862277c7cdSRichard Haines return -EINVAL; 30872277c7cdSRichard Haines 30882277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR, 30892277c7cdSRichard Haines (struct sockaddr *)&prim.ssp_addr, 30902277c7cdSRichard Haines af->sockaddr_len); 30912277c7cdSRichard Haines if (err) 30922277c7cdSRichard Haines return err; 30932277c7cdSRichard Haines 30941da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id); 30951da177e4SLinus Torvalds if (!trans) 30961da177e4SLinus Torvalds return -EINVAL; 30971da177e4SLinus Torvalds 30981da177e4SLinus Torvalds sctp_assoc_set_primary(trans->asoc, trans); 30991da177e4SLinus Torvalds 31001da177e4SLinus Torvalds return 0; 31011da177e4SLinus Torvalds } 31021da177e4SLinus Torvalds 31031da177e4SLinus Torvalds /* 31041da177e4SLinus Torvalds * 7.1.5 SCTP_NODELAY 31051da177e4SLinus Torvalds * 31061da177e4SLinus Torvalds * Turn on/off any Nagle-like algorithm. This means that packets are 31071da177e4SLinus Torvalds * generally sent as soon as possible and no unnecessary delays are 31081da177e4SLinus Torvalds * introduced, at the cost of more packets in the network. Expects an 31091da177e4SLinus Torvalds * integer boolean flag. 31101da177e4SLinus Torvalds */ 31111da177e4SLinus Torvalds static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval, 3112b7058842SDavid S. Miller unsigned int optlen) 31131da177e4SLinus Torvalds { 31141da177e4SLinus Torvalds int val; 31151da177e4SLinus Torvalds 31161da177e4SLinus Torvalds if (optlen < sizeof(int)) 31171da177e4SLinus Torvalds return -EINVAL; 31181da177e4SLinus Torvalds if (get_user(val, (int __user *)optval)) 31191da177e4SLinus Torvalds return -EFAULT; 31201da177e4SLinus Torvalds 31211da177e4SLinus Torvalds sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; 31221da177e4SLinus Torvalds return 0; 31231da177e4SLinus Torvalds } 31241da177e4SLinus Torvalds 31251da177e4SLinus Torvalds /* 31261da177e4SLinus Torvalds * 31271da177e4SLinus Torvalds * 7.1.1 SCTP_RTOINFO 31281da177e4SLinus Torvalds * 31291da177e4SLinus Torvalds * The protocol parameters used to initialize and bound retransmission 31301da177e4SLinus Torvalds * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 31311da177e4SLinus Torvalds * and modify these parameters. 31321da177e4SLinus Torvalds * All parameters are time values, in milliseconds. A value of 0, when 31331da177e4SLinus Torvalds * modifying the parameters, indicates that the current value should not 31341da177e4SLinus Torvalds * be changed. 31351da177e4SLinus Torvalds * 31361da177e4SLinus Torvalds */ 3137b7058842SDavid S. Miller static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen) 3138b7058842SDavid S. Miller { 31391da177e4SLinus Torvalds struct sctp_rtoinfo rtoinfo; 31401da177e4SLinus Torvalds struct sctp_association *asoc; 314185f935d4Swangweidong unsigned long rto_min, rto_max; 314285f935d4Swangweidong struct sctp_sock *sp = sctp_sk(sk); 31431da177e4SLinus Torvalds 31441da177e4SLinus Torvalds if (optlen != sizeof (struct sctp_rtoinfo)) 31451da177e4SLinus Torvalds return -EINVAL; 31461da177e4SLinus Torvalds 31471da177e4SLinus Torvalds if (copy_from_user(&rtoinfo, optval, optlen)) 31481da177e4SLinus Torvalds return -EFAULT; 31491da177e4SLinus Torvalds 31501da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); 31511da177e4SLinus Torvalds 31521da177e4SLinus Torvalds /* Set the values to the specific association */ 31531da177e4SLinus Torvalds if (!asoc && rtoinfo.srto_assoc_id && sctp_style(sk, UDP)) 31541da177e4SLinus Torvalds return -EINVAL; 31551da177e4SLinus Torvalds 315685f935d4Swangweidong rto_max = rtoinfo.srto_max; 315785f935d4Swangweidong rto_min = rtoinfo.srto_min; 315885f935d4Swangweidong 315985f935d4Swangweidong if (rto_max) 316085f935d4Swangweidong rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max; 316185f935d4Swangweidong else 316285f935d4Swangweidong rto_max = asoc ? asoc->rto_max : sp->rtoinfo.srto_max; 316385f935d4Swangweidong 316485f935d4Swangweidong if (rto_min) 316585f935d4Swangweidong rto_min = asoc ? msecs_to_jiffies(rto_min) : rto_min; 316685f935d4Swangweidong else 316785f935d4Swangweidong rto_min = asoc ? asoc->rto_min : sp->rtoinfo.srto_min; 316885f935d4Swangweidong 316985f935d4Swangweidong if (rto_min > rto_max) 317085f935d4Swangweidong return -EINVAL; 317185f935d4Swangweidong 31721da177e4SLinus Torvalds if (asoc) { 31731da177e4SLinus Torvalds if (rtoinfo.srto_initial != 0) 31741da177e4SLinus Torvalds asoc->rto_initial = 31751da177e4SLinus Torvalds msecs_to_jiffies(rtoinfo.srto_initial); 317685f935d4Swangweidong asoc->rto_max = rto_max; 317785f935d4Swangweidong asoc->rto_min = rto_min; 31781da177e4SLinus Torvalds } else { 31791da177e4SLinus Torvalds /* If there is no association or the association-id = 0 31801da177e4SLinus Torvalds * set the values to the endpoint. 31811da177e4SLinus Torvalds */ 31821da177e4SLinus Torvalds if (rtoinfo.srto_initial != 0) 31831da177e4SLinus Torvalds sp->rtoinfo.srto_initial = rtoinfo.srto_initial; 318485f935d4Swangweidong sp->rtoinfo.srto_max = rto_max; 318585f935d4Swangweidong sp->rtoinfo.srto_min = rto_min; 31861da177e4SLinus Torvalds } 31871da177e4SLinus Torvalds 31881da177e4SLinus Torvalds return 0; 31891da177e4SLinus Torvalds } 31901da177e4SLinus Torvalds 31911da177e4SLinus Torvalds /* 31921da177e4SLinus Torvalds * 31931da177e4SLinus Torvalds * 7.1.2 SCTP_ASSOCINFO 31941da177e4SLinus Torvalds * 319559c51591SMichael Opdenacker * This option is used to tune the maximum retransmission attempts 31961da177e4SLinus Torvalds * of the association. 31971da177e4SLinus Torvalds * Returns an error if the new association retransmission value is 31981da177e4SLinus Torvalds * greater than the sum of the retransmission value of the peer. 31991da177e4SLinus Torvalds * See [SCTP] for more information. 32001da177e4SLinus Torvalds * 32011da177e4SLinus Torvalds */ 3202b7058842SDavid S. Miller static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen) 32031da177e4SLinus Torvalds { 32041da177e4SLinus Torvalds 32051da177e4SLinus Torvalds struct sctp_assocparams assocparams; 32061da177e4SLinus Torvalds struct sctp_association *asoc; 32071da177e4SLinus Torvalds 32081da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_assocparams)) 32091da177e4SLinus Torvalds return -EINVAL; 32101da177e4SLinus Torvalds if (copy_from_user(&assocparams, optval, optlen)) 32111da177e4SLinus Torvalds return -EFAULT; 32121da177e4SLinus Torvalds 32131da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); 32141da177e4SLinus Torvalds 32151da177e4SLinus Torvalds if (!asoc && assocparams.sasoc_assoc_id && sctp_style(sk, UDP)) 32161da177e4SLinus Torvalds return -EINVAL; 32171da177e4SLinus Torvalds 32181da177e4SLinus Torvalds /* Set the values to the specific association */ 32191da177e4SLinus Torvalds if (asoc) { 3220402d68c4SVlad Yasevich if (assocparams.sasoc_asocmaxrxt != 0) { 3221402d68c4SVlad Yasevich __u32 path_sum = 0; 3222402d68c4SVlad Yasevich int paths = 0; 3223402d68c4SVlad Yasevich struct sctp_transport *peer_addr; 3224402d68c4SVlad Yasevich 32259dbc15f0SRobert P. J. Day list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list, 32269dbc15f0SRobert P. J. Day transports) { 3227402d68c4SVlad Yasevich path_sum += peer_addr->pathmaxrxt; 3228402d68c4SVlad Yasevich paths++; 3229402d68c4SVlad Yasevich } 3230402d68c4SVlad Yasevich 3231025dfdafSFrederik Schwarzer /* Only validate asocmaxrxt if we have more than 3232402d68c4SVlad Yasevich * one path/transport. We do this because path 3233402d68c4SVlad Yasevich * retransmissions are only counted when we have more 3234402d68c4SVlad Yasevich * then one path. 3235402d68c4SVlad Yasevich */ 3236402d68c4SVlad Yasevich if (paths > 1 && 3237402d68c4SVlad Yasevich assocparams.sasoc_asocmaxrxt > path_sum) 3238402d68c4SVlad Yasevich return -EINVAL; 3239402d68c4SVlad Yasevich 32401da177e4SLinus Torvalds asoc->max_retrans = assocparams.sasoc_asocmaxrxt; 3241402d68c4SVlad Yasevich } 3242402d68c4SVlad Yasevich 324352db882fSDaniel Borkmann if (assocparams.sasoc_cookie_life != 0) 324452db882fSDaniel Borkmann asoc->cookie_life = ms_to_ktime(assocparams.sasoc_cookie_life); 32451da177e4SLinus Torvalds } else { 32461da177e4SLinus Torvalds /* Set the values to the endpoint */ 32471da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 32481da177e4SLinus Torvalds 32491da177e4SLinus Torvalds if (assocparams.sasoc_asocmaxrxt != 0) 32501da177e4SLinus Torvalds sp->assocparams.sasoc_asocmaxrxt = 32511da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt; 32521da177e4SLinus Torvalds if (assocparams.sasoc_cookie_life != 0) 32531da177e4SLinus Torvalds sp->assocparams.sasoc_cookie_life = 32541da177e4SLinus Torvalds assocparams.sasoc_cookie_life; 32551da177e4SLinus Torvalds } 32561da177e4SLinus Torvalds return 0; 32571da177e4SLinus Torvalds } 32581da177e4SLinus Torvalds 32591da177e4SLinus Torvalds /* 32601da177e4SLinus Torvalds * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 32611da177e4SLinus Torvalds * 32621da177e4SLinus Torvalds * This socket option is a boolean flag which turns on or off mapped V4 32631da177e4SLinus Torvalds * addresses. If this option is turned on and the socket is type 32641da177e4SLinus Torvalds * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 32651da177e4SLinus Torvalds * If this option is turned off, then no mapping will be done of V4 32661da177e4SLinus Torvalds * addresses and a user will receive both PF_INET6 and PF_INET type 32671da177e4SLinus Torvalds * addresses on the socket. 32681da177e4SLinus Torvalds */ 3269b7058842SDavid S. Miller static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen) 32701da177e4SLinus Torvalds { 32711da177e4SLinus Torvalds int val; 32721da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 32731da177e4SLinus Torvalds 32741da177e4SLinus Torvalds if (optlen < sizeof(int)) 32751da177e4SLinus Torvalds return -EINVAL; 32761da177e4SLinus Torvalds if (get_user(val, (int __user *)optval)) 32771da177e4SLinus Torvalds return -EFAULT; 32781da177e4SLinus Torvalds if (val) 32791da177e4SLinus Torvalds sp->v4mapped = 1; 32801da177e4SLinus Torvalds else 32811da177e4SLinus Torvalds sp->v4mapped = 0; 32821da177e4SLinus Torvalds 32831da177e4SLinus Torvalds return 0; 32841da177e4SLinus Torvalds } 32851da177e4SLinus Torvalds 32861da177e4SLinus Torvalds /* 3287e89c2095SWei Yongjun * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 3288e89c2095SWei Yongjun * This option will get or set the maximum size to put in any outgoing 3289e89c2095SWei Yongjun * SCTP DATA chunk. If a message is larger than this size it will be 32901da177e4SLinus Torvalds * fragmented by SCTP into the specified size. Note that the underlying 32911da177e4SLinus Torvalds * SCTP implementation may fragment into smaller sized chunks when the 32921da177e4SLinus Torvalds * PMTU of the underlying association is smaller than the value set by 3293e89c2095SWei Yongjun * the user. The default value for this option is '0' which indicates 3294e89c2095SWei Yongjun * the user is NOT limiting fragmentation and only the PMTU will effect 3295e89c2095SWei Yongjun * SCTP's choice of DATA chunk size. Note also that values set larger 3296e89c2095SWei Yongjun * than the maximum size of an IP datagram will effectively let SCTP 3297e89c2095SWei Yongjun * control fragmentation (i.e. the same as setting this option to 0). 3298e89c2095SWei Yongjun * 3299e89c2095SWei Yongjun * The following structure is used to access and modify this parameter: 3300e89c2095SWei Yongjun * 3301e89c2095SWei Yongjun * struct sctp_assoc_value { 3302e89c2095SWei Yongjun * sctp_assoc_t assoc_id; 3303e89c2095SWei Yongjun * uint32_t assoc_value; 3304e89c2095SWei Yongjun * }; 3305e89c2095SWei Yongjun * 3306e89c2095SWei Yongjun * assoc_id: This parameter is ignored for one-to-one style sockets. 3307e89c2095SWei Yongjun * For one-to-many style sockets this parameter indicates which 3308e89c2095SWei Yongjun * association the user is performing an action upon. Note that if 3309e89c2095SWei Yongjun * this field's value is zero then the endpoints default value is 3310e89c2095SWei Yongjun * changed (effecting future associations only). 3311e89c2095SWei Yongjun * assoc_value: This parameter specifies the maximum size in bytes. 33121da177e4SLinus Torvalds */ 3313b7058842SDavid S. Miller static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen) 33141da177e4SLinus Torvalds { 3315ecca8f88SXin Long struct sctp_sock *sp = sctp_sk(sk); 3316e89c2095SWei Yongjun struct sctp_assoc_value params; 33171da177e4SLinus Torvalds struct sctp_association *asoc; 33181da177e4SLinus Torvalds int val; 33191da177e4SLinus Torvalds 3320e89c2095SWei Yongjun if (optlen == sizeof(int)) { 332194f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 3322f916ec96SNeil Horman "%s (pid %d) " 332394f65193SNeil Horman "Use of int in maxseg socket option.\n" 3324f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 3325f916ec96SNeil Horman current->comm, task_pid_nr(current)); 3326e89c2095SWei Yongjun if (copy_from_user(&val, optval, optlen)) 33271da177e4SLinus Torvalds return -EFAULT; 3328e89c2095SWei Yongjun params.assoc_id = 0; 3329e89c2095SWei Yongjun } else if (optlen == sizeof(struct sctp_assoc_value)) { 3330e89c2095SWei Yongjun if (copy_from_user(¶ms, optval, optlen)) 3331e89c2095SWei Yongjun return -EFAULT; 3332e89c2095SWei Yongjun val = params.assoc_value; 3333ecca8f88SXin Long } else { 3334e89c2095SWei Yongjun return -EINVAL; 3335ecca8f88SXin Long } 3336e89c2095SWei Yongjun 3337439ef030SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 3338439ef030SMarcelo Ricardo Leitner 3339ecca8f88SXin Long if (val) { 3340ecca8f88SXin Long int min_len, max_len; 3341439ef030SMarcelo Ricardo Leitner __u16 datasize = asoc ? sctp_datachk_len(&asoc->stream) : 3342ecca8f88SXin Long sizeof(struct sctp_data_chunk); 3343ecca8f88SXin Long 3344feddd6c1SMarcelo Ricardo Leitner min_len = sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT, 3345439ef030SMarcelo Ricardo Leitner datasize); 3346439ef030SMarcelo Ricardo Leitner max_len = SCTP_MAX_CHUNK_LEN - datasize; 3347ecca8f88SXin Long 3348ecca8f88SXin Long if (val < min_len || val > max_len) 33491da177e4SLinus Torvalds return -EINVAL; 3350ecca8f88SXin Long } 3351e89c2095SWei Yongjun 3352e89c2095SWei Yongjun if (asoc) { 3353f68b2e05SVlad Yasevich asoc->user_frag = val; 33542f5e3c9dSMarcelo Ricardo Leitner sctp_assoc_update_frag_point(asoc); 3355e89c2095SWei Yongjun } else { 3356ecca8f88SXin Long if (params.assoc_id && sctp_style(sk, UDP)) 3357ecca8f88SXin Long return -EINVAL; 33581da177e4SLinus Torvalds sp->user_frag = val; 3359e89c2095SWei Yongjun } 33601da177e4SLinus Torvalds 33611da177e4SLinus Torvalds return 0; 33621da177e4SLinus Torvalds } 33631da177e4SLinus Torvalds 33641da177e4SLinus Torvalds 33651da177e4SLinus Torvalds /* 33661da177e4SLinus Torvalds * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) 33671da177e4SLinus Torvalds * 33681da177e4SLinus Torvalds * Requests that the peer mark the enclosed address as the association 33691da177e4SLinus Torvalds * primary. The enclosed address must be one of the association's 33701da177e4SLinus Torvalds * locally bound addresses. The following structure is used to make a 33711da177e4SLinus Torvalds * set primary request: 33721da177e4SLinus Torvalds */ 33731da177e4SLinus Torvalds static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval, 3374b7058842SDavid S. Miller unsigned int optlen) 33751da177e4SLinus Torvalds { 3376e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 33771da177e4SLinus Torvalds struct sctp_sock *sp; 33781da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 33791da177e4SLinus Torvalds struct sctp_setpeerprim prim; 33801da177e4SLinus Torvalds struct sctp_chunk *chunk; 338140a01039SWei Yongjun struct sctp_af *af; 33821da177e4SLinus Torvalds int err; 33831da177e4SLinus Torvalds 33841da177e4SLinus Torvalds sp = sctp_sk(sk); 33851da177e4SLinus Torvalds 3386e1fc3b14SEric W. Biederman if (!net->sctp.addip_enable) 33871da177e4SLinus Torvalds return -EPERM; 33881da177e4SLinus Torvalds 33891da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_setpeerprim)) 33901da177e4SLinus Torvalds return -EINVAL; 33911da177e4SLinus Torvalds 33921da177e4SLinus Torvalds if (copy_from_user(&prim, optval, optlen)) 33931da177e4SLinus Torvalds return -EFAULT; 33941da177e4SLinus Torvalds 33951da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, prim.sspp_assoc_id); 33961da177e4SLinus Torvalds if (!asoc) 33971da177e4SLinus Torvalds return -EINVAL; 33981da177e4SLinus Torvalds 33991da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 34001da177e4SLinus Torvalds return -EPERM; 34011da177e4SLinus Torvalds 34021da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_SET_PRIMARY) 34031da177e4SLinus Torvalds return -EPERM; 34041da177e4SLinus Torvalds 34051da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 34061da177e4SLinus Torvalds return -ENOTCONN; 34071da177e4SLinus Torvalds 340840a01039SWei Yongjun af = sctp_get_af_specific(prim.sspp_addr.ss_family); 340940a01039SWei Yongjun if (!af) 341040a01039SWei Yongjun return -EINVAL; 341140a01039SWei Yongjun 341240a01039SWei Yongjun if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL)) 341340a01039SWei Yongjun return -EADDRNOTAVAIL; 341440a01039SWei Yongjun 34151da177e4SLinus Torvalds if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr)) 34161da177e4SLinus Torvalds return -EADDRNOTAVAIL; 34171da177e4SLinus Torvalds 34182277c7cdSRichard Haines /* Allow security module to validate address. */ 34192277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR, 34202277c7cdSRichard Haines (struct sockaddr *)&prim.sspp_addr, 34212277c7cdSRichard Haines af->sockaddr_len); 34222277c7cdSRichard Haines if (err) 34232277c7cdSRichard Haines return err; 34242277c7cdSRichard Haines 34251da177e4SLinus Torvalds /* Create an ASCONF chunk with SET_PRIMARY parameter */ 34261da177e4SLinus Torvalds chunk = sctp_make_asconf_set_prim(asoc, 34271da177e4SLinus Torvalds (union sctp_addr *)&prim.sspp_addr); 34281da177e4SLinus Torvalds if (!chunk) 34291da177e4SLinus Torvalds return -ENOMEM; 34301da177e4SLinus Torvalds 34311da177e4SLinus Torvalds err = sctp_send_asconf(asoc, chunk); 34321da177e4SLinus Torvalds 3433bb33381dSDaniel Borkmann pr_debug("%s: we set peer primary addr primitively\n", __func__); 34341da177e4SLinus Torvalds 34351da177e4SLinus Torvalds return err; 34361da177e4SLinus Torvalds } 34371da177e4SLinus Torvalds 34380f3fffd8SIvan Skytte Jorgensen static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval, 3439b7058842SDavid S. Miller unsigned int optlen) 34401da177e4SLinus Torvalds { 34410f3fffd8SIvan Skytte Jorgensen struct sctp_setadaptation adaptation; 34421da177e4SLinus Torvalds 34430f3fffd8SIvan Skytte Jorgensen if (optlen != sizeof(struct sctp_setadaptation)) 34441da177e4SLinus Torvalds return -EINVAL; 34450f3fffd8SIvan Skytte Jorgensen if (copy_from_user(&adaptation, optval, optlen)) 34461da177e4SLinus Torvalds return -EFAULT; 34471da177e4SLinus Torvalds 34480f3fffd8SIvan Skytte Jorgensen sctp_sk(sk)->adaptation_ind = adaptation.ssb_adaptation_ind; 34491da177e4SLinus Torvalds 34501da177e4SLinus Torvalds return 0; 34511da177e4SLinus Torvalds } 34521da177e4SLinus Torvalds 34536ab792f5SIvan Skytte Jorgensen /* 34546ab792f5SIvan Skytte Jorgensen * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 34556ab792f5SIvan Skytte Jorgensen * 34566ab792f5SIvan Skytte Jorgensen * The context field in the sctp_sndrcvinfo structure is normally only 34576ab792f5SIvan Skytte Jorgensen * used when a failed message is retrieved holding the value that was 34586ab792f5SIvan Skytte Jorgensen * sent down on the actual send call. This option allows the setting of 34596ab792f5SIvan Skytte Jorgensen * a default context on an association basis that will be received on 34606ab792f5SIvan Skytte Jorgensen * reading messages from the peer. This is especially helpful in the 34616ab792f5SIvan Skytte Jorgensen * one-2-many model for an application to keep some reference to an 34626ab792f5SIvan Skytte Jorgensen * internal state machine that is processing messages on the 34636ab792f5SIvan Skytte Jorgensen * association. Note that the setting of this value only effects 34646ab792f5SIvan Skytte Jorgensen * received messages from the peer and does not effect the value that is 34656ab792f5SIvan Skytte Jorgensen * saved with outbound messages. 34666ab792f5SIvan Skytte Jorgensen */ 34676ab792f5SIvan Skytte Jorgensen static int sctp_setsockopt_context(struct sock *sk, char __user *optval, 3468b7058842SDavid S. Miller unsigned int optlen) 34696ab792f5SIvan Skytte Jorgensen { 34706ab792f5SIvan Skytte Jorgensen struct sctp_assoc_value params; 34716ab792f5SIvan Skytte Jorgensen struct sctp_sock *sp; 34726ab792f5SIvan Skytte Jorgensen struct sctp_association *asoc; 34736ab792f5SIvan Skytte Jorgensen 34746ab792f5SIvan Skytte Jorgensen if (optlen != sizeof(struct sctp_assoc_value)) 34756ab792f5SIvan Skytte Jorgensen return -EINVAL; 34766ab792f5SIvan Skytte Jorgensen if (copy_from_user(¶ms, optval, optlen)) 34776ab792f5SIvan Skytte Jorgensen return -EFAULT; 34786ab792f5SIvan Skytte Jorgensen 34796ab792f5SIvan Skytte Jorgensen sp = sctp_sk(sk); 34806ab792f5SIvan Skytte Jorgensen 34816ab792f5SIvan Skytte Jorgensen if (params.assoc_id != 0) { 34826ab792f5SIvan Skytte Jorgensen asoc = sctp_id2assoc(sk, params.assoc_id); 34836ab792f5SIvan Skytte Jorgensen if (!asoc) 34846ab792f5SIvan Skytte Jorgensen return -EINVAL; 34856ab792f5SIvan Skytte Jorgensen asoc->default_rcv_context = params.assoc_value; 34866ab792f5SIvan Skytte Jorgensen } else { 34876ab792f5SIvan Skytte Jorgensen sp->default_rcv_context = params.assoc_value; 34886ab792f5SIvan Skytte Jorgensen } 34896ab792f5SIvan Skytte Jorgensen 34906ab792f5SIvan Skytte Jorgensen return 0; 34916ab792f5SIvan Skytte Jorgensen } 34926ab792f5SIvan Skytte Jorgensen 3493b6e1331fSVlad Yasevich /* 3494b6e1331fSVlad Yasevich * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 3495b6e1331fSVlad Yasevich * 3496b6e1331fSVlad Yasevich * This options will at a minimum specify if the implementation is doing 3497b6e1331fSVlad Yasevich * fragmented interleave. Fragmented interleave, for a one to many 3498b6e1331fSVlad Yasevich * socket, is when subsequent calls to receive a message may return 3499b6e1331fSVlad Yasevich * parts of messages from different associations. Some implementations 3500b6e1331fSVlad Yasevich * may allow you to turn this value on or off. If so, when turned off, 3501b6e1331fSVlad Yasevich * no fragment interleave will occur (which will cause a head of line 3502b6e1331fSVlad Yasevich * blocking amongst multiple associations sharing the same one to many 3503b6e1331fSVlad Yasevich * socket). When this option is turned on, then each receive call may 3504b6e1331fSVlad Yasevich * come from a different association (thus the user must receive data 3505b6e1331fSVlad Yasevich * with the extended calls (e.g. sctp_recvmsg) to keep track of which 3506b6e1331fSVlad Yasevich * association each receive belongs to. 3507b6e1331fSVlad Yasevich * 3508b6e1331fSVlad Yasevich * This option takes a boolean value. A non-zero value indicates that 3509b6e1331fSVlad Yasevich * fragmented interleave is on. A value of zero indicates that 3510b6e1331fSVlad Yasevich * fragmented interleave is off. 3511b6e1331fSVlad Yasevich * 3512b6e1331fSVlad Yasevich * Note that it is important that an implementation that allows this 3513b6e1331fSVlad Yasevich * option to be turned on, have it off by default. Otherwise an unaware 3514b6e1331fSVlad Yasevich * application using the one to many model may become confused and act 3515b6e1331fSVlad Yasevich * incorrectly. 3516b6e1331fSVlad Yasevich */ 3517b6e1331fSVlad Yasevich static int sctp_setsockopt_fragment_interleave(struct sock *sk, 3518b6e1331fSVlad Yasevich char __user *optval, 3519b7058842SDavid S. Miller unsigned int optlen) 3520b6e1331fSVlad Yasevich { 3521b6e1331fSVlad Yasevich int val; 3522b6e1331fSVlad Yasevich 3523b6e1331fSVlad Yasevich if (optlen != sizeof(int)) 3524b6e1331fSVlad Yasevich return -EINVAL; 3525b6e1331fSVlad Yasevich if (get_user(val, (int __user *)optval)) 3526b6e1331fSVlad Yasevich return -EFAULT; 3527b6e1331fSVlad Yasevich 3528772a5869SXin Long sctp_sk(sk)->frag_interleave = !!val; 3529772a5869SXin Long 3530772a5869SXin Long if (!sctp_sk(sk)->frag_interleave) 3531772a5869SXin Long sctp_sk(sk)->strm_interleave = 0; 3532b6e1331fSVlad Yasevich 3533b6e1331fSVlad Yasevich return 0; 3534b6e1331fSVlad Yasevich } 3535b6e1331fSVlad Yasevich 3536d49d91d7SVlad Yasevich /* 35378510b937SWei Yongjun * 8.1.21. Set or Get the SCTP Partial Delivery Point 3538d49d91d7SVlad Yasevich * (SCTP_PARTIAL_DELIVERY_POINT) 35398510b937SWei Yongjun * 3540d49d91d7SVlad Yasevich * This option will set or get the SCTP partial delivery point. This 3541d49d91d7SVlad Yasevich * point is the size of a message where the partial delivery API will be 3542d49d91d7SVlad Yasevich * invoked to help free up rwnd space for the peer. Setting this to a 35438510b937SWei Yongjun * lower value will cause partial deliveries to happen more often. The 3544d49d91d7SVlad Yasevich * calls argument is an integer that sets or gets the partial delivery 35458510b937SWei Yongjun * point. Note also that the call will fail if the user attempts to set 35468510b937SWei Yongjun * this value larger than the socket receive buffer size. 35478510b937SWei Yongjun * 35488510b937SWei Yongjun * Note that any single message having a length smaller than or equal to 35498510b937SWei Yongjun * the SCTP partial delivery point will be delivered in one single read 35508510b937SWei Yongjun * call as long as the user provided buffer is large enough to hold the 35518510b937SWei Yongjun * message. 3552d49d91d7SVlad Yasevich */ 3553d49d91d7SVlad Yasevich static int sctp_setsockopt_partial_delivery_point(struct sock *sk, 3554d49d91d7SVlad Yasevich char __user *optval, 3555b7058842SDavid S. Miller unsigned int optlen) 3556d49d91d7SVlad Yasevich { 3557d49d91d7SVlad Yasevich u32 val; 3558d49d91d7SVlad Yasevich 3559d49d91d7SVlad Yasevich if (optlen != sizeof(u32)) 3560d49d91d7SVlad Yasevich return -EINVAL; 3561d49d91d7SVlad Yasevich if (get_user(val, (int __user *)optval)) 3562d49d91d7SVlad Yasevich return -EFAULT; 3563d49d91d7SVlad Yasevich 35648510b937SWei Yongjun /* Note: We double the receive buffer from what the user sets 35658510b937SWei Yongjun * it to be, also initial rwnd is based on rcvbuf/2. 35668510b937SWei Yongjun */ 35678510b937SWei Yongjun if (val > (sk->sk_rcvbuf >> 1)) 35688510b937SWei Yongjun return -EINVAL; 35698510b937SWei Yongjun 3570d49d91d7SVlad Yasevich sctp_sk(sk)->pd_point = val; 3571d49d91d7SVlad Yasevich 3572d49d91d7SVlad Yasevich return 0; /* is this the right error code? */ 3573d49d91d7SVlad Yasevich } 3574d49d91d7SVlad Yasevich 357570331571SVlad Yasevich /* 357670331571SVlad Yasevich * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 357770331571SVlad Yasevich * 357870331571SVlad Yasevich * This option will allow a user to change the maximum burst of packets 357970331571SVlad Yasevich * that can be emitted by this association. Note that the default value 358070331571SVlad Yasevich * is 4, and some implementations may restrict this setting so that it 358170331571SVlad Yasevich * can only be lowered. 358270331571SVlad Yasevich * 358370331571SVlad Yasevich * NOTE: This text doesn't seem right. Do this on a socket basis with 358470331571SVlad Yasevich * future associations inheriting the socket value. 358570331571SVlad Yasevich */ 358670331571SVlad Yasevich static int sctp_setsockopt_maxburst(struct sock *sk, 358770331571SVlad Yasevich char __user *optval, 3588b7058842SDavid S. Miller unsigned int optlen) 358970331571SVlad Yasevich { 3590219b99a9SNeil Horman struct sctp_assoc_value params; 3591219b99a9SNeil Horman struct sctp_sock *sp; 3592219b99a9SNeil Horman struct sctp_association *asoc; 359370331571SVlad Yasevich int val; 3594219b99a9SNeil Horman int assoc_id = 0; 359570331571SVlad Yasevich 3596219b99a9SNeil Horman if (optlen == sizeof(int)) { 359794f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 3598f916ec96SNeil Horman "%s (pid %d) " 359994f65193SNeil Horman "Use of int in max_burst socket option deprecated.\n" 3600f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 3601f916ec96SNeil Horman current->comm, task_pid_nr(current)); 3602219b99a9SNeil Horman if (copy_from_user(&val, optval, optlen)) 360370331571SVlad Yasevich return -EFAULT; 3604219b99a9SNeil Horman } else if (optlen == sizeof(struct sctp_assoc_value)) { 3605219b99a9SNeil Horman if (copy_from_user(¶ms, optval, optlen)) 3606219b99a9SNeil Horman return -EFAULT; 3607219b99a9SNeil Horman val = params.assoc_value; 3608219b99a9SNeil Horman assoc_id = params.assoc_id; 3609219b99a9SNeil Horman } else 361070331571SVlad Yasevich return -EINVAL; 361170331571SVlad Yasevich 3612219b99a9SNeil Horman sp = sctp_sk(sk); 3613219b99a9SNeil Horman 3614219b99a9SNeil Horman if (assoc_id != 0) { 3615219b99a9SNeil Horman asoc = sctp_id2assoc(sk, assoc_id); 3616219b99a9SNeil Horman if (!asoc) 3617219b99a9SNeil Horman return -EINVAL; 3618219b99a9SNeil Horman asoc->max_burst = val; 3619219b99a9SNeil Horman } else 3620219b99a9SNeil Horman sp->max_burst = val; 362170331571SVlad Yasevich 362270331571SVlad Yasevich return 0; 362370331571SVlad Yasevich } 362470331571SVlad Yasevich 362565b07e5dSVlad Yasevich /* 362665b07e5dSVlad Yasevich * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) 362765b07e5dSVlad Yasevich * 362865b07e5dSVlad Yasevich * This set option adds a chunk type that the user is requesting to be 362965b07e5dSVlad Yasevich * received only in an authenticated way. Changes to the list of chunks 363065b07e5dSVlad Yasevich * will only effect future associations on the socket. 363165b07e5dSVlad Yasevich */ 363265b07e5dSVlad Yasevich static int sctp_setsockopt_auth_chunk(struct sock *sk, 363365b07e5dSVlad Yasevich char __user *optval, 3634b7058842SDavid S. Miller unsigned int optlen) 363565b07e5dSVlad Yasevich { 3636b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 363765b07e5dSVlad Yasevich struct sctp_authchunk val; 363865b07e5dSVlad Yasevich 3639b14878ccSVlad Yasevich if (!ep->auth_enable) 36405e739d17SVlad Yasevich return -EACCES; 36415e739d17SVlad Yasevich 364265b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authchunk)) 364365b07e5dSVlad Yasevich return -EINVAL; 364465b07e5dSVlad Yasevich if (copy_from_user(&val, optval, optlen)) 364565b07e5dSVlad Yasevich return -EFAULT; 364665b07e5dSVlad Yasevich 364765b07e5dSVlad Yasevich switch (val.sauth_chunk) { 364865b07e5dSVlad Yasevich case SCTP_CID_INIT: 364965b07e5dSVlad Yasevich case SCTP_CID_INIT_ACK: 365065b07e5dSVlad Yasevich case SCTP_CID_SHUTDOWN_COMPLETE: 365165b07e5dSVlad Yasevich case SCTP_CID_AUTH: 365265b07e5dSVlad Yasevich return -EINVAL; 365365b07e5dSVlad Yasevich } 365465b07e5dSVlad Yasevich 365565b07e5dSVlad Yasevich /* add this chunk id to the endpoint */ 3656b14878ccSVlad Yasevich return sctp_auth_ep_add_chunkid(ep, val.sauth_chunk); 365765b07e5dSVlad Yasevich } 365865b07e5dSVlad Yasevich 365965b07e5dSVlad Yasevich /* 366065b07e5dSVlad Yasevich * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) 366165b07e5dSVlad Yasevich * 366265b07e5dSVlad Yasevich * This option gets or sets the list of HMAC algorithms that the local 366365b07e5dSVlad Yasevich * endpoint requires the peer to use. 366465b07e5dSVlad Yasevich */ 366565b07e5dSVlad Yasevich static int sctp_setsockopt_hmac_ident(struct sock *sk, 366665b07e5dSVlad Yasevich char __user *optval, 3667b7058842SDavid S. Miller unsigned int optlen) 366865b07e5dSVlad Yasevich { 3669b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 367065b07e5dSVlad Yasevich struct sctp_hmacalgo *hmacs; 3671d9724055SVlad Yasevich u32 idents; 367265b07e5dSVlad Yasevich int err; 367365b07e5dSVlad Yasevich 3674b14878ccSVlad Yasevich if (!ep->auth_enable) 36755e739d17SVlad Yasevich return -EACCES; 36765e739d17SVlad Yasevich 367765b07e5dSVlad Yasevich if (optlen < sizeof(struct sctp_hmacalgo)) 367865b07e5dSVlad Yasevich return -EINVAL; 36795960cefaSMarcelo Ricardo Leitner optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) + 36805960cefaSMarcelo Ricardo Leitner SCTP_AUTH_NUM_HMACS * sizeof(u16)); 368165b07e5dSVlad Yasevich 3682934253a7SShan Wei hmacs = memdup_user(optval, optlen); 3683934253a7SShan Wei if (IS_ERR(hmacs)) 3684934253a7SShan Wei return PTR_ERR(hmacs); 368565b07e5dSVlad Yasevich 3686d9724055SVlad Yasevich idents = hmacs->shmac_num_idents; 3687d9724055SVlad Yasevich if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || 3688d9724055SVlad Yasevich (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) { 368965b07e5dSVlad Yasevich err = -EINVAL; 369065b07e5dSVlad Yasevich goto out; 369165b07e5dSVlad Yasevich } 369265b07e5dSVlad Yasevich 3693b14878ccSVlad Yasevich err = sctp_auth_ep_set_hmacs(ep, hmacs); 369465b07e5dSVlad Yasevich out: 369565b07e5dSVlad Yasevich kfree(hmacs); 369665b07e5dSVlad Yasevich return err; 369765b07e5dSVlad Yasevich } 369865b07e5dSVlad Yasevich 369965b07e5dSVlad Yasevich /* 370065b07e5dSVlad Yasevich * 7.1.20. Set a shared key (SCTP_AUTH_KEY) 370165b07e5dSVlad Yasevich * 370265b07e5dSVlad Yasevich * This option will set a shared secret key which is used to build an 370365b07e5dSVlad Yasevich * association shared key. 370465b07e5dSVlad Yasevich */ 370565b07e5dSVlad Yasevich static int sctp_setsockopt_auth_key(struct sock *sk, 370665b07e5dSVlad Yasevich char __user *optval, 3707b7058842SDavid S. Miller unsigned int optlen) 370865b07e5dSVlad Yasevich { 3709b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 371065b07e5dSVlad Yasevich struct sctp_authkey *authkey; 371165b07e5dSVlad Yasevich struct sctp_association *asoc; 371265b07e5dSVlad Yasevich int ret; 371365b07e5dSVlad Yasevich 3714b14878ccSVlad Yasevich if (!ep->auth_enable) 37155e739d17SVlad Yasevich return -EACCES; 37165e739d17SVlad Yasevich 371765b07e5dSVlad Yasevich if (optlen <= sizeof(struct sctp_authkey)) 371865b07e5dSVlad Yasevich return -EINVAL; 37195960cefaSMarcelo Ricardo Leitner /* authkey->sca_keylength is u16, so optlen can't be bigger than 37205960cefaSMarcelo Ricardo Leitner * this. 37215960cefaSMarcelo Ricardo Leitner */ 37225960cefaSMarcelo Ricardo Leitner optlen = min_t(unsigned int, optlen, USHRT_MAX + 37235960cefaSMarcelo Ricardo Leitner sizeof(struct sctp_authkey)); 372465b07e5dSVlad Yasevich 3725934253a7SShan Wei authkey = memdup_user(optval, optlen); 3726934253a7SShan Wei if (IS_ERR(authkey)) 3727934253a7SShan Wei return PTR_ERR(authkey); 372865b07e5dSVlad Yasevich 3729328fc47eSVlad Yasevich if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { 373030c2235cSVlad Yasevich ret = -EINVAL; 373130c2235cSVlad Yasevich goto out; 373230c2235cSVlad Yasevich } 373330c2235cSVlad Yasevich 373465b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); 373565b07e5dSVlad Yasevich if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) { 373665b07e5dSVlad Yasevich ret = -EINVAL; 373765b07e5dSVlad Yasevich goto out; 373865b07e5dSVlad Yasevich } 373965b07e5dSVlad Yasevich 3740b14878ccSVlad Yasevich ret = sctp_auth_set_key(ep, asoc, authkey); 374165b07e5dSVlad Yasevich out: 37426ba542a2SDaniel Borkmann kzfree(authkey); 374365b07e5dSVlad Yasevich return ret; 374465b07e5dSVlad Yasevich } 374565b07e5dSVlad Yasevich 374665b07e5dSVlad Yasevich /* 374765b07e5dSVlad Yasevich * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) 374865b07e5dSVlad Yasevich * 374965b07e5dSVlad Yasevich * This option will get or set the active shared key to be used to build 375065b07e5dSVlad Yasevich * the association shared key. 375165b07e5dSVlad Yasevich */ 375265b07e5dSVlad Yasevich static int sctp_setsockopt_active_key(struct sock *sk, 375365b07e5dSVlad Yasevich char __user *optval, 3754b7058842SDavid S. Miller unsigned int optlen) 375565b07e5dSVlad Yasevich { 3756b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 375765b07e5dSVlad Yasevich struct sctp_authkeyid val; 375865b07e5dSVlad Yasevich struct sctp_association *asoc; 375965b07e5dSVlad Yasevich 3760b14878ccSVlad Yasevich if (!ep->auth_enable) 37615e739d17SVlad Yasevich return -EACCES; 37625e739d17SVlad Yasevich 376365b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authkeyid)) 376465b07e5dSVlad Yasevich return -EINVAL; 376565b07e5dSVlad Yasevich if (copy_from_user(&val, optval, optlen)) 376665b07e5dSVlad Yasevich return -EFAULT; 376765b07e5dSVlad Yasevich 376865b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 376965b07e5dSVlad Yasevich if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 377065b07e5dSVlad Yasevich return -EINVAL; 377165b07e5dSVlad Yasevich 3772b14878ccSVlad Yasevich return sctp_auth_set_active_key(ep, asoc, val.scact_keynumber); 377365b07e5dSVlad Yasevich } 377465b07e5dSVlad Yasevich 377565b07e5dSVlad Yasevich /* 377665b07e5dSVlad Yasevich * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY) 377765b07e5dSVlad Yasevich * 377865b07e5dSVlad Yasevich * This set option will delete a shared secret key from use. 377965b07e5dSVlad Yasevich */ 378065b07e5dSVlad Yasevich static int sctp_setsockopt_del_key(struct sock *sk, 378165b07e5dSVlad Yasevich char __user *optval, 3782b7058842SDavid S. Miller unsigned int optlen) 378365b07e5dSVlad Yasevich { 3784b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 378565b07e5dSVlad Yasevich struct sctp_authkeyid val; 378665b07e5dSVlad Yasevich struct sctp_association *asoc; 378765b07e5dSVlad Yasevich 3788b14878ccSVlad Yasevich if (!ep->auth_enable) 37895e739d17SVlad Yasevich return -EACCES; 37905e739d17SVlad Yasevich 379165b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authkeyid)) 379265b07e5dSVlad Yasevich return -EINVAL; 379365b07e5dSVlad Yasevich if (copy_from_user(&val, optval, optlen)) 379465b07e5dSVlad Yasevich return -EFAULT; 379565b07e5dSVlad Yasevich 379665b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 379765b07e5dSVlad Yasevich if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 379865b07e5dSVlad Yasevich return -EINVAL; 379965b07e5dSVlad Yasevich 3800b14878ccSVlad Yasevich return sctp_auth_del_key_id(ep, asoc, val.scact_keynumber); 380165b07e5dSVlad Yasevich 380265b07e5dSVlad Yasevich } 380365b07e5dSVlad Yasevich 38047dc04d71SMichio Honda /* 3805601590ecSXin Long * 8.3.4 Deactivate a Shared Key (SCTP_AUTH_DEACTIVATE_KEY) 3806601590ecSXin Long * 3807601590ecSXin Long * This set option will deactivate a shared secret key. 3808601590ecSXin Long */ 3809601590ecSXin Long static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval, 3810601590ecSXin Long unsigned int optlen) 3811601590ecSXin Long { 3812601590ecSXin Long struct sctp_endpoint *ep = sctp_sk(sk)->ep; 3813601590ecSXin Long struct sctp_authkeyid val; 3814601590ecSXin Long struct sctp_association *asoc; 3815601590ecSXin Long 3816601590ecSXin Long if (!ep->auth_enable) 3817601590ecSXin Long return -EACCES; 3818601590ecSXin Long 3819601590ecSXin Long if (optlen != sizeof(struct sctp_authkeyid)) 3820601590ecSXin Long return -EINVAL; 3821601590ecSXin Long if (copy_from_user(&val, optval, optlen)) 3822601590ecSXin Long return -EFAULT; 3823601590ecSXin Long 3824601590ecSXin Long asoc = sctp_id2assoc(sk, val.scact_assoc_id); 3825601590ecSXin Long if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 3826601590ecSXin Long return -EINVAL; 3827601590ecSXin Long 3828601590ecSXin Long return sctp_auth_deact_key_id(ep, asoc, val.scact_keynumber); 3829601590ecSXin Long } 3830601590ecSXin Long 3831601590ecSXin Long /* 38327dc04d71SMichio Honda * 8.1.23 SCTP_AUTO_ASCONF 38337dc04d71SMichio Honda * 38347dc04d71SMichio Honda * This option will enable or disable the use of the automatic generation of 38357dc04d71SMichio Honda * ASCONF chunks to add and delete addresses to an existing association. Note 38367dc04d71SMichio Honda * that this option has two caveats namely: a) it only affects sockets that 38377dc04d71SMichio Honda * are bound to all addresses available to the SCTP stack, and b) the system 38387dc04d71SMichio Honda * administrator may have an overriding control that turns the ASCONF feature 38397dc04d71SMichio Honda * off no matter what setting the socket option may have. 38407dc04d71SMichio Honda * This option expects an integer boolean flag, where a non-zero value turns on 38417dc04d71SMichio Honda * the option, and a zero value turns off the option. 38427dc04d71SMichio Honda * Note. In this implementation, socket operation overrides default parameter 38437dc04d71SMichio Honda * being set by sysctl as well as FreeBSD implementation 38447dc04d71SMichio Honda */ 38457dc04d71SMichio Honda static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, 38467dc04d71SMichio Honda unsigned int optlen) 38477dc04d71SMichio Honda { 38487dc04d71SMichio Honda int val; 38497dc04d71SMichio Honda struct sctp_sock *sp = sctp_sk(sk); 38507dc04d71SMichio Honda 38517dc04d71SMichio Honda if (optlen < sizeof(int)) 38527dc04d71SMichio Honda return -EINVAL; 38537dc04d71SMichio Honda if (get_user(val, (int __user *)optval)) 38547dc04d71SMichio Honda return -EFAULT; 38557dc04d71SMichio Honda if (!sctp_is_ep_boundall(sk) && val) 38567dc04d71SMichio Honda return -EINVAL; 38577dc04d71SMichio Honda if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf)) 38587dc04d71SMichio Honda return 0; 38597dc04d71SMichio Honda 38602d45a02dSMarcelo Ricardo Leitner spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock); 38617dc04d71SMichio Honda if (val == 0 && sp->do_auto_asconf) { 38627dc04d71SMichio Honda list_del(&sp->auto_asconf_list); 38637dc04d71SMichio Honda sp->do_auto_asconf = 0; 38647dc04d71SMichio Honda } else if (val && !sp->do_auto_asconf) { 38657dc04d71SMichio Honda list_add_tail(&sp->auto_asconf_list, 38664db67e80SEric W. Biederman &sock_net(sk)->sctp.auto_asconf_splist); 38677dc04d71SMichio Honda sp->do_auto_asconf = 1; 38687dc04d71SMichio Honda } 38692d45a02dSMarcelo Ricardo Leitner spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock); 38707dc04d71SMichio Honda return 0; 38717dc04d71SMichio Honda } 38727dc04d71SMichio Honda 38735aa93bcfSNeil Horman /* 38745aa93bcfSNeil Horman * SCTP_PEER_ADDR_THLDS 38755aa93bcfSNeil Horman * 38765aa93bcfSNeil Horman * This option allows us to alter the partially failed threshold for one or all 38775aa93bcfSNeil Horman * transports in an association. See Section 6.1 of: 38785aa93bcfSNeil Horman * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 38795aa93bcfSNeil Horman */ 38805aa93bcfSNeil Horman static int sctp_setsockopt_paddr_thresholds(struct sock *sk, 38815aa93bcfSNeil Horman char __user *optval, 38825aa93bcfSNeil Horman unsigned int optlen) 38835aa93bcfSNeil Horman { 38845aa93bcfSNeil Horman struct sctp_paddrthlds val; 38855aa93bcfSNeil Horman struct sctp_transport *trans; 38865aa93bcfSNeil Horman struct sctp_association *asoc; 38875aa93bcfSNeil Horman 38885aa93bcfSNeil Horman if (optlen < sizeof(struct sctp_paddrthlds)) 38895aa93bcfSNeil Horman return -EINVAL; 38905aa93bcfSNeil Horman if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, 38915aa93bcfSNeil Horman sizeof(struct sctp_paddrthlds))) 38925aa93bcfSNeil Horman return -EFAULT; 38935aa93bcfSNeil Horman 38945aa93bcfSNeil Horman 38955aa93bcfSNeil Horman if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { 38965aa93bcfSNeil Horman asoc = sctp_id2assoc(sk, val.spt_assoc_id); 38975aa93bcfSNeil Horman if (!asoc) 38985aa93bcfSNeil Horman return -ENOENT; 38995aa93bcfSNeil Horman list_for_each_entry(trans, &asoc->peer.transport_addr_list, 39005aa93bcfSNeil Horman transports) { 39015aa93bcfSNeil Horman if (val.spt_pathmaxrxt) 39025aa93bcfSNeil Horman trans->pathmaxrxt = val.spt_pathmaxrxt; 39035aa93bcfSNeil Horman trans->pf_retrans = val.spt_pathpfthld; 39045aa93bcfSNeil Horman } 39055aa93bcfSNeil Horman 39065aa93bcfSNeil Horman if (val.spt_pathmaxrxt) 39075aa93bcfSNeil Horman asoc->pathmaxrxt = val.spt_pathmaxrxt; 39085aa93bcfSNeil Horman asoc->pf_retrans = val.spt_pathpfthld; 39095aa93bcfSNeil Horman } else { 39105aa93bcfSNeil Horman trans = sctp_addr_id2transport(sk, &val.spt_address, 39115aa93bcfSNeil Horman val.spt_assoc_id); 39125aa93bcfSNeil Horman if (!trans) 39135aa93bcfSNeil Horman return -ENOENT; 39145aa93bcfSNeil Horman 39155aa93bcfSNeil Horman if (val.spt_pathmaxrxt) 39165aa93bcfSNeil Horman trans->pathmaxrxt = val.spt_pathmaxrxt; 39175aa93bcfSNeil Horman trans->pf_retrans = val.spt_pathpfthld; 39185aa93bcfSNeil Horman } 39195aa93bcfSNeil Horman 39205aa93bcfSNeil Horman return 0; 39215aa93bcfSNeil Horman } 39225aa93bcfSNeil Horman 39230d3a421dSGeir Ola Vaagland static int sctp_setsockopt_recvrcvinfo(struct sock *sk, 39240d3a421dSGeir Ola Vaagland char __user *optval, 39250d3a421dSGeir Ola Vaagland unsigned int optlen) 39260d3a421dSGeir Ola Vaagland { 39270d3a421dSGeir Ola Vaagland int val; 39280d3a421dSGeir Ola Vaagland 39290d3a421dSGeir Ola Vaagland if (optlen < sizeof(int)) 39300d3a421dSGeir Ola Vaagland return -EINVAL; 39310d3a421dSGeir Ola Vaagland if (get_user(val, (int __user *) optval)) 39320d3a421dSGeir Ola Vaagland return -EFAULT; 39330d3a421dSGeir Ola Vaagland 39340d3a421dSGeir Ola Vaagland sctp_sk(sk)->recvrcvinfo = (val == 0) ? 0 : 1; 39350d3a421dSGeir Ola Vaagland 39360d3a421dSGeir Ola Vaagland return 0; 39370d3a421dSGeir Ola Vaagland } 39380d3a421dSGeir Ola Vaagland 39392347c80fSGeir Ola Vaagland static int sctp_setsockopt_recvnxtinfo(struct sock *sk, 39402347c80fSGeir Ola Vaagland char __user *optval, 39412347c80fSGeir Ola Vaagland unsigned int optlen) 39422347c80fSGeir Ola Vaagland { 39432347c80fSGeir Ola Vaagland int val; 39442347c80fSGeir Ola Vaagland 39452347c80fSGeir Ola Vaagland if (optlen < sizeof(int)) 39462347c80fSGeir Ola Vaagland return -EINVAL; 39472347c80fSGeir Ola Vaagland if (get_user(val, (int __user *) optval)) 39482347c80fSGeir Ola Vaagland return -EFAULT; 39492347c80fSGeir Ola Vaagland 39502347c80fSGeir Ola Vaagland sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1; 39512347c80fSGeir Ola Vaagland 39522347c80fSGeir Ola Vaagland return 0; 39532347c80fSGeir Ola Vaagland } 39542347c80fSGeir Ola Vaagland 395528aa4c26SXin Long static int sctp_setsockopt_pr_supported(struct sock *sk, 395628aa4c26SXin Long char __user *optval, 395728aa4c26SXin Long unsigned int optlen) 395828aa4c26SXin Long { 395928aa4c26SXin Long struct sctp_assoc_value params; 396028aa4c26SXin Long struct sctp_association *asoc; 396128aa4c26SXin Long int retval = -EINVAL; 396228aa4c26SXin Long 396328aa4c26SXin Long if (optlen != sizeof(params)) 396428aa4c26SXin Long goto out; 396528aa4c26SXin Long 396628aa4c26SXin Long if (copy_from_user(¶ms, optval, optlen)) { 396728aa4c26SXin Long retval = -EFAULT; 396828aa4c26SXin Long goto out; 396928aa4c26SXin Long } 397028aa4c26SXin Long 397128aa4c26SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 397228aa4c26SXin Long if (asoc) { 397328aa4c26SXin Long asoc->prsctp_enable = !!params.assoc_value; 397428aa4c26SXin Long } else if (!params.assoc_id) { 397528aa4c26SXin Long struct sctp_sock *sp = sctp_sk(sk); 397628aa4c26SXin Long 397728aa4c26SXin Long sp->ep->prsctp_enable = !!params.assoc_value; 397828aa4c26SXin Long } else { 397928aa4c26SXin Long goto out; 398028aa4c26SXin Long } 398128aa4c26SXin Long 398228aa4c26SXin Long retval = 0; 398328aa4c26SXin Long 398428aa4c26SXin Long out: 398528aa4c26SXin Long return retval; 398628aa4c26SXin Long } 398728aa4c26SXin Long 3988f959fb44SXin Long static int sctp_setsockopt_default_prinfo(struct sock *sk, 3989f959fb44SXin Long char __user *optval, 3990f959fb44SXin Long unsigned int optlen) 3991f959fb44SXin Long { 3992f959fb44SXin Long struct sctp_default_prinfo info; 3993f959fb44SXin Long struct sctp_association *asoc; 3994f959fb44SXin Long int retval = -EINVAL; 3995f959fb44SXin Long 3996f959fb44SXin Long if (optlen != sizeof(info)) 3997f959fb44SXin Long goto out; 3998f959fb44SXin Long 3999f959fb44SXin Long if (copy_from_user(&info, optval, sizeof(info))) { 4000f959fb44SXin Long retval = -EFAULT; 4001f959fb44SXin Long goto out; 4002f959fb44SXin Long } 4003f959fb44SXin Long 4004f959fb44SXin Long if (info.pr_policy & ~SCTP_PR_SCTP_MASK) 4005f959fb44SXin Long goto out; 4006f959fb44SXin Long 4007f959fb44SXin Long if (info.pr_policy == SCTP_PR_SCTP_NONE) 4008f959fb44SXin Long info.pr_value = 0; 4009f959fb44SXin Long 4010f959fb44SXin Long asoc = sctp_id2assoc(sk, info.pr_assoc_id); 4011f959fb44SXin Long if (asoc) { 4012f959fb44SXin Long SCTP_PR_SET_POLICY(asoc->default_flags, info.pr_policy); 4013f959fb44SXin Long asoc->default_timetolive = info.pr_value; 4014f959fb44SXin Long } else if (!info.pr_assoc_id) { 4015f959fb44SXin Long struct sctp_sock *sp = sctp_sk(sk); 4016f959fb44SXin Long 4017f959fb44SXin Long SCTP_PR_SET_POLICY(sp->default_flags, info.pr_policy); 4018f959fb44SXin Long sp->default_timetolive = info.pr_value; 4019f959fb44SXin Long } else { 4020f959fb44SXin Long goto out; 4021f959fb44SXin Long } 4022f959fb44SXin Long 4023f959fb44SXin Long retval = 0; 4024f959fb44SXin Long 4025f959fb44SXin Long out: 4026f959fb44SXin Long return retval; 4027f959fb44SXin Long } 4028f959fb44SXin Long 4029c0d8bab6SXin Long static int sctp_setsockopt_reconfig_supported(struct sock *sk, 4030c0d8bab6SXin Long char __user *optval, 4031c0d8bab6SXin Long unsigned int optlen) 4032c0d8bab6SXin Long { 4033c0d8bab6SXin Long struct sctp_assoc_value params; 4034c0d8bab6SXin Long struct sctp_association *asoc; 4035c0d8bab6SXin Long int retval = -EINVAL; 4036c0d8bab6SXin Long 4037c0d8bab6SXin Long if (optlen != sizeof(params)) 4038c0d8bab6SXin Long goto out; 4039c0d8bab6SXin Long 4040c0d8bab6SXin Long if (copy_from_user(¶ms, optval, optlen)) { 4041c0d8bab6SXin Long retval = -EFAULT; 4042c0d8bab6SXin Long goto out; 4043c0d8bab6SXin Long } 4044c0d8bab6SXin Long 4045c0d8bab6SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 4046c0d8bab6SXin Long if (asoc) { 4047c0d8bab6SXin Long asoc->reconf_enable = !!params.assoc_value; 4048c0d8bab6SXin Long } else if (!params.assoc_id) { 4049c0d8bab6SXin Long struct sctp_sock *sp = sctp_sk(sk); 4050c0d8bab6SXin Long 4051c0d8bab6SXin Long sp->ep->reconf_enable = !!params.assoc_value; 4052c0d8bab6SXin Long } else { 4053c0d8bab6SXin Long goto out; 4054c0d8bab6SXin Long } 4055c0d8bab6SXin Long 4056c0d8bab6SXin Long retval = 0; 4057c0d8bab6SXin Long 4058c0d8bab6SXin Long out: 4059c0d8bab6SXin Long return retval; 4060c0d8bab6SXin Long } 4061c0d8bab6SXin Long 40629fb657aeSXin Long static int sctp_setsockopt_enable_strreset(struct sock *sk, 40639fb657aeSXin Long char __user *optval, 40649fb657aeSXin Long unsigned int optlen) 40659fb657aeSXin Long { 40669fb657aeSXin Long struct sctp_assoc_value params; 40679fb657aeSXin Long struct sctp_association *asoc; 40689fb657aeSXin Long int retval = -EINVAL; 40699fb657aeSXin Long 40709fb657aeSXin Long if (optlen != sizeof(params)) 40719fb657aeSXin Long goto out; 40729fb657aeSXin Long 40739fb657aeSXin Long if (copy_from_user(¶ms, optval, optlen)) { 40749fb657aeSXin Long retval = -EFAULT; 40759fb657aeSXin Long goto out; 40769fb657aeSXin Long } 40779fb657aeSXin Long 40789fb657aeSXin Long if (params.assoc_value & (~SCTP_ENABLE_STRRESET_MASK)) 40799fb657aeSXin Long goto out; 40809fb657aeSXin Long 40819fb657aeSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 40829fb657aeSXin Long if (asoc) { 40839fb657aeSXin Long asoc->strreset_enable = params.assoc_value; 40849fb657aeSXin Long } else if (!params.assoc_id) { 40859fb657aeSXin Long struct sctp_sock *sp = sctp_sk(sk); 40869fb657aeSXin Long 40879fb657aeSXin Long sp->ep->strreset_enable = params.assoc_value; 40889fb657aeSXin Long } else { 40899fb657aeSXin Long goto out; 40909fb657aeSXin Long } 40919fb657aeSXin Long 40929fb657aeSXin Long retval = 0; 40939fb657aeSXin Long 40949fb657aeSXin Long out: 40959fb657aeSXin Long return retval; 40969fb657aeSXin Long } 40979fb657aeSXin Long 40987f9d68acSXin Long static int sctp_setsockopt_reset_streams(struct sock *sk, 40997f9d68acSXin Long char __user *optval, 41007f9d68acSXin Long unsigned int optlen) 41017f9d68acSXin Long { 41027f9d68acSXin Long struct sctp_reset_streams *params; 41037f9d68acSXin Long struct sctp_association *asoc; 41047f9d68acSXin Long int retval = -EINVAL; 41057f9d68acSXin Long 41062342b8d9SXin Long if (optlen < sizeof(*params)) 41077f9d68acSXin Long return -EINVAL; 41085960cefaSMarcelo Ricardo Leitner /* srs_number_streams is u16, so optlen can't be bigger than this. */ 41095960cefaSMarcelo Ricardo Leitner optlen = min_t(unsigned int, optlen, USHRT_MAX + 41105960cefaSMarcelo Ricardo Leitner sizeof(__u16) * sizeof(*params)); 41117f9d68acSXin Long 41127f9d68acSXin Long params = memdup_user(optval, optlen); 41137f9d68acSXin Long if (IS_ERR(params)) 41147f9d68acSXin Long return PTR_ERR(params); 41157f9d68acSXin Long 41162342b8d9SXin Long if (params->srs_number_streams * sizeof(__u16) > 41172342b8d9SXin Long optlen - sizeof(*params)) 41182342b8d9SXin Long goto out; 41192342b8d9SXin Long 41207f9d68acSXin Long asoc = sctp_id2assoc(sk, params->srs_assoc_id); 41217f9d68acSXin Long if (!asoc) 41227f9d68acSXin Long goto out; 41237f9d68acSXin Long 41247f9d68acSXin Long retval = sctp_send_reset_streams(asoc, params); 41257f9d68acSXin Long 41267f9d68acSXin Long out: 41277f9d68acSXin Long kfree(params); 41287f9d68acSXin Long return retval; 41297f9d68acSXin Long } 41307f9d68acSXin Long 4131a92ce1a4SXin Long static int sctp_setsockopt_reset_assoc(struct sock *sk, 4132a92ce1a4SXin Long char __user *optval, 4133a92ce1a4SXin Long unsigned int optlen) 4134a92ce1a4SXin Long { 4135a92ce1a4SXin Long struct sctp_association *asoc; 4136a92ce1a4SXin Long sctp_assoc_t associd; 4137a92ce1a4SXin Long int retval = -EINVAL; 4138a92ce1a4SXin Long 4139a92ce1a4SXin Long if (optlen != sizeof(associd)) 4140a92ce1a4SXin Long goto out; 4141a92ce1a4SXin Long 4142a92ce1a4SXin Long if (copy_from_user(&associd, optval, optlen)) { 4143a92ce1a4SXin Long retval = -EFAULT; 4144a92ce1a4SXin Long goto out; 4145a92ce1a4SXin Long } 4146a92ce1a4SXin Long 4147a92ce1a4SXin Long asoc = sctp_id2assoc(sk, associd); 4148a92ce1a4SXin Long if (!asoc) 4149a92ce1a4SXin Long goto out; 4150a92ce1a4SXin Long 4151a92ce1a4SXin Long retval = sctp_send_reset_assoc(asoc); 4152a92ce1a4SXin Long 4153a92ce1a4SXin Long out: 4154a92ce1a4SXin Long return retval; 4155a92ce1a4SXin Long } 4156a92ce1a4SXin Long 4157242bd2d5SXin Long static int sctp_setsockopt_add_streams(struct sock *sk, 4158242bd2d5SXin Long char __user *optval, 4159242bd2d5SXin Long unsigned int optlen) 4160242bd2d5SXin Long { 4161242bd2d5SXin Long struct sctp_association *asoc; 4162242bd2d5SXin Long struct sctp_add_streams params; 4163242bd2d5SXin Long int retval = -EINVAL; 4164242bd2d5SXin Long 4165242bd2d5SXin Long if (optlen != sizeof(params)) 4166242bd2d5SXin Long goto out; 4167242bd2d5SXin Long 4168242bd2d5SXin Long if (copy_from_user(¶ms, optval, optlen)) { 4169242bd2d5SXin Long retval = -EFAULT; 4170242bd2d5SXin Long goto out; 4171242bd2d5SXin Long } 4172242bd2d5SXin Long 4173242bd2d5SXin Long asoc = sctp_id2assoc(sk, params.sas_assoc_id); 4174242bd2d5SXin Long if (!asoc) 4175242bd2d5SXin Long goto out; 4176242bd2d5SXin Long 4177242bd2d5SXin Long retval = sctp_send_add_streams(asoc, ¶ms); 4178242bd2d5SXin Long 4179242bd2d5SXin Long out: 4180242bd2d5SXin Long return retval; 4181242bd2d5SXin Long } 4182242bd2d5SXin Long 418313aa8770SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler(struct sock *sk, 418413aa8770SMarcelo Ricardo Leitner char __user *optval, 418513aa8770SMarcelo Ricardo Leitner unsigned int optlen) 418613aa8770SMarcelo Ricardo Leitner { 418713aa8770SMarcelo Ricardo Leitner struct sctp_association *asoc; 418813aa8770SMarcelo Ricardo Leitner struct sctp_assoc_value params; 418913aa8770SMarcelo Ricardo Leitner int retval = -EINVAL; 419013aa8770SMarcelo Ricardo Leitner 419113aa8770SMarcelo Ricardo Leitner if (optlen < sizeof(params)) 419213aa8770SMarcelo Ricardo Leitner goto out; 419313aa8770SMarcelo Ricardo Leitner 419413aa8770SMarcelo Ricardo Leitner optlen = sizeof(params); 419513aa8770SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, optlen)) { 419613aa8770SMarcelo Ricardo Leitner retval = -EFAULT; 419713aa8770SMarcelo Ricardo Leitner goto out; 419813aa8770SMarcelo Ricardo Leitner } 419913aa8770SMarcelo Ricardo Leitner 420013aa8770SMarcelo Ricardo Leitner if (params.assoc_value > SCTP_SS_MAX) 420113aa8770SMarcelo Ricardo Leitner goto out; 420213aa8770SMarcelo Ricardo Leitner 420313aa8770SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 420413aa8770SMarcelo Ricardo Leitner if (!asoc) 420513aa8770SMarcelo Ricardo Leitner goto out; 420613aa8770SMarcelo Ricardo Leitner 420713aa8770SMarcelo Ricardo Leitner retval = sctp_sched_set_sched(asoc, params.assoc_value); 420813aa8770SMarcelo Ricardo Leitner 420913aa8770SMarcelo Ricardo Leitner out: 421013aa8770SMarcelo Ricardo Leitner return retval; 421113aa8770SMarcelo Ricardo Leitner } 421213aa8770SMarcelo Ricardo Leitner 42130ccdf3c7SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler_value(struct sock *sk, 42140ccdf3c7SMarcelo Ricardo Leitner char __user *optval, 42150ccdf3c7SMarcelo Ricardo Leitner unsigned int optlen) 42160ccdf3c7SMarcelo Ricardo Leitner { 42170ccdf3c7SMarcelo Ricardo Leitner struct sctp_association *asoc; 42180ccdf3c7SMarcelo Ricardo Leitner struct sctp_stream_value params; 42190ccdf3c7SMarcelo Ricardo Leitner int retval = -EINVAL; 42200ccdf3c7SMarcelo Ricardo Leitner 42210ccdf3c7SMarcelo Ricardo Leitner if (optlen < sizeof(params)) 42220ccdf3c7SMarcelo Ricardo Leitner goto out; 42230ccdf3c7SMarcelo Ricardo Leitner 42240ccdf3c7SMarcelo Ricardo Leitner optlen = sizeof(params); 42250ccdf3c7SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, optlen)) { 42260ccdf3c7SMarcelo Ricardo Leitner retval = -EFAULT; 42270ccdf3c7SMarcelo Ricardo Leitner goto out; 42280ccdf3c7SMarcelo Ricardo Leitner } 42290ccdf3c7SMarcelo Ricardo Leitner 42300ccdf3c7SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 42310ccdf3c7SMarcelo Ricardo Leitner if (!asoc) 42320ccdf3c7SMarcelo Ricardo Leitner goto out; 42330ccdf3c7SMarcelo Ricardo Leitner 42340ccdf3c7SMarcelo Ricardo Leitner retval = sctp_sched_set_value(asoc, params.stream_id, 42350ccdf3c7SMarcelo Ricardo Leitner params.stream_value, GFP_KERNEL); 42360ccdf3c7SMarcelo Ricardo Leitner 42370ccdf3c7SMarcelo Ricardo Leitner out: 42380ccdf3c7SMarcelo Ricardo Leitner return retval; 42390ccdf3c7SMarcelo Ricardo Leitner } 42400ccdf3c7SMarcelo Ricardo Leitner 4241772a5869SXin Long static int sctp_setsockopt_interleaving_supported(struct sock *sk, 4242772a5869SXin Long char __user *optval, 4243772a5869SXin Long unsigned int optlen) 4244772a5869SXin Long { 4245772a5869SXin Long struct sctp_sock *sp = sctp_sk(sk); 4246772a5869SXin Long struct net *net = sock_net(sk); 4247772a5869SXin Long struct sctp_assoc_value params; 4248772a5869SXin Long int retval = -EINVAL; 4249772a5869SXin Long 4250772a5869SXin Long if (optlen < sizeof(params)) 4251772a5869SXin Long goto out; 4252772a5869SXin Long 4253772a5869SXin Long optlen = sizeof(params); 4254772a5869SXin Long if (copy_from_user(¶ms, optval, optlen)) { 4255772a5869SXin Long retval = -EFAULT; 4256772a5869SXin Long goto out; 4257772a5869SXin Long } 4258772a5869SXin Long 4259772a5869SXin Long if (params.assoc_id) 4260772a5869SXin Long goto out; 4261772a5869SXin Long 4262772a5869SXin Long if (!net->sctp.intl_enable || !sp->frag_interleave) { 4263772a5869SXin Long retval = -EPERM; 4264772a5869SXin Long goto out; 4265772a5869SXin Long } 4266772a5869SXin Long 4267772a5869SXin Long sp->strm_interleave = !!params.assoc_value; 4268772a5869SXin Long 4269772a5869SXin Long retval = 0; 4270772a5869SXin Long 4271772a5869SXin Long out: 4272772a5869SXin Long return retval; 4273772a5869SXin Long } 4274772a5869SXin Long 4275b0e9a2feSXin Long static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval, 4276b0e9a2feSXin Long unsigned int optlen) 4277b0e9a2feSXin Long { 4278b0e9a2feSXin Long int val; 4279b0e9a2feSXin Long 4280b0e9a2feSXin Long if (!sctp_style(sk, TCP)) 4281b0e9a2feSXin Long return -EOPNOTSUPP; 4282b0e9a2feSXin Long 4283b0e9a2feSXin Long if (sctp_sk(sk)->ep->base.bind_addr.port) 4284b0e9a2feSXin Long return -EFAULT; 4285b0e9a2feSXin Long 4286b0e9a2feSXin Long if (optlen < sizeof(int)) 4287b0e9a2feSXin Long return -EINVAL; 4288b0e9a2feSXin Long 4289b0e9a2feSXin Long if (get_user(val, (int __user *)optval)) 4290b0e9a2feSXin Long return -EFAULT; 4291b0e9a2feSXin Long 4292b0e9a2feSXin Long sctp_sk(sk)->reuse = !!val; 4293b0e9a2feSXin Long 4294b0e9a2feSXin Long return 0; 4295b0e9a2feSXin Long } 4296b0e9a2feSXin Long 42971da177e4SLinus Torvalds /* API 6.2 setsockopt(), getsockopt() 42981da177e4SLinus Torvalds * 42991da177e4SLinus Torvalds * Applications use setsockopt() and getsockopt() to set or retrieve 43001da177e4SLinus Torvalds * socket options. Socket options are used to change the default 43011da177e4SLinus Torvalds * behavior of sockets calls. They are described in Section 7. 43021da177e4SLinus Torvalds * 43031da177e4SLinus Torvalds * The syntax is: 43041da177e4SLinus Torvalds * 43051da177e4SLinus Torvalds * ret = getsockopt(int sd, int level, int optname, void __user *optval, 43061da177e4SLinus Torvalds * int __user *optlen); 43071da177e4SLinus Torvalds * ret = setsockopt(int sd, int level, int optname, const void __user *optval, 43081da177e4SLinus Torvalds * int optlen); 43091da177e4SLinus Torvalds * 43101da177e4SLinus Torvalds * sd - the socket descript. 43111da177e4SLinus Torvalds * level - set to IPPROTO_SCTP for all SCTP options. 43121da177e4SLinus Torvalds * optname - the option name. 43131da177e4SLinus Torvalds * optval - the buffer to store the value of the option. 43141da177e4SLinus Torvalds * optlen - the size of the buffer. 43151da177e4SLinus Torvalds */ 4316dda91928SDaniel Borkmann static int sctp_setsockopt(struct sock *sk, int level, int optname, 4317b7058842SDavid S. Miller char __user *optval, unsigned int optlen) 43181da177e4SLinus Torvalds { 43191da177e4SLinus Torvalds int retval = 0; 43201da177e4SLinus Torvalds 4321bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 43221da177e4SLinus Torvalds 43231da177e4SLinus Torvalds /* I can hardly begin to describe how wrong this is. This is 43241da177e4SLinus Torvalds * so broken as to be worse than useless. The API draft 43251da177e4SLinus Torvalds * REALLY is NOT helpful here... I am not convinced that the 43261da177e4SLinus Torvalds * semantics of setsockopt() with a level OTHER THAN SOL_SCTP 43271da177e4SLinus Torvalds * are at all well-founded. 43281da177e4SLinus Torvalds */ 43291da177e4SLinus Torvalds if (level != SOL_SCTP) { 43301da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 43311da177e4SLinus Torvalds retval = af->setsockopt(sk, level, optname, optval, optlen); 43321da177e4SLinus Torvalds goto out_nounlock; 43331da177e4SLinus Torvalds } 43341da177e4SLinus Torvalds 4335048ed4b6Swangweidong lock_sock(sk); 43361da177e4SLinus Torvalds 43371da177e4SLinus Torvalds switch (optname) { 43381da177e4SLinus Torvalds case SCTP_SOCKOPT_BINDX_ADD: 43391da177e4SLinus Torvalds /* 'optlen' is the size of the addresses buffer. */ 43401da177e4SLinus Torvalds retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval, 43411da177e4SLinus Torvalds optlen, SCTP_BINDX_ADD_ADDR); 43421da177e4SLinus Torvalds break; 43431da177e4SLinus Torvalds 43441da177e4SLinus Torvalds case SCTP_SOCKOPT_BINDX_REM: 43451da177e4SLinus Torvalds /* 'optlen' is the size of the addresses buffer. */ 43461da177e4SLinus Torvalds retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval, 43471da177e4SLinus Torvalds optlen, SCTP_BINDX_REM_ADDR); 43481da177e4SLinus Torvalds break; 43491da177e4SLinus Torvalds 435088a0a948SVlad Yasevich case SCTP_SOCKOPT_CONNECTX_OLD: 435188a0a948SVlad Yasevich /* 'optlen' is the size of the addresses buffer. */ 435288a0a948SVlad Yasevich retval = sctp_setsockopt_connectx_old(sk, 435388a0a948SVlad Yasevich (struct sockaddr __user *)optval, 435488a0a948SVlad Yasevich optlen); 435588a0a948SVlad Yasevich break; 435688a0a948SVlad Yasevich 43573f7a87d2SFrank Filz case SCTP_SOCKOPT_CONNECTX: 43583f7a87d2SFrank Filz /* 'optlen' is the size of the addresses buffer. */ 435988a0a948SVlad Yasevich retval = sctp_setsockopt_connectx(sk, 436088a0a948SVlad Yasevich (struct sockaddr __user *)optval, 43613f7a87d2SFrank Filz optlen); 43623f7a87d2SFrank Filz break; 43633f7a87d2SFrank Filz 43641da177e4SLinus Torvalds case SCTP_DISABLE_FRAGMENTS: 43651da177e4SLinus Torvalds retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); 43661da177e4SLinus Torvalds break; 43671da177e4SLinus Torvalds 43681da177e4SLinus Torvalds case SCTP_EVENTS: 43691da177e4SLinus Torvalds retval = sctp_setsockopt_events(sk, optval, optlen); 43701da177e4SLinus Torvalds break; 43711da177e4SLinus Torvalds 43721da177e4SLinus Torvalds case SCTP_AUTOCLOSE: 43731da177e4SLinus Torvalds retval = sctp_setsockopt_autoclose(sk, optval, optlen); 43741da177e4SLinus Torvalds break; 43751da177e4SLinus Torvalds 43761da177e4SLinus Torvalds case SCTP_PEER_ADDR_PARAMS: 43771da177e4SLinus Torvalds retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen); 43781da177e4SLinus Torvalds break; 43791da177e4SLinus Torvalds 43804580ccc0SShan Wei case SCTP_DELAYED_SACK: 4381d364d927SWei Yongjun retval = sctp_setsockopt_delayed_ack(sk, optval, optlen); 43827708610bSFrank Filz break; 4383d49d91d7SVlad Yasevich case SCTP_PARTIAL_DELIVERY_POINT: 4384d49d91d7SVlad Yasevich retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen); 4385d49d91d7SVlad Yasevich break; 43867708610bSFrank Filz 43871da177e4SLinus Torvalds case SCTP_INITMSG: 43881da177e4SLinus Torvalds retval = sctp_setsockopt_initmsg(sk, optval, optlen); 43891da177e4SLinus Torvalds break; 43901da177e4SLinus Torvalds case SCTP_DEFAULT_SEND_PARAM: 43911da177e4SLinus Torvalds retval = sctp_setsockopt_default_send_param(sk, optval, 43921da177e4SLinus Torvalds optlen); 43931da177e4SLinus Torvalds break; 43946b3fd5f3SGeir Ola Vaagland case SCTP_DEFAULT_SNDINFO: 43956b3fd5f3SGeir Ola Vaagland retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen); 43966b3fd5f3SGeir Ola Vaagland break; 43971da177e4SLinus Torvalds case SCTP_PRIMARY_ADDR: 43981da177e4SLinus Torvalds retval = sctp_setsockopt_primary_addr(sk, optval, optlen); 43991da177e4SLinus Torvalds break; 44001da177e4SLinus Torvalds case SCTP_SET_PEER_PRIMARY_ADDR: 44011da177e4SLinus Torvalds retval = sctp_setsockopt_peer_primary_addr(sk, optval, optlen); 44021da177e4SLinus Torvalds break; 44031da177e4SLinus Torvalds case SCTP_NODELAY: 44041da177e4SLinus Torvalds retval = sctp_setsockopt_nodelay(sk, optval, optlen); 44051da177e4SLinus Torvalds break; 44061da177e4SLinus Torvalds case SCTP_RTOINFO: 44071da177e4SLinus Torvalds retval = sctp_setsockopt_rtoinfo(sk, optval, optlen); 44081da177e4SLinus Torvalds break; 44091da177e4SLinus Torvalds case SCTP_ASSOCINFO: 44101da177e4SLinus Torvalds retval = sctp_setsockopt_associnfo(sk, optval, optlen); 44111da177e4SLinus Torvalds break; 44121da177e4SLinus Torvalds case SCTP_I_WANT_MAPPED_V4_ADDR: 44131da177e4SLinus Torvalds retval = sctp_setsockopt_mappedv4(sk, optval, optlen); 44141da177e4SLinus Torvalds break; 44151da177e4SLinus Torvalds case SCTP_MAXSEG: 44161da177e4SLinus Torvalds retval = sctp_setsockopt_maxseg(sk, optval, optlen); 44171da177e4SLinus Torvalds break; 44180f3fffd8SIvan Skytte Jorgensen case SCTP_ADAPTATION_LAYER: 44190f3fffd8SIvan Skytte Jorgensen retval = sctp_setsockopt_adaptation_layer(sk, optval, optlen); 44201da177e4SLinus Torvalds break; 44216ab792f5SIvan Skytte Jorgensen case SCTP_CONTEXT: 44226ab792f5SIvan Skytte Jorgensen retval = sctp_setsockopt_context(sk, optval, optlen); 44236ab792f5SIvan Skytte Jorgensen break; 4424b6e1331fSVlad Yasevich case SCTP_FRAGMENT_INTERLEAVE: 4425b6e1331fSVlad Yasevich retval = sctp_setsockopt_fragment_interleave(sk, optval, optlen); 4426b6e1331fSVlad Yasevich break; 442770331571SVlad Yasevich case SCTP_MAX_BURST: 442870331571SVlad Yasevich retval = sctp_setsockopt_maxburst(sk, optval, optlen); 442970331571SVlad Yasevich break; 443065b07e5dSVlad Yasevich case SCTP_AUTH_CHUNK: 443165b07e5dSVlad Yasevich retval = sctp_setsockopt_auth_chunk(sk, optval, optlen); 443265b07e5dSVlad Yasevich break; 443365b07e5dSVlad Yasevich case SCTP_HMAC_IDENT: 443465b07e5dSVlad Yasevich retval = sctp_setsockopt_hmac_ident(sk, optval, optlen); 443565b07e5dSVlad Yasevich break; 443665b07e5dSVlad Yasevich case SCTP_AUTH_KEY: 443765b07e5dSVlad Yasevich retval = sctp_setsockopt_auth_key(sk, optval, optlen); 443865b07e5dSVlad Yasevich break; 443965b07e5dSVlad Yasevich case SCTP_AUTH_ACTIVE_KEY: 444065b07e5dSVlad Yasevich retval = sctp_setsockopt_active_key(sk, optval, optlen); 444165b07e5dSVlad Yasevich break; 444265b07e5dSVlad Yasevich case SCTP_AUTH_DELETE_KEY: 444365b07e5dSVlad Yasevich retval = sctp_setsockopt_del_key(sk, optval, optlen); 444465b07e5dSVlad Yasevich break; 4445601590ecSXin Long case SCTP_AUTH_DEACTIVATE_KEY: 4446601590ecSXin Long retval = sctp_setsockopt_deactivate_key(sk, optval, optlen); 4447601590ecSXin Long break; 44487dc04d71SMichio Honda case SCTP_AUTO_ASCONF: 44497dc04d71SMichio Honda retval = sctp_setsockopt_auto_asconf(sk, optval, optlen); 44507dc04d71SMichio Honda break; 44515aa93bcfSNeil Horman case SCTP_PEER_ADDR_THLDS: 44525aa93bcfSNeil Horman retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); 44535aa93bcfSNeil Horman break; 44540d3a421dSGeir Ola Vaagland case SCTP_RECVRCVINFO: 44550d3a421dSGeir Ola Vaagland retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); 44560d3a421dSGeir Ola Vaagland break; 44572347c80fSGeir Ola Vaagland case SCTP_RECVNXTINFO: 44582347c80fSGeir Ola Vaagland retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen); 44592347c80fSGeir Ola Vaagland break; 446028aa4c26SXin Long case SCTP_PR_SUPPORTED: 446128aa4c26SXin Long retval = sctp_setsockopt_pr_supported(sk, optval, optlen); 446228aa4c26SXin Long break; 4463f959fb44SXin Long case SCTP_DEFAULT_PRINFO: 4464f959fb44SXin Long retval = sctp_setsockopt_default_prinfo(sk, optval, optlen); 4465f959fb44SXin Long break; 4466c0d8bab6SXin Long case SCTP_RECONFIG_SUPPORTED: 4467c0d8bab6SXin Long retval = sctp_setsockopt_reconfig_supported(sk, optval, optlen); 4468c0d8bab6SXin Long break; 44699fb657aeSXin Long case SCTP_ENABLE_STREAM_RESET: 44709fb657aeSXin Long retval = sctp_setsockopt_enable_strreset(sk, optval, optlen); 44719fb657aeSXin Long break; 44727f9d68acSXin Long case SCTP_RESET_STREAMS: 44737f9d68acSXin Long retval = sctp_setsockopt_reset_streams(sk, optval, optlen); 44747f9d68acSXin Long break; 4475a92ce1a4SXin Long case SCTP_RESET_ASSOC: 4476a92ce1a4SXin Long retval = sctp_setsockopt_reset_assoc(sk, optval, optlen); 4477a92ce1a4SXin Long break; 4478242bd2d5SXin Long case SCTP_ADD_STREAMS: 4479242bd2d5SXin Long retval = sctp_setsockopt_add_streams(sk, optval, optlen); 4480242bd2d5SXin Long break; 448113aa8770SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER: 448213aa8770SMarcelo Ricardo Leitner retval = sctp_setsockopt_scheduler(sk, optval, optlen); 448313aa8770SMarcelo Ricardo Leitner break; 44840ccdf3c7SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER_VALUE: 44850ccdf3c7SMarcelo Ricardo Leitner retval = sctp_setsockopt_scheduler_value(sk, optval, optlen); 44860ccdf3c7SMarcelo Ricardo Leitner break; 4487772a5869SXin Long case SCTP_INTERLEAVING_SUPPORTED: 4488772a5869SXin Long retval = sctp_setsockopt_interleaving_supported(sk, optval, 4489772a5869SXin Long optlen); 4490772a5869SXin Long break; 4491b0e9a2feSXin Long case SCTP_REUSE_PORT: 4492b0e9a2feSXin Long retval = sctp_setsockopt_reuse_port(sk, optval, optlen); 4493b0e9a2feSXin Long break; 44941da177e4SLinus Torvalds default: 44951da177e4SLinus Torvalds retval = -ENOPROTOOPT; 44961da177e4SLinus Torvalds break; 44973ff50b79SStephen Hemminger } 44981da177e4SLinus Torvalds 4499048ed4b6Swangweidong release_sock(sk); 45001da177e4SLinus Torvalds 45011da177e4SLinus Torvalds out_nounlock: 45021da177e4SLinus Torvalds return retval; 45031da177e4SLinus Torvalds } 45041da177e4SLinus Torvalds 45051da177e4SLinus Torvalds /* API 3.1.6 connect() - UDP Style Syntax 45061da177e4SLinus Torvalds * 45071da177e4SLinus Torvalds * An application may use the connect() call in the UDP model to initiate an 45081da177e4SLinus Torvalds * association without sending data. 45091da177e4SLinus Torvalds * 45101da177e4SLinus Torvalds * The syntax is: 45111da177e4SLinus Torvalds * 45121da177e4SLinus Torvalds * ret = connect(int sd, const struct sockaddr *nam, socklen_t len); 45131da177e4SLinus Torvalds * 45141da177e4SLinus Torvalds * sd: the socket descriptor to have a new association added to. 45151da177e4SLinus Torvalds * 45161da177e4SLinus Torvalds * nam: the address structure (either struct sockaddr_in or struct 45171da177e4SLinus Torvalds * sockaddr_in6 defined in RFC2553 [7]). 45181da177e4SLinus Torvalds * 45191da177e4SLinus Torvalds * len: the size of the address. 45201da177e4SLinus Torvalds */ 4521dda91928SDaniel Borkmann static int sctp_connect(struct sock *sk, struct sockaddr *addr, 4522644fbdeaSXin Long int addr_len, int flags) 45231da177e4SLinus Torvalds { 4524644fbdeaSXin Long struct inet_sock *inet = inet_sk(sk); 45253f7a87d2SFrank Filz struct sctp_af *af; 4526644fbdeaSXin Long int err = 0; 45271da177e4SLinus Torvalds 4528048ed4b6Swangweidong lock_sock(sk); 45291da177e4SLinus Torvalds 4530bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk, 4531bb33381dSDaniel Borkmann addr, addr_len); 45321da177e4SLinus Torvalds 4533644fbdeaSXin Long /* We may need to bind the socket. */ 4534644fbdeaSXin Long if (!inet->inet_num) { 4535644fbdeaSXin Long if (sk->sk_prot->get_port(sk, 0)) { 4536644fbdeaSXin Long release_sock(sk); 4537644fbdeaSXin Long return -EAGAIN; 4538644fbdeaSXin Long } 4539644fbdeaSXin Long inet->inet_sport = htons(inet->inet_num); 4540644fbdeaSXin Long } 4541644fbdeaSXin Long 45423f7a87d2SFrank Filz /* Validate addr_len before calling common connect/connectx routine. */ 45433f7a87d2SFrank Filz af = sctp_get_af_specific(addr->sa_family); 45443f7a87d2SFrank Filz if (!af || addr_len < af->sockaddr_len) { 45453f7a87d2SFrank Filz err = -EINVAL; 45463f7a87d2SFrank Filz } else { 45473f7a87d2SFrank Filz /* Pass correct addr len to common routine (so it knows there 45483f7a87d2SFrank Filz * is only one address being passed. 45491da177e4SLinus Torvalds */ 4550644fbdeaSXin Long err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL); 45511da177e4SLinus Torvalds } 45521da177e4SLinus Torvalds 4553048ed4b6Swangweidong release_sock(sk); 45541da177e4SLinus Torvalds return err; 45551da177e4SLinus Torvalds } 45561da177e4SLinus Torvalds 4557644fbdeaSXin Long int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr, 4558644fbdeaSXin Long int addr_len, int flags) 4559644fbdeaSXin Long { 4560644fbdeaSXin Long if (addr_len < sizeof(uaddr->sa_family)) 4561644fbdeaSXin Long return -EINVAL; 4562644fbdeaSXin Long 4563644fbdeaSXin Long if (uaddr->sa_family == AF_UNSPEC) 4564644fbdeaSXin Long return -EOPNOTSUPP; 4565644fbdeaSXin Long 4566644fbdeaSXin Long return sctp_connect(sock->sk, uaddr, addr_len, flags); 4567644fbdeaSXin Long } 4568644fbdeaSXin Long 45691da177e4SLinus Torvalds /* FIXME: Write comments. */ 4570dda91928SDaniel Borkmann static int sctp_disconnect(struct sock *sk, int flags) 45711da177e4SLinus Torvalds { 45721da177e4SLinus Torvalds return -EOPNOTSUPP; /* STUB */ 45731da177e4SLinus Torvalds } 45741da177e4SLinus Torvalds 45751da177e4SLinus Torvalds /* 4.1.4 accept() - TCP Style Syntax 45761da177e4SLinus Torvalds * 45771da177e4SLinus Torvalds * Applications use accept() call to remove an established SCTP 45781da177e4SLinus Torvalds * association from the accept queue of the endpoint. A new socket 45791da177e4SLinus Torvalds * descriptor will be returned from accept() to represent the newly 45801da177e4SLinus Torvalds * formed association. 45811da177e4SLinus Torvalds */ 4582cdfbabfbSDavid Howells static struct sock *sctp_accept(struct sock *sk, int flags, int *err, bool kern) 45831da177e4SLinus Torvalds { 45841da177e4SLinus Torvalds struct sctp_sock *sp; 45851da177e4SLinus Torvalds struct sctp_endpoint *ep; 45861da177e4SLinus Torvalds struct sock *newsk = NULL; 45871da177e4SLinus Torvalds struct sctp_association *asoc; 45881da177e4SLinus Torvalds long timeo; 45891da177e4SLinus Torvalds int error = 0; 45901da177e4SLinus Torvalds 4591048ed4b6Swangweidong lock_sock(sk); 45921da177e4SLinus Torvalds 45931da177e4SLinus Torvalds sp = sctp_sk(sk); 45941da177e4SLinus Torvalds ep = sp->ep; 45951da177e4SLinus Torvalds 45961da177e4SLinus Torvalds if (!sctp_style(sk, TCP)) { 45971da177e4SLinus Torvalds error = -EOPNOTSUPP; 45981da177e4SLinus Torvalds goto out; 45991da177e4SLinus Torvalds } 46001da177e4SLinus Torvalds 46011da177e4SLinus Torvalds if (!sctp_sstate(sk, LISTENING)) { 46021da177e4SLinus Torvalds error = -EINVAL; 46031da177e4SLinus Torvalds goto out; 46041da177e4SLinus Torvalds } 46051da177e4SLinus Torvalds 46068abfedd8SSridhar Samudrala timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 46071da177e4SLinus Torvalds 46081da177e4SLinus Torvalds error = sctp_wait_for_accept(sk, timeo); 46091da177e4SLinus Torvalds if (error) 46101da177e4SLinus Torvalds goto out; 46111da177e4SLinus Torvalds 46121da177e4SLinus Torvalds /* We treat the list of associations on the endpoint as the accept 46131da177e4SLinus Torvalds * queue and pick the first association on the list. 46141da177e4SLinus Torvalds */ 46151da177e4SLinus Torvalds asoc = list_entry(ep->asocs.next, struct sctp_association, asocs); 46161da177e4SLinus Torvalds 4617cdfbabfbSDavid Howells newsk = sp->pf->create_accept_sk(sk, asoc, kern); 46181da177e4SLinus Torvalds if (!newsk) { 46191da177e4SLinus Torvalds error = -ENOMEM; 46201da177e4SLinus Torvalds goto out; 46211da177e4SLinus Torvalds } 46221da177e4SLinus Torvalds 46231da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the 46241da177e4SLinus Torvalds * asoc to the newsk. 46251da177e4SLinus Torvalds */ 46261da177e4SLinus Torvalds sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); 46271da177e4SLinus Torvalds 46281da177e4SLinus Torvalds out: 4629048ed4b6Swangweidong release_sock(sk); 46301da177e4SLinus Torvalds *err = error; 46311da177e4SLinus Torvalds return newsk; 46321da177e4SLinus Torvalds } 46331da177e4SLinus Torvalds 46341da177e4SLinus Torvalds /* The SCTP ioctl handler. */ 4635dda91928SDaniel Borkmann static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) 46361da177e4SLinus Torvalds { 463765040c33SDiego Elio 'Flameeyes' Pettenò int rc = -ENOTCONN; 463865040c33SDiego Elio 'Flameeyes' Pettenò 4639048ed4b6Swangweidong lock_sock(sk); 464065040c33SDiego Elio 'Flameeyes' Pettenò 464165040c33SDiego Elio 'Flameeyes' Pettenò /* 464265040c33SDiego Elio 'Flameeyes' Pettenò * SEQPACKET-style sockets in LISTENING state are valid, for 464365040c33SDiego Elio 'Flameeyes' Pettenò * SCTP, so only discard TCP-style sockets in LISTENING state. 464465040c33SDiego Elio 'Flameeyes' Pettenò */ 464565040c33SDiego Elio 'Flameeyes' Pettenò if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 464665040c33SDiego Elio 'Flameeyes' Pettenò goto out; 464765040c33SDiego Elio 'Flameeyes' Pettenò 464865040c33SDiego Elio 'Flameeyes' Pettenò switch (cmd) { 464965040c33SDiego Elio 'Flameeyes' Pettenò case SIOCINQ: { 465065040c33SDiego Elio 'Flameeyes' Pettenò struct sk_buff *skb; 465165040c33SDiego Elio 'Flameeyes' Pettenò unsigned int amount = 0; 465265040c33SDiego Elio 'Flameeyes' Pettenò 465365040c33SDiego Elio 'Flameeyes' Pettenò skb = skb_peek(&sk->sk_receive_queue); 465465040c33SDiego Elio 'Flameeyes' Pettenò if (skb != NULL) { 465565040c33SDiego Elio 'Flameeyes' Pettenò /* 465665040c33SDiego Elio 'Flameeyes' Pettenò * We will only return the amount of this packet since 465765040c33SDiego Elio 'Flameeyes' Pettenò * that is all that will be read. 465865040c33SDiego Elio 'Flameeyes' Pettenò */ 465965040c33SDiego Elio 'Flameeyes' Pettenò amount = skb->len; 466065040c33SDiego Elio 'Flameeyes' Pettenò } 466165040c33SDiego Elio 'Flameeyes' Pettenò rc = put_user(amount, (int __user *)arg); 466265040c33SDiego Elio 'Flameeyes' Pettenò break; 46639a7241c2SDavid S. Miller } 466465040c33SDiego Elio 'Flameeyes' Pettenò default: 466565040c33SDiego Elio 'Flameeyes' Pettenò rc = -ENOIOCTLCMD; 466665040c33SDiego Elio 'Flameeyes' Pettenò break; 466765040c33SDiego Elio 'Flameeyes' Pettenò } 466865040c33SDiego Elio 'Flameeyes' Pettenò out: 4669048ed4b6Swangweidong release_sock(sk); 467065040c33SDiego Elio 'Flameeyes' Pettenò return rc; 46711da177e4SLinus Torvalds } 46721da177e4SLinus Torvalds 46731da177e4SLinus Torvalds /* This is the function which gets called during socket creation to 46741da177e4SLinus Torvalds * initialized the SCTP-specific portion of the sock. 46751da177e4SLinus Torvalds * The sock structure should already be zero-filled memory. 46761da177e4SLinus Torvalds */ 4677dda91928SDaniel Borkmann static int sctp_init_sock(struct sock *sk) 46781da177e4SLinus Torvalds { 4679e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 46801da177e4SLinus Torvalds struct sctp_sock *sp; 46811da177e4SLinus Torvalds 4682bb33381dSDaniel Borkmann pr_debug("%s: sk:%p\n", __func__, sk); 46831da177e4SLinus Torvalds 46841da177e4SLinus Torvalds sp = sctp_sk(sk); 46851da177e4SLinus Torvalds 46861da177e4SLinus Torvalds /* Initialize the SCTP per socket area. */ 46871da177e4SLinus Torvalds switch (sk->sk_type) { 46881da177e4SLinus Torvalds case SOCK_SEQPACKET: 46891da177e4SLinus Torvalds sp->type = SCTP_SOCKET_UDP; 46901da177e4SLinus Torvalds break; 46911da177e4SLinus Torvalds case SOCK_STREAM: 46921da177e4SLinus Torvalds sp->type = SCTP_SOCKET_TCP; 46931da177e4SLinus Torvalds break; 46941da177e4SLinus Torvalds default: 46951da177e4SLinus Torvalds return -ESOCKTNOSUPPORT; 46961da177e4SLinus Torvalds } 46971da177e4SLinus Torvalds 469890017accSMarcelo Ricardo Leitner sk->sk_gso_type = SKB_GSO_SCTP; 469990017accSMarcelo Ricardo Leitner 47001da177e4SLinus Torvalds /* Initialize default send parameters. These parameters can be 47011da177e4SLinus Torvalds * modified with the SCTP_DEFAULT_SEND_PARAM socket option. 47021da177e4SLinus Torvalds */ 47031da177e4SLinus Torvalds sp->default_stream = 0; 47041da177e4SLinus Torvalds sp->default_ppid = 0; 47051da177e4SLinus Torvalds sp->default_flags = 0; 47061da177e4SLinus Torvalds sp->default_context = 0; 47071da177e4SLinus Torvalds sp->default_timetolive = 0; 47081da177e4SLinus Torvalds 47096ab792f5SIvan Skytte Jorgensen sp->default_rcv_context = 0; 4710e1fc3b14SEric W. Biederman sp->max_burst = net->sctp.max_burst; 47116ab792f5SIvan Skytte Jorgensen 47123c68198eSNeil Horman sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg; 47133c68198eSNeil Horman 47141da177e4SLinus Torvalds /* Initialize default setup parameters. These parameters 47151da177e4SLinus Torvalds * can be modified with the SCTP_INITMSG socket option or 47161da177e4SLinus Torvalds * overridden by the SCTP_INIT CMSG. 47171da177e4SLinus Torvalds */ 47181da177e4SLinus Torvalds sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; 47191da177e4SLinus Torvalds sp->initmsg.sinit_max_instreams = sctp_max_instreams; 4720e1fc3b14SEric W. Biederman sp->initmsg.sinit_max_attempts = net->sctp.max_retrans_init; 4721e1fc3b14SEric W. Biederman sp->initmsg.sinit_max_init_timeo = net->sctp.rto_max; 47221da177e4SLinus Torvalds 47231da177e4SLinus Torvalds /* Initialize default RTO related parameters. These parameters can 47241da177e4SLinus Torvalds * be modified for with the SCTP_RTOINFO socket option. 47251da177e4SLinus Torvalds */ 4726e1fc3b14SEric W. Biederman sp->rtoinfo.srto_initial = net->sctp.rto_initial; 4727e1fc3b14SEric W. Biederman sp->rtoinfo.srto_max = net->sctp.rto_max; 4728e1fc3b14SEric W. Biederman sp->rtoinfo.srto_min = net->sctp.rto_min; 47291da177e4SLinus Torvalds 47301da177e4SLinus Torvalds /* Initialize default association related parameters. These parameters 47311da177e4SLinus Torvalds * can be modified with the SCTP_ASSOCINFO socket option. 47321da177e4SLinus Torvalds */ 4733e1fc3b14SEric W. Biederman sp->assocparams.sasoc_asocmaxrxt = net->sctp.max_retrans_association; 47341da177e4SLinus Torvalds sp->assocparams.sasoc_number_peer_destinations = 0; 47351da177e4SLinus Torvalds sp->assocparams.sasoc_peer_rwnd = 0; 47361da177e4SLinus Torvalds sp->assocparams.sasoc_local_rwnd = 0; 4737e1fc3b14SEric W. Biederman sp->assocparams.sasoc_cookie_life = net->sctp.valid_cookie_life; 47381da177e4SLinus Torvalds 47391da177e4SLinus Torvalds /* Initialize default event subscriptions. By default, all the 47401da177e4SLinus Torvalds * options are off. 47411da177e4SLinus Torvalds */ 47421da177e4SLinus Torvalds memset(&sp->subscribe, 0, sizeof(struct sctp_event_subscribe)); 47431da177e4SLinus Torvalds 47441da177e4SLinus Torvalds /* Default Peer Address Parameters. These defaults can 47451da177e4SLinus Torvalds * be modified via SCTP_PEER_ADDR_PARAMS 47461da177e4SLinus Torvalds */ 4747e1fc3b14SEric W. Biederman sp->hbinterval = net->sctp.hb_interval; 4748e1fc3b14SEric W. Biederman sp->pathmaxrxt = net->sctp.max_retrans_path; 47494e2d52bfSwangweidong sp->pathmtu = 0; /* allow default discovery */ 4750e1fc3b14SEric W. Biederman sp->sackdelay = net->sctp.sack_timeout; 47517bfe8bdbSVlad Yasevich sp->sackfreq = 2; 475252ccb8e9SFrank Filz sp->param_flags = SPP_HB_ENABLE | 475352ccb8e9SFrank Filz SPP_PMTUD_ENABLE | 475452ccb8e9SFrank Filz SPP_SACKDELAY_ENABLE; 47551da177e4SLinus Torvalds 47561da177e4SLinus Torvalds /* If enabled no SCTP message fragmentation will be performed. 47571da177e4SLinus Torvalds * Configure through SCTP_DISABLE_FRAGMENTS socket option. 47581da177e4SLinus Torvalds */ 47591da177e4SLinus Torvalds sp->disable_fragments = 0; 47601da177e4SLinus Torvalds 4761208edef6SSridhar Samudrala /* Enable Nagle algorithm by default. */ 4762208edef6SSridhar Samudrala sp->nodelay = 0; 47631da177e4SLinus Torvalds 47640d3a421dSGeir Ola Vaagland sp->recvrcvinfo = 0; 47652347c80fSGeir Ola Vaagland sp->recvnxtinfo = 0; 47660d3a421dSGeir Ola Vaagland 47671da177e4SLinus Torvalds /* Enable by default. */ 47681da177e4SLinus Torvalds sp->v4mapped = 1; 47691da177e4SLinus Torvalds 47701da177e4SLinus Torvalds /* Auto-close idle associations after the configured 47711da177e4SLinus Torvalds * number of seconds. A value of 0 disables this 47721da177e4SLinus Torvalds * feature. Configure through the SCTP_AUTOCLOSE socket option, 47731da177e4SLinus Torvalds * for UDP-style sockets only. 47741da177e4SLinus Torvalds */ 47751da177e4SLinus Torvalds sp->autoclose = 0; 47761da177e4SLinus Torvalds 47771da177e4SLinus Torvalds /* User specified fragmentation limit. */ 47781da177e4SLinus Torvalds sp->user_frag = 0; 47791da177e4SLinus Torvalds 47800f3fffd8SIvan Skytte Jorgensen sp->adaptation_ind = 0; 47811da177e4SLinus Torvalds 47821da177e4SLinus Torvalds sp->pf = sctp_get_pf_specific(sk->sk_family); 47831da177e4SLinus Torvalds 47841da177e4SLinus Torvalds /* Control variables for partial data delivery. */ 4785b6e1331fSVlad Yasevich atomic_set(&sp->pd_mode, 0); 47861da177e4SLinus Torvalds skb_queue_head_init(&sp->pd_lobby); 4787b6e1331fSVlad Yasevich sp->frag_interleave = 0; 47881da177e4SLinus Torvalds 47891da177e4SLinus Torvalds /* Create a per socket endpoint structure. Even if we 47901da177e4SLinus Torvalds * change the data structure relationships, this may still 47911da177e4SLinus Torvalds * be useful for storing pre-connect address information. 47921da177e4SLinus Torvalds */ 4793c164b838SDaniel Borkmann sp->ep = sctp_endpoint_new(sk, GFP_KERNEL); 4794c164b838SDaniel Borkmann if (!sp->ep) 47951da177e4SLinus Torvalds return -ENOMEM; 47961da177e4SLinus Torvalds 47971da177e4SLinus Torvalds sp->hmac = NULL; 47981da177e4SLinus Torvalds 47990a2fbac1SDaniel Borkmann sk->sk_destruct = sctp_destruct_sock; 48000a2fbac1SDaniel Borkmann 48011da177e4SLinus Torvalds SCTP_DBG_OBJCNT_INC(sock); 48026f756a8cSDavid S. Miller 48036f756a8cSDavid S. Miller local_bh_disable(); 48048cb38a60STonghao Zhang sk_sockets_allocated_inc(sk); 4805e1fc3b14SEric W. Biederman sock_prot_inuse_add(net, sk->sk_prot, 1); 48062d45a02dSMarcelo Ricardo Leitner 48072d45a02dSMarcelo Ricardo Leitner /* Nothing can fail after this block, otherwise 48082d45a02dSMarcelo Ricardo Leitner * sctp_destroy_sock() will be called without addr_wq_lock held 48092d45a02dSMarcelo Ricardo Leitner */ 4810e1fc3b14SEric W. Biederman if (net->sctp.default_auto_asconf) { 48112d45a02dSMarcelo Ricardo Leitner spin_lock(&sock_net(sk)->sctp.addr_wq_lock); 48129f7d653bSMichio Honda list_add_tail(&sp->auto_asconf_list, 4813e1fc3b14SEric W. Biederman &net->sctp.auto_asconf_splist); 48149f7d653bSMichio Honda sp->do_auto_asconf = 1; 48152d45a02dSMarcelo Ricardo Leitner spin_unlock(&sock_net(sk)->sctp.addr_wq_lock); 48162d45a02dSMarcelo Ricardo Leitner } else { 48179f7d653bSMichio Honda sp->do_auto_asconf = 0; 48182d45a02dSMarcelo Ricardo Leitner } 48192d45a02dSMarcelo Ricardo Leitner 48206f756a8cSDavid S. Miller local_bh_enable(); 48216f756a8cSDavid S. Miller 48221da177e4SLinus Torvalds return 0; 48231da177e4SLinus Torvalds } 48241da177e4SLinus Torvalds 48252d45a02dSMarcelo Ricardo Leitner /* Cleanup any SCTP per socket resources. Must be called with 48262d45a02dSMarcelo Ricardo Leitner * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true 48272d45a02dSMarcelo Ricardo Leitner */ 4828dda91928SDaniel Borkmann static void sctp_destroy_sock(struct sock *sk) 48291da177e4SLinus Torvalds { 48309f7d653bSMichio Honda struct sctp_sock *sp; 48311da177e4SLinus Torvalds 4832bb33381dSDaniel Borkmann pr_debug("%s: sk:%p\n", __func__, sk); 48331da177e4SLinus Torvalds 48341da177e4SLinus Torvalds /* Release our hold on the endpoint. */ 48359f7d653bSMichio Honda sp = sctp_sk(sk); 48361abd165eSDaniel Borkmann /* This could happen during socket init, thus we bail out 48371abd165eSDaniel Borkmann * early, since the rest of the below is not setup either. 48381abd165eSDaniel Borkmann */ 48391abd165eSDaniel Borkmann if (sp->ep == NULL) 48401abd165eSDaniel Borkmann return; 48411abd165eSDaniel Borkmann 48429f7d653bSMichio Honda if (sp->do_auto_asconf) { 48439f7d653bSMichio Honda sp->do_auto_asconf = 0; 48449f7d653bSMichio Honda list_del(&sp->auto_asconf_list); 48459f7d653bSMichio Honda } 48469f7d653bSMichio Honda sctp_endpoint_free(sp->ep); 48475bc0b3bfSEric Dumazet local_bh_disable(); 48488cb38a60STonghao Zhang sk_sockets_allocated_dec(sk); 48499a57f7faSEric Dumazet sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 48505bc0b3bfSEric Dumazet local_bh_enable(); 48511da177e4SLinus Torvalds } 48521da177e4SLinus Torvalds 48530a2fbac1SDaniel Borkmann /* Triggered when there are no references on the socket anymore */ 48540a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk) 48550a2fbac1SDaniel Borkmann { 48560a2fbac1SDaniel Borkmann struct sctp_sock *sp = sctp_sk(sk); 48570a2fbac1SDaniel Borkmann 48580a2fbac1SDaniel Borkmann /* Free up the HMAC transform. */ 48595821c769SHerbert Xu crypto_free_shash(sp->hmac); 48600a2fbac1SDaniel Borkmann 48610a2fbac1SDaniel Borkmann inet_sock_destruct(sk); 48620a2fbac1SDaniel Borkmann } 48630a2fbac1SDaniel Borkmann 48641da177e4SLinus Torvalds /* API 4.1.7 shutdown() - TCP Style Syntax 48651da177e4SLinus Torvalds * int shutdown(int socket, int how); 48661da177e4SLinus Torvalds * 48671da177e4SLinus Torvalds * sd - the socket descriptor of the association to be closed. 48681da177e4SLinus Torvalds * how - Specifies the type of shutdown. The values are 48691da177e4SLinus Torvalds * as follows: 48701da177e4SLinus Torvalds * SHUT_RD 48711da177e4SLinus Torvalds * Disables further receive operations. No SCTP 48721da177e4SLinus Torvalds * protocol action is taken. 48731da177e4SLinus Torvalds * SHUT_WR 48741da177e4SLinus Torvalds * Disables further send operations, and initiates 48751da177e4SLinus Torvalds * the SCTP shutdown sequence. 48761da177e4SLinus Torvalds * SHUT_RDWR 48771da177e4SLinus Torvalds * Disables further send and receive operations 48781da177e4SLinus Torvalds * and initiates the SCTP shutdown sequence. 48791da177e4SLinus Torvalds */ 4880dda91928SDaniel Borkmann static void sctp_shutdown(struct sock *sk, int how) 48811da177e4SLinus Torvalds { 488255e26eb9SEric W. Biederman struct net *net = sock_net(sk); 48831da177e4SLinus Torvalds struct sctp_endpoint *ep; 48841da177e4SLinus Torvalds 48851da177e4SLinus Torvalds if (!sctp_style(sk, TCP)) 48861da177e4SLinus Torvalds return; 48871da177e4SLinus Torvalds 48881da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 48895bf35ddfSXin Long if (how & SEND_SHUTDOWN && !list_empty(&ep->asocs)) { 48905bf35ddfSXin Long struct sctp_association *asoc; 48915bf35ddfSXin Long 4892cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_CLOSING); 48931da177e4SLinus Torvalds asoc = list_entry(ep->asocs.next, 48941da177e4SLinus Torvalds struct sctp_association, asocs); 489555e26eb9SEric W. Biederman sctp_primitive_SHUTDOWN(net, asoc, NULL); 48961da177e4SLinus Torvalds } 48971da177e4SLinus Torvalds } 48981da177e4SLinus Torvalds 489952c52a61SXin Long int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, 490052c52a61SXin Long struct sctp_info *info) 490152c52a61SXin Long { 490252c52a61SXin Long struct sctp_transport *prim; 490352c52a61SXin Long struct list_head *pos; 490452c52a61SXin Long int mask; 490552c52a61SXin Long 490652c52a61SXin Long memset(info, 0, sizeof(*info)); 490752c52a61SXin Long if (!asoc) { 490852c52a61SXin Long struct sctp_sock *sp = sctp_sk(sk); 490952c52a61SXin Long 491052c52a61SXin Long info->sctpi_s_autoclose = sp->autoclose; 491152c52a61SXin Long info->sctpi_s_adaptation_ind = sp->adaptation_ind; 491252c52a61SXin Long info->sctpi_s_pd_point = sp->pd_point; 491352c52a61SXin Long info->sctpi_s_nodelay = sp->nodelay; 491452c52a61SXin Long info->sctpi_s_disable_fragments = sp->disable_fragments; 491552c52a61SXin Long info->sctpi_s_v4mapped = sp->v4mapped; 491652c52a61SXin Long info->sctpi_s_frag_interleave = sp->frag_interleave; 491740eb90e9SXin Long info->sctpi_s_type = sp->type; 491852c52a61SXin Long 491952c52a61SXin Long return 0; 492052c52a61SXin Long } 492152c52a61SXin Long 492252c52a61SXin Long info->sctpi_tag = asoc->c.my_vtag; 492352c52a61SXin Long info->sctpi_state = asoc->state; 492452c52a61SXin Long info->sctpi_rwnd = asoc->a_rwnd; 492552c52a61SXin Long info->sctpi_unackdata = asoc->unack_data; 492652c52a61SXin Long info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 4927cee360abSXin Long info->sctpi_instrms = asoc->stream.incnt; 4928cee360abSXin Long info->sctpi_outstrms = asoc->stream.outcnt; 492952c52a61SXin Long list_for_each(pos, &asoc->base.inqueue.in_chunk_list) 493052c52a61SXin Long info->sctpi_inqueue++; 493152c52a61SXin Long list_for_each(pos, &asoc->outqueue.out_chunk_list) 493252c52a61SXin Long info->sctpi_outqueue++; 493352c52a61SXin Long info->sctpi_overall_error = asoc->overall_error_count; 493452c52a61SXin Long info->sctpi_max_burst = asoc->max_burst; 493552c52a61SXin Long info->sctpi_maxseg = asoc->frag_point; 493652c52a61SXin Long info->sctpi_peer_rwnd = asoc->peer.rwnd; 493752c52a61SXin Long info->sctpi_peer_tag = asoc->c.peer_vtag; 493852c52a61SXin Long 493952c52a61SXin Long mask = asoc->peer.ecn_capable << 1; 494052c52a61SXin Long mask = (mask | asoc->peer.ipv4_address) << 1; 494152c52a61SXin Long mask = (mask | asoc->peer.ipv6_address) << 1; 494252c52a61SXin Long mask = (mask | asoc->peer.hostname_address) << 1; 494352c52a61SXin Long mask = (mask | asoc->peer.asconf_capable) << 1; 494452c52a61SXin Long mask = (mask | asoc->peer.prsctp_capable) << 1; 494552c52a61SXin Long mask = (mask | asoc->peer.auth_capable); 494652c52a61SXin Long info->sctpi_peer_capable = mask; 494752c52a61SXin Long mask = asoc->peer.sack_needed << 1; 494852c52a61SXin Long mask = (mask | asoc->peer.sack_generation) << 1; 494952c52a61SXin Long mask = (mask | asoc->peer.zero_window_announced); 495052c52a61SXin Long info->sctpi_peer_sack = mask; 495152c52a61SXin Long 495252c52a61SXin Long info->sctpi_isacks = asoc->stats.isacks; 495352c52a61SXin Long info->sctpi_osacks = asoc->stats.osacks; 495452c52a61SXin Long info->sctpi_opackets = asoc->stats.opackets; 495552c52a61SXin Long info->sctpi_ipackets = asoc->stats.ipackets; 495652c52a61SXin Long info->sctpi_rtxchunks = asoc->stats.rtxchunks; 495752c52a61SXin Long info->sctpi_outofseqtsns = asoc->stats.outofseqtsns; 495852c52a61SXin Long info->sctpi_idupchunks = asoc->stats.idupchunks; 495952c52a61SXin Long info->sctpi_gapcnt = asoc->stats.gapcnt; 496052c52a61SXin Long info->sctpi_ouodchunks = asoc->stats.ouodchunks; 496152c52a61SXin Long info->sctpi_iuodchunks = asoc->stats.iuodchunks; 496252c52a61SXin Long info->sctpi_oodchunks = asoc->stats.oodchunks; 496352c52a61SXin Long info->sctpi_iodchunks = asoc->stats.iodchunks; 496452c52a61SXin Long info->sctpi_octrlchunks = asoc->stats.octrlchunks; 496552c52a61SXin Long info->sctpi_ictrlchunks = asoc->stats.ictrlchunks; 496652c52a61SXin Long 496752c52a61SXin Long prim = asoc->peer.primary_path; 4968ee6c88bbSStefano Brivio memcpy(&info->sctpi_p_address, &prim->ipaddr, sizeof(prim->ipaddr)); 496952c52a61SXin Long info->sctpi_p_state = prim->state; 497052c52a61SXin Long info->sctpi_p_cwnd = prim->cwnd; 497152c52a61SXin Long info->sctpi_p_srtt = prim->srtt; 497252c52a61SXin Long info->sctpi_p_rto = jiffies_to_msecs(prim->rto); 497352c52a61SXin Long info->sctpi_p_hbinterval = prim->hbinterval; 497452c52a61SXin Long info->sctpi_p_pathmaxrxt = prim->pathmaxrxt; 497552c52a61SXin Long info->sctpi_p_sackdelay = jiffies_to_msecs(prim->sackdelay); 497652c52a61SXin Long info->sctpi_p_ssthresh = prim->ssthresh; 497752c52a61SXin Long info->sctpi_p_partial_bytes_acked = prim->partial_bytes_acked; 497852c52a61SXin Long info->sctpi_p_flight_size = prim->flight_size; 497952c52a61SXin Long info->sctpi_p_error = prim->error_count; 498052c52a61SXin Long 498152c52a61SXin Long return 0; 498252c52a61SXin Long } 498352c52a61SXin Long EXPORT_SYMBOL_GPL(sctp_get_sctp_info); 498452c52a61SXin Long 4985626d16f5SXin Long /* use callback to avoid exporting the core structure */ 498697a6ec4aSTom Herbert void sctp_transport_walk_start(struct rhashtable_iter *iter) 4987626d16f5SXin Long { 49887fda702fSXin Long rhltable_walk_enter(&sctp_transport_hashtable, iter); 4989626d16f5SXin Long 499097a6ec4aSTom Herbert rhashtable_walk_start(iter); 4991626d16f5SXin Long } 4992626d16f5SXin Long 4993626d16f5SXin Long void sctp_transport_walk_stop(struct rhashtable_iter *iter) 4994626d16f5SXin Long { 4995626d16f5SXin Long rhashtable_walk_stop(iter); 4996626d16f5SXin Long rhashtable_walk_exit(iter); 4997626d16f5SXin Long } 4998626d16f5SXin Long 4999626d16f5SXin Long struct sctp_transport *sctp_transport_get_next(struct net *net, 5000626d16f5SXin Long struct rhashtable_iter *iter) 5001626d16f5SXin Long { 5002626d16f5SXin Long struct sctp_transport *t; 5003626d16f5SXin Long 5004626d16f5SXin Long t = rhashtable_walk_next(iter); 5005626d16f5SXin Long for (; t; t = rhashtable_walk_next(iter)) { 5006626d16f5SXin Long if (IS_ERR(t)) { 5007626d16f5SXin Long if (PTR_ERR(t) == -EAGAIN) 5008626d16f5SXin Long continue; 5009626d16f5SXin Long break; 5010626d16f5SXin Long } 5011626d16f5SXin Long 5012bab1be79SXin Long if (!sctp_transport_hold(t)) 5013bab1be79SXin Long continue; 5014bab1be79SXin Long 5015626d16f5SXin Long if (net_eq(sock_net(t->asoc->base.sk), net) && 5016626d16f5SXin Long t->asoc->peer.primary_path == t) 5017626d16f5SXin Long break; 5018bab1be79SXin Long 5019bab1be79SXin Long sctp_transport_put(t); 5020626d16f5SXin Long } 5021626d16f5SXin Long 5022626d16f5SXin Long return t; 5023626d16f5SXin Long } 5024626d16f5SXin Long 5025626d16f5SXin Long struct sctp_transport *sctp_transport_get_idx(struct net *net, 5026626d16f5SXin Long struct rhashtable_iter *iter, 5027626d16f5SXin Long int pos) 5028626d16f5SXin Long { 5029bab1be79SXin Long struct sctp_transport *t; 5030626d16f5SXin Long 5031bab1be79SXin Long if (!pos) 5032bab1be79SXin Long return SEQ_START_TOKEN; 5033626d16f5SXin Long 5034bab1be79SXin Long while ((t = sctp_transport_get_next(net, iter)) && !IS_ERR(t)) { 5035bab1be79SXin Long if (!--pos) 5036bab1be79SXin Long break; 5037bab1be79SXin Long sctp_transport_put(t); 5038bab1be79SXin Long } 5039bab1be79SXin Long 5040bab1be79SXin Long return t; 5041626d16f5SXin Long } 5042626d16f5SXin Long 5043626d16f5SXin Long int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), 5044626d16f5SXin Long void *p) { 5045626d16f5SXin Long int err = 0; 5046626d16f5SXin Long int hash = 0; 5047626d16f5SXin Long struct sctp_ep_common *epb; 5048626d16f5SXin Long struct sctp_hashbucket *head; 5049626d16f5SXin Long 5050626d16f5SXin Long for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize; 5051626d16f5SXin Long hash++, head++) { 5052581409daSXin Long read_lock_bh(&head->lock); 5053626d16f5SXin Long sctp_for_each_hentry(epb, &head->chain) { 5054626d16f5SXin Long err = cb(sctp_ep(epb), p); 5055626d16f5SXin Long if (err) 5056626d16f5SXin Long break; 5057626d16f5SXin Long } 5058581409daSXin Long read_unlock_bh(&head->lock); 5059626d16f5SXin Long } 5060626d16f5SXin Long 5061626d16f5SXin Long return err; 5062626d16f5SXin Long } 5063626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_for_each_endpoint); 5064626d16f5SXin Long 5065626d16f5SXin Long int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *), 5066626d16f5SXin Long struct net *net, 5067626d16f5SXin Long const union sctp_addr *laddr, 5068626d16f5SXin Long const union sctp_addr *paddr, void *p) 5069626d16f5SXin Long { 5070626d16f5SXin Long struct sctp_transport *transport; 507108abb795SXin Long int err; 5072626d16f5SXin Long 5073626d16f5SXin Long rcu_read_lock(); 5074626d16f5SXin Long transport = sctp_addrs_lookup_transport(net, laddr, paddr); 5075626d16f5SXin Long rcu_read_unlock(); 507608abb795SXin Long if (!transport) 507708abb795SXin Long return -ENOENT; 507808abb795SXin Long 50791cceda78SXin Long err = cb(transport, p); 5080cd26da4fSXin Long sctp_transport_put(transport); 50811cceda78SXin Long 5082626d16f5SXin Long return err; 5083626d16f5SXin Long } 5084626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_transport_lookup_process); 5085626d16f5SXin Long 5086626d16f5SXin Long int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *), 5087d25adbebSXin Long int (*cb_done)(struct sctp_transport *, void *), 5088d25adbebSXin Long struct net *net, int *pos, void *p) { 5089626d16f5SXin Long struct rhashtable_iter hti; 5090d25adbebSXin Long struct sctp_transport *tsp; 5091d25adbebSXin Long int ret; 5092626d16f5SXin Long 5093d25adbebSXin Long again: 5094f53d77e1SXin Long ret = 0; 509597a6ec4aSTom Herbert sctp_transport_walk_start(&hti); 5096626d16f5SXin Long 5097d25adbebSXin Long tsp = sctp_transport_get_idx(net, &hti, *pos + 1); 5098d25adbebSXin Long for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) { 5099d25adbebSXin Long ret = cb(tsp, p); 5100d25adbebSXin Long if (ret) 5101626d16f5SXin Long break; 5102d25adbebSXin Long (*pos)++; 5103d25adbebSXin Long sctp_transport_put(tsp); 5104626d16f5SXin Long } 5105626d16f5SXin Long sctp_transport_walk_stop(&hti); 510653fa1036SXin Long 5107d25adbebSXin Long if (ret) { 5108d25adbebSXin Long if (cb_done && !cb_done(tsp, p)) { 5109d25adbebSXin Long (*pos)++; 5110d25adbebSXin Long sctp_transport_put(tsp); 5111d25adbebSXin Long goto again; 5112d25adbebSXin Long } 5113d25adbebSXin Long sctp_transport_put(tsp); 5114d25adbebSXin Long } 5115d25adbebSXin Long 5116d25adbebSXin Long return ret; 5117626d16f5SXin Long } 5118626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_for_each_transport); 5119626d16f5SXin Long 51201da177e4SLinus Torvalds /* 7.2.1 Association Status (SCTP_STATUS) 51211da177e4SLinus Torvalds 51221da177e4SLinus Torvalds * Applications can retrieve current status information about an 51231da177e4SLinus Torvalds * association, including association state, peer receiver window size, 51241da177e4SLinus Torvalds * number of unacked data chunks, and number of data chunks pending 51251da177e4SLinus Torvalds * receipt. This information is read-only. 51261da177e4SLinus Torvalds */ 51271da177e4SLinus Torvalds static int sctp_getsockopt_sctp_status(struct sock *sk, int len, 51281da177e4SLinus Torvalds char __user *optval, 51291da177e4SLinus Torvalds int __user *optlen) 51301da177e4SLinus Torvalds { 51311da177e4SLinus Torvalds struct sctp_status status; 51321da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 51331da177e4SLinus Torvalds struct sctp_transport *transport; 51341da177e4SLinus Torvalds sctp_assoc_t associd; 51351da177e4SLinus Torvalds int retval = 0; 51361da177e4SLinus Torvalds 5137408f22e8SNeil Horman if (len < sizeof(status)) { 51381da177e4SLinus Torvalds retval = -EINVAL; 51391da177e4SLinus Torvalds goto out; 51401da177e4SLinus Torvalds } 51411da177e4SLinus Torvalds 5142408f22e8SNeil Horman len = sizeof(status); 5143408f22e8SNeil Horman if (copy_from_user(&status, optval, len)) { 51441da177e4SLinus Torvalds retval = -EFAULT; 51451da177e4SLinus Torvalds goto out; 51461da177e4SLinus Torvalds } 51471da177e4SLinus Torvalds 51481da177e4SLinus Torvalds associd = status.sstat_assoc_id; 51491da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, associd); 51501da177e4SLinus Torvalds if (!asoc) { 51511da177e4SLinus Torvalds retval = -EINVAL; 51521da177e4SLinus Torvalds goto out; 51531da177e4SLinus Torvalds } 51541da177e4SLinus Torvalds 51551da177e4SLinus Torvalds transport = asoc->peer.primary_path; 51561da177e4SLinus Torvalds 51571da177e4SLinus Torvalds status.sstat_assoc_id = sctp_assoc2id(asoc); 515838ab1fa9SDaniel Borkmann status.sstat_state = sctp_assoc_to_state(asoc); 51591da177e4SLinus Torvalds status.sstat_rwnd = asoc->peer.rwnd; 51601da177e4SLinus Torvalds status.sstat_unackdata = asoc->unack_data; 51611da177e4SLinus Torvalds 51621da177e4SLinus Torvalds status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 5163cee360abSXin Long status.sstat_instrms = asoc->stream.incnt; 5164cee360abSXin Long status.sstat_outstrms = asoc->stream.outcnt; 51651da177e4SLinus Torvalds status.sstat_fragmentation_point = asoc->frag_point; 51661da177e4SLinus Torvalds status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 51678cec6b80SAl Viro memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, 51688cec6b80SAl Viro transport->af_specific->sockaddr_len); 51691da177e4SLinus Torvalds /* Map ipv4 address into v4-mapped-on-v6 address. */ 5170299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), 51711da177e4SLinus Torvalds (union sctp_addr *)&status.sstat_primary.spinfo_address); 51723f7a87d2SFrank Filz status.sstat_primary.spinfo_state = transport->state; 51731da177e4SLinus Torvalds status.sstat_primary.spinfo_cwnd = transport->cwnd; 51741da177e4SLinus Torvalds status.sstat_primary.spinfo_srtt = transport->srtt; 51751da177e4SLinus Torvalds status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto); 517652ccb8e9SFrank Filz status.sstat_primary.spinfo_mtu = transport->pathmtu; 51771da177e4SLinus Torvalds 51783f7a87d2SFrank Filz if (status.sstat_primary.spinfo_state == SCTP_UNKNOWN) 51793f7a87d2SFrank Filz status.sstat_primary.spinfo_state = SCTP_ACTIVE; 51803f7a87d2SFrank Filz 51811da177e4SLinus Torvalds if (put_user(len, optlen)) { 51821da177e4SLinus Torvalds retval = -EFAULT; 51831da177e4SLinus Torvalds goto out; 51841da177e4SLinus Torvalds } 51851da177e4SLinus Torvalds 5186bb33381dSDaniel Borkmann pr_debug("%s: len:%d, state:%d, rwnd:%d, assoc_id:%d\n", 5187bb33381dSDaniel Borkmann __func__, len, status.sstat_state, status.sstat_rwnd, 51881da177e4SLinus Torvalds status.sstat_assoc_id); 51891da177e4SLinus Torvalds 51901da177e4SLinus Torvalds if (copy_to_user(optval, &status, len)) { 51911da177e4SLinus Torvalds retval = -EFAULT; 51921da177e4SLinus Torvalds goto out; 51931da177e4SLinus Torvalds } 51941da177e4SLinus Torvalds 51951da177e4SLinus Torvalds out: 5196a02cec21SEric Dumazet return retval; 51971da177e4SLinus Torvalds } 51981da177e4SLinus Torvalds 51991da177e4SLinus Torvalds 52001da177e4SLinus Torvalds /* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO) 52011da177e4SLinus Torvalds * 52021da177e4SLinus Torvalds * Applications can retrieve information about a specific peer address 52031da177e4SLinus Torvalds * of an association, including its reachability state, congestion 52041da177e4SLinus Torvalds * window, and retransmission timer values. This information is 52051da177e4SLinus Torvalds * read-only. 52061da177e4SLinus Torvalds */ 52071da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, 52081da177e4SLinus Torvalds char __user *optval, 52091da177e4SLinus Torvalds int __user *optlen) 52101da177e4SLinus Torvalds { 52111da177e4SLinus Torvalds struct sctp_paddrinfo pinfo; 52121da177e4SLinus Torvalds struct sctp_transport *transport; 52131da177e4SLinus Torvalds int retval = 0; 52141da177e4SLinus Torvalds 5215408f22e8SNeil Horman if (len < sizeof(pinfo)) { 52161da177e4SLinus Torvalds retval = -EINVAL; 52171da177e4SLinus Torvalds goto out; 52181da177e4SLinus Torvalds } 52191da177e4SLinus Torvalds 5220408f22e8SNeil Horman len = sizeof(pinfo); 5221408f22e8SNeil Horman if (copy_from_user(&pinfo, optval, len)) { 52221da177e4SLinus Torvalds retval = -EFAULT; 52231da177e4SLinus Torvalds goto out; 52241da177e4SLinus Torvalds } 52251da177e4SLinus Torvalds 52261da177e4SLinus Torvalds transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address, 52271da177e4SLinus Torvalds pinfo.spinfo_assoc_id); 52281da177e4SLinus Torvalds if (!transport) 52291da177e4SLinus Torvalds return -EINVAL; 52301da177e4SLinus Torvalds 52311da177e4SLinus Torvalds pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 52323f7a87d2SFrank Filz pinfo.spinfo_state = transport->state; 52331da177e4SLinus Torvalds pinfo.spinfo_cwnd = transport->cwnd; 52341da177e4SLinus Torvalds pinfo.spinfo_srtt = transport->srtt; 52351da177e4SLinus Torvalds pinfo.spinfo_rto = jiffies_to_msecs(transport->rto); 523652ccb8e9SFrank Filz pinfo.spinfo_mtu = transport->pathmtu; 52371da177e4SLinus Torvalds 52383f7a87d2SFrank Filz if (pinfo.spinfo_state == SCTP_UNKNOWN) 52393f7a87d2SFrank Filz pinfo.spinfo_state = SCTP_ACTIVE; 52403f7a87d2SFrank Filz 52411da177e4SLinus Torvalds if (put_user(len, optlen)) { 52421da177e4SLinus Torvalds retval = -EFAULT; 52431da177e4SLinus Torvalds goto out; 52441da177e4SLinus Torvalds } 52451da177e4SLinus Torvalds 52461da177e4SLinus Torvalds if (copy_to_user(optval, &pinfo, len)) { 52471da177e4SLinus Torvalds retval = -EFAULT; 52481da177e4SLinus Torvalds goto out; 52491da177e4SLinus Torvalds } 52501da177e4SLinus Torvalds 52511da177e4SLinus Torvalds out: 5252a02cec21SEric Dumazet return retval; 52531da177e4SLinus Torvalds } 52541da177e4SLinus Torvalds 52551da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) 52561da177e4SLinus Torvalds * 52571da177e4SLinus Torvalds * This option is a on/off flag. If enabled no SCTP message 52581da177e4SLinus Torvalds * fragmentation will be performed. Instead if a message being sent 52591da177e4SLinus Torvalds * exceeds the current PMTU size, the message will NOT be sent and 52601da177e4SLinus Torvalds * instead a error will be indicated to the user. 52611da177e4SLinus Torvalds */ 52621da177e4SLinus Torvalds static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, 52631da177e4SLinus Torvalds char __user *optval, int __user *optlen) 52641da177e4SLinus Torvalds { 52651da177e4SLinus Torvalds int val; 52661da177e4SLinus Torvalds 52671da177e4SLinus Torvalds if (len < sizeof(int)) 52681da177e4SLinus Torvalds return -EINVAL; 52691da177e4SLinus Torvalds 52701da177e4SLinus Torvalds len = sizeof(int); 52711da177e4SLinus Torvalds val = (sctp_sk(sk)->disable_fragments == 1); 52721da177e4SLinus Torvalds if (put_user(len, optlen)) 52731da177e4SLinus Torvalds return -EFAULT; 52741da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 52751da177e4SLinus Torvalds return -EFAULT; 52761da177e4SLinus Torvalds return 0; 52771da177e4SLinus Torvalds } 52781da177e4SLinus Torvalds 52791da177e4SLinus Torvalds /* 7.1.15 Set notification and ancillary events (SCTP_EVENTS) 52801da177e4SLinus Torvalds * 52811da177e4SLinus Torvalds * This socket option is used to specify various notifications and 52821da177e4SLinus Torvalds * ancillary data the user wishes to receive. 52831da177e4SLinus Torvalds */ 52841da177e4SLinus Torvalds static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, 52851da177e4SLinus Torvalds int __user *optlen) 52861da177e4SLinus Torvalds { 5287a4b8e71bSJiri Slaby if (len == 0) 52881da177e4SLinus Torvalds return -EINVAL; 5289acdd5985SThomas Graf if (len > sizeof(struct sctp_event_subscribe)) 5290408f22e8SNeil Horman len = sizeof(struct sctp_event_subscribe); 5291408f22e8SNeil Horman if (put_user(len, optlen)) 5292408f22e8SNeil Horman return -EFAULT; 52931da177e4SLinus Torvalds if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len)) 52941da177e4SLinus Torvalds return -EFAULT; 52951da177e4SLinus Torvalds return 0; 52961da177e4SLinus Torvalds } 52971da177e4SLinus Torvalds 52981da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) 52991da177e4SLinus Torvalds * 53001da177e4SLinus Torvalds * This socket option is applicable to the UDP-style socket only. When 53011da177e4SLinus Torvalds * set it will cause associations that are idle for more than the 53021da177e4SLinus Torvalds * specified number of seconds to automatically close. An association 53031da177e4SLinus Torvalds * being idle is defined an association that has NOT sent or received 53041da177e4SLinus Torvalds * user data. The special value of '0' indicates that no automatic 53051da177e4SLinus Torvalds * close of any associations should be performed. The option expects an 53061da177e4SLinus Torvalds * integer defining the number of seconds of idle time before an 53071da177e4SLinus Torvalds * association is closed. 53081da177e4SLinus Torvalds */ 53091da177e4SLinus Torvalds static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optval, int __user *optlen) 53101da177e4SLinus Torvalds { 53111da177e4SLinus Torvalds /* Applicable to UDP-style socket only */ 53121da177e4SLinus Torvalds if (sctp_style(sk, TCP)) 53131da177e4SLinus Torvalds return -EOPNOTSUPP; 5314408f22e8SNeil Horman if (len < sizeof(int)) 53151da177e4SLinus Torvalds return -EINVAL; 5316408f22e8SNeil Horman len = sizeof(int); 5317408f22e8SNeil Horman if (put_user(len, optlen)) 5318408f22e8SNeil Horman return -EFAULT; 5319b2ce04c2SDavid Windsor if (put_user(sctp_sk(sk)->autoclose, (int __user *)optval)) 53201da177e4SLinus Torvalds return -EFAULT; 53211da177e4SLinus Torvalds return 0; 53221da177e4SLinus Torvalds } 53231da177e4SLinus Torvalds 53241da177e4SLinus Torvalds /* Helper routine to branch off an association to a new socket. */ 53250343c554SBenjamin Poirier int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) 53261da177e4SLinus Torvalds { 53270343c554SBenjamin Poirier struct sctp_association *asoc = sctp_id2assoc(sk, id); 5328299ee123SJason Gunthorpe struct sctp_sock *sp = sctp_sk(sk); 53291da177e4SLinus Torvalds struct socket *sock; 53301da177e4SLinus Torvalds int err = 0; 53311da177e4SLinus Torvalds 5332df80cd9bSXin Long /* Do not peel off from one netns to another one. */ 5333df80cd9bSXin Long if (!net_eq(current->nsproxy->net_ns, sock_net(sk))) 5334df80cd9bSXin Long return -EINVAL; 5335df80cd9bSXin Long 53360343c554SBenjamin Poirier if (!asoc) 53370343c554SBenjamin Poirier return -EINVAL; 53380343c554SBenjamin Poirier 53391da177e4SLinus Torvalds /* An association cannot be branched off from an already peeled-off 53401da177e4SLinus Torvalds * socket, nor is this supported for tcp style sockets. 53411da177e4SLinus Torvalds */ 53421da177e4SLinus Torvalds if (!sctp_style(sk, UDP)) 53431da177e4SLinus Torvalds return -EINVAL; 53441da177e4SLinus Torvalds 53451da177e4SLinus Torvalds /* Create a new socket. */ 53461da177e4SLinus Torvalds err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); 53471da177e4SLinus Torvalds if (err < 0) 53481da177e4SLinus Torvalds return err; 53491da177e4SLinus Torvalds 5350914e1c8bSVlad Yasevich sctp_copy_sock(sock->sk, sk, asoc); 53514f444308SVlad Yasevich 53524f444308SVlad Yasevich /* Make peeled-off sockets more like 1-1 accepted sockets. 5353b7e10c25SRichard Haines * Set the daddr and initialize id to something more random and also 5354b7e10c25SRichard Haines * copy over any ip options. 53554f444308SVlad Yasevich */ 5356299ee123SJason Gunthorpe sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk); 5357b7e10c25SRichard Haines sp->pf->copy_ip_options(sk, sock->sk); 5358914e1c8bSVlad Yasevich 5359914e1c8bSVlad Yasevich /* Populate the fields of the newsk from the oldsk and migrate the 5360914e1c8bSVlad Yasevich * asoc to the newsk. 5361914e1c8bSVlad Yasevich */ 5362914e1c8bSVlad Yasevich sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); 53634f444308SVlad Yasevich 53641da177e4SLinus Torvalds *sockp = sock; 53651da177e4SLinus Torvalds 53661da177e4SLinus Torvalds return err; 53671da177e4SLinus Torvalds } 53680343c554SBenjamin Poirier EXPORT_SYMBOL(sctp_do_peeloff); 53691da177e4SLinus Torvalds 53702cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *peeloff, 53712cb5c8e3SNeil Horman struct file **newfile, unsigned flags) 53722cb5c8e3SNeil Horman { 53732cb5c8e3SNeil Horman struct socket *newsock; 53742cb5c8e3SNeil Horman int retval; 53752cb5c8e3SNeil Horman 53762cb5c8e3SNeil Horman retval = sctp_do_peeloff(sk, peeloff->associd, &newsock); 53772cb5c8e3SNeil Horman if (retval < 0) 53782cb5c8e3SNeil Horman goto out; 53792cb5c8e3SNeil Horman 53802cb5c8e3SNeil Horman /* Map the socket to an unused fd that can be returned to the user. */ 53812cb5c8e3SNeil Horman retval = get_unused_fd_flags(flags & SOCK_CLOEXEC); 53822cb5c8e3SNeil Horman if (retval < 0) { 53832cb5c8e3SNeil Horman sock_release(newsock); 53842cb5c8e3SNeil Horman goto out; 53852cb5c8e3SNeil Horman } 53862cb5c8e3SNeil Horman 53872cb5c8e3SNeil Horman *newfile = sock_alloc_file(newsock, 0, NULL); 53882cb5c8e3SNeil Horman if (IS_ERR(*newfile)) { 53892cb5c8e3SNeil Horman put_unused_fd(retval); 53902cb5c8e3SNeil Horman retval = PTR_ERR(*newfile); 53912cb5c8e3SNeil Horman *newfile = NULL; 53922cb5c8e3SNeil Horman return retval; 53932cb5c8e3SNeil Horman } 53942cb5c8e3SNeil Horman 53952cb5c8e3SNeil Horman pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk, 53962cb5c8e3SNeil Horman retval); 53972cb5c8e3SNeil Horman 53982cb5c8e3SNeil Horman peeloff->sd = retval; 53992cb5c8e3SNeil Horman 54002cb5c8e3SNeil Horman if (flags & SOCK_NONBLOCK) 54012cb5c8e3SNeil Horman (*newfile)->f_flags |= O_NONBLOCK; 54022cb5c8e3SNeil Horman out: 54032cb5c8e3SNeil Horman return retval; 54042cb5c8e3SNeil Horman } 54052cb5c8e3SNeil Horman 54061da177e4SLinus Torvalds static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) 54071da177e4SLinus Torvalds { 54081da177e4SLinus Torvalds sctp_peeloff_arg_t peeloff; 54092cb5c8e3SNeil Horman struct file *newfile = NULL; 54101da177e4SLinus Torvalds int retval = 0; 54111da177e4SLinus Torvalds 5412408f22e8SNeil Horman if (len < sizeof(sctp_peeloff_arg_t)) 54131da177e4SLinus Torvalds return -EINVAL; 5414408f22e8SNeil Horman len = sizeof(sctp_peeloff_arg_t); 54151da177e4SLinus Torvalds if (copy_from_user(&peeloff, optval, len)) 54161da177e4SLinus Torvalds return -EFAULT; 54171da177e4SLinus Torvalds 54182cb5c8e3SNeil Horman retval = sctp_getsockopt_peeloff_common(sk, &peeloff, &newfile, 0); 54191da177e4SLinus Torvalds if (retval < 0) 54201da177e4SLinus Torvalds goto out; 54211da177e4SLinus Torvalds 54221da177e4SLinus Torvalds /* Return the fd mapped to the new socket. */ 542356b31d1cSAl Viro if (put_user(len, optlen)) { 542456b31d1cSAl Viro fput(newfile); 542556b31d1cSAl Viro put_unused_fd(retval); 5426408f22e8SNeil Horman return -EFAULT; 542756b31d1cSAl Viro } 54282cb5c8e3SNeil Horman 54292cb5c8e3SNeil Horman if (copy_to_user(optval, &peeloff, len)) { 54302cb5c8e3SNeil Horman fput(newfile); 54312cb5c8e3SNeil Horman put_unused_fd(retval); 54322cb5c8e3SNeil Horman return -EFAULT; 54332cb5c8e3SNeil Horman } 54342cb5c8e3SNeil Horman fd_install(retval, newfile); 54352cb5c8e3SNeil Horman out: 54362cb5c8e3SNeil Horman return retval; 54372cb5c8e3SNeil Horman } 54382cb5c8e3SNeil Horman 54392cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len, 54402cb5c8e3SNeil Horman char __user *optval, int __user *optlen) 54412cb5c8e3SNeil Horman { 54422cb5c8e3SNeil Horman sctp_peeloff_flags_arg_t peeloff; 54432cb5c8e3SNeil Horman struct file *newfile = NULL; 54442cb5c8e3SNeil Horman int retval = 0; 54452cb5c8e3SNeil Horman 54462cb5c8e3SNeil Horman if (len < sizeof(sctp_peeloff_flags_arg_t)) 54472cb5c8e3SNeil Horman return -EINVAL; 54482cb5c8e3SNeil Horman len = sizeof(sctp_peeloff_flags_arg_t); 54492cb5c8e3SNeil Horman if (copy_from_user(&peeloff, optval, len)) 54502cb5c8e3SNeil Horman return -EFAULT; 54512cb5c8e3SNeil Horman 54522cb5c8e3SNeil Horman retval = sctp_getsockopt_peeloff_common(sk, &peeloff.p_arg, 54532cb5c8e3SNeil Horman &newfile, peeloff.flags); 54542cb5c8e3SNeil Horman if (retval < 0) 54552cb5c8e3SNeil Horman goto out; 54562cb5c8e3SNeil Horman 54572cb5c8e3SNeil Horman /* Return the fd mapped to the new socket. */ 54582cb5c8e3SNeil Horman if (put_user(len, optlen)) { 54592cb5c8e3SNeil Horman fput(newfile); 54602cb5c8e3SNeil Horman put_unused_fd(retval); 54612cb5c8e3SNeil Horman return -EFAULT; 54622cb5c8e3SNeil Horman } 54632cb5c8e3SNeil Horman 546456b31d1cSAl Viro if (copy_to_user(optval, &peeloff, len)) { 546556b31d1cSAl Viro fput(newfile); 546656b31d1cSAl Viro put_unused_fd(retval); 546756b31d1cSAl Viro return -EFAULT; 546856b31d1cSAl Viro } 546956b31d1cSAl Viro fd_install(retval, newfile); 54701da177e4SLinus Torvalds out: 54711da177e4SLinus Torvalds return retval; 54721da177e4SLinus Torvalds } 54731da177e4SLinus Torvalds 54741da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) 54751da177e4SLinus Torvalds * 54761da177e4SLinus Torvalds * Applications can enable or disable heartbeats for any peer address of 54771da177e4SLinus Torvalds * an association, modify an address's heartbeat interval, force a 54781da177e4SLinus Torvalds * heartbeat to be sent immediately, and adjust the address's maximum 54791da177e4SLinus Torvalds * number of retransmissions sent before an address is considered 54801da177e4SLinus Torvalds * unreachable. The following structure is used to access and modify an 54811da177e4SLinus Torvalds * address's parameters: 54821da177e4SLinus Torvalds * 54831da177e4SLinus Torvalds * struct sctp_paddrparams { 54841da177e4SLinus Torvalds * sctp_assoc_t spp_assoc_id; 54851da177e4SLinus Torvalds * struct sockaddr_storage spp_address; 54861da177e4SLinus Torvalds * uint32_t spp_hbinterval; 54871da177e4SLinus Torvalds * uint16_t spp_pathmaxrxt; 548852ccb8e9SFrank Filz * uint32_t spp_pathmtu; 548952ccb8e9SFrank Filz * uint32_t spp_sackdelay; 549052ccb8e9SFrank Filz * uint32_t spp_flags; 54911da177e4SLinus Torvalds * }; 54921da177e4SLinus Torvalds * 549352ccb8e9SFrank Filz * spp_assoc_id - (one-to-many style socket) This is filled in the 549452ccb8e9SFrank Filz * application, and identifies the association for 549552ccb8e9SFrank Filz * this query. 54961da177e4SLinus Torvalds * spp_address - This specifies which address is of interest. 54971da177e4SLinus Torvalds * spp_hbinterval - This contains the value of the heartbeat interval, 549852ccb8e9SFrank Filz * in milliseconds. If a value of zero 549952ccb8e9SFrank Filz * is present in this field then no changes are to 550052ccb8e9SFrank Filz * be made to this parameter. 55011da177e4SLinus Torvalds * spp_pathmaxrxt - This contains the maximum number of 55021da177e4SLinus Torvalds * retransmissions before this address shall be 550352ccb8e9SFrank Filz * considered unreachable. If a value of zero 550452ccb8e9SFrank Filz * is present in this field then no changes are to 550552ccb8e9SFrank Filz * be made to this parameter. 550652ccb8e9SFrank Filz * spp_pathmtu - When Path MTU discovery is disabled the value 550752ccb8e9SFrank Filz * specified here will be the "fixed" path mtu. 550852ccb8e9SFrank Filz * Note that if the spp_address field is empty 550952ccb8e9SFrank Filz * then all associations on this address will 551052ccb8e9SFrank Filz * have this fixed path mtu set upon them. 551152ccb8e9SFrank Filz * 551252ccb8e9SFrank Filz * spp_sackdelay - When delayed sack is enabled, this value specifies 551352ccb8e9SFrank Filz * the number of milliseconds that sacks will be delayed 551452ccb8e9SFrank Filz * for. This value will apply to all addresses of an 551552ccb8e9SFrank Filz * association if the spp_address field is empty. Note 551652ccb8e9SFrank Filz * also, that if delayed sack is enabled and this 551752ccb8e9SFrank Filz * value is set to 0, no change is made to the last 551852ccb8e9SFrank Filz * recorded delayed sack timer value. 551952ccb8e9SFrank Filz * 552052ccb8e9SFrank Filz * spp_flags - These flags are used to control various features 552152ccb8e9SFrank Filz * on an association. The flag field may contain 552252ccb8e9SFrank Filz * zero or more of the following options. 552352ccb8e9SFrank Filz * 552452ccb8e9SFrank Filz * SPP_HB_ENABLE - Enable heartbeats on the 552552ccb8e9SFrank Filz * specified address. Note that if the address 552652ccb8e9SFrank Filz * field is empty all addresses for the association 552752ccb8e9SFrank Filz * have heartbeats enabled upon them. 552852ccb8e9SFrank Filz * 552952ccb8e9SFrank Filz * SPP_HB_DISABLE - Disable heartbeats on the 553052ccb8e9SFrank Filz * speicifed address. Note that if the address 553152ccb8e9SFrank Filz * field is empty all addresses for the association 553252ccb8e9SFrank Filz * will have their heartbeats disabled. Note also 553352ccb8e9SFrank Filz * that SPP_HB_ENABLE and SPP_HB_DISABLE are 553452ccb8e9SFrank Filz * mutually exclusive, only one of these two should 553552ccb8e9SFrank Filz * be specified. Enabling both fields will have 553652ccb8e9SFrank Filz * undetermined results. 553752ccb8e9SFrank Filz * 553852ccb8e9SFrank Filz * SPP_HB_DEMAND - Request a user initiated heartbeat 553952ccb8e9SFrank Filz * to be made immediately. 554052ccb8e9SFrank Filz * 554152ccb8e9SFrank Filz * SPP_PMTUD_ENABLE - This field will enable PMTU 554252ccb8e9SFrank Filz * discovery upon the specified address. Note that 554352ccb8e9SFrank Filz * if the address feild is empty then all addresses 554452ccb8e9SFrank Filz * on the association are effected. 554552ccb8e9SFrank Filz * 554652ccb8e9SFrank Filz * SPP_PMTUD_DISABLE - This field will disable PMTU 554752ccb8e9SFrank Filz * discovery upon the specified address. Note that 554852ccb8e9SFrank Filz * if the address feild is empty then all addresses 554952ccb8e9SFrank Filz * on the association are effected. Not also that 555052ccb8e9SFrank Filz * SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually 555152ccb8e9SFrank Filz * exclusive. Enabling both will have undetermined 555252ccb8e9SFrank Filz * results. 555352ccb8e9SFrank Filz * 555452ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE - Setting this flag turns 555552ccb8e9SFrank Filz * on delayed sack. The time specified in spp_sackdelay 555652ccb8e9SFrank Filz * is used to specify the sack delay for this address. Note 555752ccb8e9SFrank Filz * that if spp_address is empty then all addresses will 555852ccb8e9SFrank Filz * enable delayed sack and take on the sack delay 555952ccb8e9SFrank Filz * value specified in spp_sackdelay. 556052ccb8e9SFrank Filz * SPP_SACKDELAY_DISABLE - Setting this flag turns 556152ccb8e9SFrank Filz * off delayed sack. If the spp_address field is blank then 556252ccb8e9SFrank Filz * delayed sack is disabled for the entire association. Note 556352ccb8e9SFrank Filz * also that this field is mutually exclusive to 556452ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE, setting both will have undefined 556552ccb8e9SFrank Filz * results. 55660b0dce7aSXin Long * 55670b0dce7aSXin Long * SPP_IPV6_FLOWLABEL: Setting this flag enables the 55680b0dce7aSXin Long * setting of the IPV6 flow label value. The value is 55690b0dce7aSXin Long * contained in the spp_ipv6_flowlabel field. 55700b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 55710b0dce7aSXin Long * the spp_ipv6_flowlabel field has a valid value returned. 55720b0dce7aSXin Long * If a specific destination address is set (in the 55730b0dce7aSXin Long * spp_address field), then the value returned is that of 55740b0dce7aSXin Long * the address. If just an association is specified (and 55750b0dce7aSXin Long * no address), then the association's default flow label 55760b0dce7aSXin Long * is returned. If neither an association nor a destination 55770b0dce7aSXin Long * is specified, then the socket's default flow label is 55780b0dce7aSXin Long * returned. For non-IPv6 sockets, this flag will be left 55790b0dce7aSXin Long * cleared. 55800b0dce7aSXin Long * 55810b0dce7aSXin Long * SPP_DSCP: Setting this flag enables the setting of the 55820b0dce7aSXin Long * Differentiated Services Code Point (DSCP) value 55830b0dce7aSXin Long * associated with either the association or a specific 55840b0dce7aSXin Long * address. The value is obtained in the spp_dscp field. 55850b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 55860b0dce7aSXin Long * the spp_dscp field has a valid value returned. If a 55870b0dce7aSXin Long * specific destination address is set when called (in the 55880b0dce7aSXin Long * spp_address field), then that specific destination 55890b0dce7aSXin Long * address's DSCP value is returned. If just an association 55900b0dce7aSXin Long * is specified, then the association's default DSCP is 55910b0dce7aSXin Long * returned. If neither an association nor a destination is 55920b0dce7aSXin Long * specified, then the socket's default DSCP is returned. 55930b0dce7aSXin Long * 55940b0dce7aSXin Long * spp_ipv6_flowlabel 55950b0dce7aSXin Long * - This field is used in conjunction with the 55960b0dce7aSXin Long * SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label. 55970b0dce7aSXin Long * The 20 least significant bits are used for the flow 55980b0dce7aSXin Long * label. This setting has precedence over any IPv6-layer 55990b0dce7aSXin Long * setting. 56000b0dce7aSXin Long * 56010b0dce7aSXin Long * spp_dscp - This field is used in conjunction with the SPP_DSCP flag 56020b0dce7aSXin Long * and contains the DSCP. The 6 most significant bits are 56030b0dce7aSXin Long * used for the DSCP. This setting has precedence over any 56040b0dce7aSXin Long * IPv4- or IPv6- layer setting. 56051da177e4SLinus Torvalds */ 56061da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, 56071da177e4SLinus Torvalds char __user *optval, int __user *optlen) 56081da177e4SLinus Torvalds { 56091da177e4SLinus Torvalds struct sctp_paddrparams params; 561052ccb8e9SFrank Filz struct sctp_transport *trans = NULL; 561152ccb8e9SFrank Filz struct sctp_association *asoc = NULL; 561252ccb8e9SFrank Filz struct sctp_sock *sp = sctp_sk(sk); 56131da177e4SLinus Torvalds 56140b0dce7aSXin Long if (len >= sizeof(params)) 56150b0dce7aSXin Long len = sizeof(params); 56160b0dce7aSXin Long else if (len >= ALIGN(offsetof(struct sctp_paddrparams, 56170b0dce7aSXin Long spp_ipv6_flowlabel), 4)) 56180b0dce7aSXin Long len = ALIGN(offsetof(struct sctp_paddrparams, 56190b0dce7aSXin Long spp_ipv6_flowlabel), 4); 56200b0dce7aSXin Long else 56211da177e4SLinus Torvalds return -EINVAL; 56220b0dce7aSXin Long 56231da177e4SLinus Torvalds if (copy_from_user(¶ms, optval, len)) 56241da177e4SLinus Torvalds return -EFAULT; 56251da177e4SLinus Torvalds 562652ccb8e9SFrank Filz /* If an address other than INADDR_ANY is specified, and 562752ccb8e9SFrank Filz * no transport is found, then the request is invalid. 56281da177e4SLinus Torvalds */ 562952cae8f0SVlad Yasevich if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { 56301da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, ¶ms.spp_address, 56311da177e4SLinus Torvalds params.spp_assoc_id); 563252ccb8e9SFrank Filz if (!trans) { 5633bb33381dSDaniel Borkmann pr_debug("%s: failed no transport\n", __func__); 56341da177e4SLinus Torvalds return -EINVAL; 563552ccb8e9SFrank Filz } 563652ccb8e9SFrank Filz } 56371da177e4SLinus Torvalds 563852ccb8e9SFrank Filz /* Get association, if assoc_id != 0 and the socket is a one 563952ccb8e9SFrank Filz * to many style socket, and an association was not found, then 564052ccb8e9SFrank Filz * the id was invalid. 56411da177e4SLinus Torvalds */ 564252ccb8e9SFrank Filz asoc = sctp_id2assoc(sk, params.spp_assoc_id); 564352ccb8e9SFrank Filz if (!asoc && params.spp_assoc_id && sctp_style(sk, UDP)) { 5644bb33381dSDaniel Borkmann pr_debug("%s: failed no association\n", __func__); 564552ccb8e9SFrank Filz return -EINVAL; 564652ccb8e9SFrank Filz } 56471da177e4SLinus Torvalds 564852ccb8e9SFrank Filz if (trans) { 564952ccb8e9SFrank Filz /* Fetch transport values. */ 565052ccb8e9SFrank Filz params.spp_hbinterval = jiffies_to_msecs(trans->hbinterval); 565152ccb8e9SFrank Filz params.spp_pathmtu = trans->pathmtu; 565252ccb8e9SFrank Filz params.spp_pathmaxrxt = trans->pathmaxrxt; 565352ccb8e9SFrank Filz params.spp_sackdelay = jiffies_to_msecs(trans->sackdelay); 56541da177e4SLinus Torvalds 565552ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 565652ccb8e9SFrank Filz params.spp_flags = trans->param_flags; 56570b0dce7aSXin Long if (trans->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 56580b0dce7aSXin Long params.spp_ipv6_flowlabel = trans->flowlabel & 56590b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 56600b0dce7aSXin Long params.spp_flags |= SPP_IPV6_FLOWLABEL; 56610b0dce7aSXin Long } 56620b0dce7aSXin Long if (trans->dscp & SCTP_DSCP_SET_MASK) { 56630b0dce7aSXin Long params.spp_dscp = trans->dscp & SCTP_DSCP_VAL_MASK; 56640b0dce7aSXin Long params.spp_flags |= SPP_DSCP; 56650b0dce7aSXin Long } 566652ccb8e9SFrank Filz } else if (asoc) { 566752ccb8e9SFrank Filz /* Fetch association values. */ 566852ccb8e9SFrank Filz params.spp_hbinterval = jiffies_to_msecs(asoc->hbinterval); 566952ccb8e9SFrank Filz params.spp_pathmtu = asoc->pathmtu; 567052ccb8e9SFrank Filz params.spp_pathmaxrxt = asoc->pathmaxrxt; 567152ccb8e9SFrank Filz params.spp_sackdelay = jiffies_to_msecs(asoc->sackdelay); 567252ccb8e9SFrank Filz 567352ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 567452ccb8e9SFrank Filz params.spp_flags = asoc->param_flags; 56750b0dce7aSXin Long if (asoc->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 56760b0dce7aSXin Long params.spp_ipv6_flowlabel = asoc->flowlabel & 56770b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 56780b0dce7aSXin Long params.spp_flags |= SPP_IPV6_FLOWLABEL; 56790b0dce7aSXin Long } 56800b0dce7aSXin Long if (asoc->dscp & SCTP_DSCP_SET_MASK) { 56810b0dce7aSXin Long params.spp_dscp = asoc->dscp & SCTP_DSCP_VAL_MASK; 56820b0dce7aSXin Long params.spp_flags |= SPP_DSCP; 56830b0dce7aSXin Long } 568452ccb8e9SFrank Filz } else { 568552ccb8e9SFrank Filz /* Fetch socket values. */ 568652ccb8e9SFrank Filz params.spp_hbinterval = sp->hbinterval; 568752ccb8e9SFrank Filz params.spp_pathmtu = sp->pathmtu; 568852ccb8e9SFrank Filz params.spp_sackdelay = sp->sackdelay; 568952ccb8e9SFrank Filz params.spp_pathmaxrxt = sp->pathmaxrxt; 569052ccb8e9SFrank Filz 569152ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 569252ccb8e9SFrank Filz params.spp_flags = sp->param_flags; 56930b0dce7aSXin Long if (sp->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 56940b0dce7aSXin Long params.spp_ipv6_flowlabel = sp->flowlabel & 56950b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 56960b0dce7aSXin Long params.spp_flags |= SPP_IPV6_FLOWLABEL; 56970b0dce7aSXin Long } 56980b0dce7aSXin Long if (sp->dscp & SCTP_DSCP_SET_MASK) { 56990b0dce7aSXin Long params.spp_dscp = sp->dscp & SCTP_DSCP_VAL_MASK; 57000b0dce7aSXin Long params.spp_flags |= SPP_DSCP; 57010b0dce7aSXin Long } 570252ccb8e9SFrank Filz } 570352ccb8e9SFrank Filz 57041da177e4SLinus Torvalds if (copy_to_user(optval, ¶ms, len)) 57051da177e4SLinus Torvalds return -EFAULT; 57061da177e4SLinus Torvalds 57071da177e4SLinus Torvalds if (put_user(len, optlen)) 57081da177e4SLinus Torvalds return -EFAULT; 57091da177e4SLinus Torvalds 57101da177e4SLinus Torvalds return 0; 57111da177e4SLinus Torvalds } 57121da177e4SLinus Torvalds 5713d364d927SWei Yongjun /* 5714d364d927SWei Yongjun * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 57157708610bSFrank Filz * 5716d364d927SWei Yongjun * This option will effect the way delayed acks are performed. This 5717d364d927SWei Yongjun * option allows you to get or set the delayed ack time, in 5718d364d927SWei Yongjun * milliseconds. It also allows changing the delayed ack frequency. 5719d364d927SWei Yongjun * Changing the frequency to 1 disables the delayed sack algorithm. If 5720d364d927SWei Yongjun * the assoc_id is 0, then this sets or gets the endpoints default 5721d364d927SWei Yongjun * values. If the assoc_id field is non-zero, then the set or get 5722d364d927SWei Yongjun * effects the specified association for the one to many model (the 5723d364d927SWei Yongjun * assoc_id field is ignored by the one to one model). Note that if 5724d364d927SWei Yongjun * sack_delay or sack_freq are 0 when setting this option, then the 5725d364d927SWei Yongjun * current values will remain unchanged. 57267708610bSFrank Filz * 5727d364d927SWei Yongjun * struct sctp_sack_info { 5728d364d927SWei Yongjun * sctp_assoc_t sack_assoc_id; 5729d364d927SWei Yongjun * uint32_t sack_delay; 5730d364d927SWei Yongjun * uint32_t sack_freq; 57317708610bSFrank Filz * }; 57327708610bSFrank Filz * 5733d364d927SWei Yongjun * sack_assoc_id - This parameter, indicates which association the user 5734d364d927SWei Yongjun * is performing an action upon. Note that if this field's value is 5735d364d927SWei Yongjun * zero then the endpoints default value is changed (effecting future 57367708610bSFrank Filz * associations only). 57377708610bSFrank Filz * 5738d364d927SWei Yongjun * sack_delay - This parameter contains the number of milliseconds that 5739d364d927SWei Yongjun * the user is requesting the delayed ACK timer be set to. Note that 5740d364d927SWei Yongjun * this value is defined in the standard to be between 200 and 500 5741d364d927SWei Yongjun * milliseconds. 57427708610bSFrank Filz * 5743d364d927SWei Yongjun * sack_freq - This parameter contains the number of packets that must 5744d364d927SWei Yongjun * be received before a sack is sent without waiting for the delay 5745d364d927SWei Yongjun * timer to expire. The default value for this is 2, setting this 5746d364d927SWei Yongjun * value to 1 will disable the delayed sack algorithm. 57477708610bSFrank Filz */ 5748d364d927SWei Yongjun static int sctp_getsockopt_delayed_ack(struct sock *sk, int len, 57497708610bSFrank Filz char __user *optval, 57507708610bSFrank Filz int __user *optlen) 57517708610bSFrank Filz { 5752d364d927SWei Yongjun struct sctp_sack_info params; 57537708610bSFrank Filz struct sctp_association *asoc = NULL; 57547708610bSFrank Filz struct sctp_sock *sp = sctp_sk(sk); 57557708610bSFrank Filz 5756d364d927SWei Yongjun if (len >= sizeof(struct sctp_sack_info)) { 5757d364d927SWei Yongjun len = sizeof(struct sctp_sack_info); 5758408f22e8SNeil Horman 57597708610bSFrank Filz if (copy_from_user(¶ms, optval, len)) 57607708610bSFrank Filz return -EFAULT; 5761d364d927SWei Yongjun } else if (len == sizeof(struct sctp_assoc_value)) { 576294f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 5763f916ec96SNeil Horman "%s (pid %d) " 576494f65193SNeil Horman "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 5765f916ec96SNeil Horman "Use struct sctp_sack_info instead\n", 5766f916ec96SNeil Horman current->comm, task_pid_nr(current)); 5767d364d927SWei Yongjun if (copy_from_user(¶ms, optval, len)) 5768d364d927SWei Yongjun return -EFAULT; 5769d364d927SWei Yongjun } else 5770d364d927SWei Yongjun return -EINVAL; 57717708610bSFrank Filz 5772d364d927SWei Yongjun /* Get association, if sack_assoc_id != 0 and the socket is a one 57737708610bSFrank Filz * to many style socket, and an association was not found, then 57747708610bSFrank Filz * the id was invalid. 57757708610bSFrank Filz */ 5776d364d927SWei Yongjun asoc = sctp_id2assoc(sk, params.sack_assoc_id); 5777d364d927SWei Yongjun if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP)) 57787708610bSFrank Filz return -EINVAL; 57797708610bSFrank Filz 57807708610bSFrank Filz if (asoc) { 57817708610bSFrank Filz /* Fetch association values. */ 5782d364d927SWei Yongjun if (asoc->param_flags & SPP_SACKDELAY_ENABLE) { 5783d364d927SWei Yongjun params.sack_delay = jiffies_to_msecs( 57847708610bSFrank Filz asoc->sackdelay); 5785d364d927SWei Yongjun params.sack_freq = asoc->sackfreq; 5786d364d927SWei Yongjun 5787d364d927SWei Yongjun } else { 5788d364d927SWei Yongjun params.sack_delay = 0; 5789d364d927SWei Yongjun params.sack_freq = 1; 5790d364d927SWei Yongjun } 57917708610bSFrank Filz } else { 57927708610bSFrank Filz /* Fetch socket values. */ 5793d364d927SWei Yongjun if (sp->param_flags & SPP_SACKDELAY_ENABLE) { 5794d364d927SWei Yongjun params.sack_delay = sp->sackdelay; 5795d364d927SWei Yongjun params.sack_freq = sp->sackfreq; 5796d364d927SWei Yongjun } else { 5797d364d927SWei Yongjun params.sack_delay = 0; 5798d364d927SWei Yongjun params.sack_freq = 1; 5799d364d927SWei Yongjun } 58007708610bSFrank Filz } 58017708610bSFrank Filz 58027708610bSFrank Filz if (copy_to_user(optval, ¶ms, len)) 58037708610bSFrank Filz return -EFAULT; 58047708610bSFrank Filz 58057708610bSFrank Filz if (put_user(len, optlen)) 58067708610bSFrank Filz return -EFAULT; 58077708610bSFrank Filz 58087708610bSFrank Filz return 0; 58097708610bSFrank Filz } 58107708610bSFrank Filz 58111da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG) 58121da177e4SLinus Torvalds * 58131da177e4SLinus Torvalds * Applications can specify protocol parameters for the default association 58141da177e4SLinus Torvalds * initialization. The option name argument to setsockopt() and getsockopt() 58151da177e4SLinus Torvalds * is SCTP_INITMSG. 58161da177e4SLinus Torvalds * 58171da177e4SLinus Torvalds * Setting initialization parameters is effective only on an unconnected 58181da177e4SLinus Torvalds * socket (for UDP-style sockets only future associations are effected 58191da177e4SLinus Torvalds * by the change). With TCP-style sockets, this option is inherited by 58201da177e4SLinus Torvalds * sockets derived from a listener socket. 58211da177e4SLinus Torvalds */ 58221da177e4SLinus Torvalds static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen) 58231da177e4SLinus Torvalds { 5824408f22e8SNeil Horman if (len < sizeof(struct sctp_initmsg)) 58251da177e4SLinus Torvalds return -EINVAL; 5826408f22e8SNeil Horman len = sizeof(struct sctp_initmsg); 5827408f22e8SNeil Horman if (put_user(len, optlen)) 5828408f22e8SNeil Horman return -EFAULT; 58291da177e4SLinus Torvalds if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len)) 58301da177e4SLinus Torvalds return -EFAULT; 58311da177e4SLinus Torvalds return 0; 58321da177e4SLinus Torvalds } 58331da177e4SLinus Torvalds 58341da177e4SLinus Torvalds 58355fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, 58365fe467eeSIvan Skytte Jørgensen char __user *optval, int __user *optlen) 58375fe467eeSIvan Skytte Jørgensen { 58385fe467eeSIvan Skytte Jørgensen struct sctp_association *asoc; 58395fe467eeSIvan Skytte Jørgensen int cnt = 0; 58405fe467eeSIvan Skytte Jørgensen struct sctp_getaddrs getaddrs; 58415fe467eeSIvan Skytte Jørgensen struct sctp_transport *from; 58425fe467eeSIvan Skytte Jørgensen void __user *to; 58435fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 58445fe467eeSIvan Skytte Jørgensen struct sctp_sock *sp = sctp_sk(sk); 58455fe467eeSIvan Skytte Jørgensen int addrlen; 58465fe467eeSIvan Skytte Jørgensen size_t space_left; 58475fe467eeSIvan Skytte Jørgensen int bytes_copied; 58485fe467eeSIvan Skytte Jørgensen 58495fe467eeSIvan Skytte Jørgensen if (len < sizeof(struct sctp_getaddrs)) 58505fe467eeSIvan Skytte Jørgensen return -EINVAL; 58515fe467eeSIvan Skytte Jørgensen 58525fe467eeSIvan Skytte Jørgensen if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 58535fe467eeSIvan Skytte Jørgensen return -EFAULT; 58545fe467eeSIvan Skytte Jørgensen 58555fe467eeSIvan Skytte Jørgensen /* For UDP-style sockets, id specifies the association to query. */ 58565fe467eeSIvan Skytte Jørgensen asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 58575fe467eeSIvan Skytte Jørgensen if (!asoc) 58585fe467eeSIvan Skytte Jørgensen return -EINVAL; 58595fe467eeSIvan Skytte Jørgensen 58605fe467eeSIvan Skytte Jørgensen to = optval + offsetof(struct sctp_getaddrs, addrs); 5861186e2343SNeil Horman space_left = len - offsetof(struct sctp_getaddrs, addrs); 58625fe467eeSIvan Skytte Jørgensen 58639dbc15f0SRobert P. J. Day list_for_each_entry(from, &asoc->peer.transport_addr_list, 58649dbc15f0SRobert P. J. Day transports) { 5865b3f5b3b6SAl Viro memcpy(&temp, &from->ipaddr, sizeof(temp)); 5866299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 5867299ee123SJason Gunthorpe ->addr_to_user(sp, &temp); 58685fe467eeSIvan Skytte Jørgensen if (space_left < addrlen) 58695fe467eeSIvan Skytte Jørgensen return -ENOMEM; 58705fe467eeSIvan Skytte Jørgensen if (copy_to_user(to, &temp, addrlen)) 58715fe467eeSIvan Skytte Jørgensen return -EFAULT; 58725fe467eeSIvan Skytte Jørgensen to += addrlen; 58735fe467eeSIvan Skytte Jørgensen cnt++; 58745fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 58755fe467eeSIvan Skytte Jørgensen } 58765fe467eeSIvan Skytte Jørgensen 58775fe467eeSIvan Skytte Jørgensen if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) 58785fe467eeSIvan Skytte Jørgensen return -EFAULT; 58795fe467eeSIvan Skytte Jørgensen bytes_copied = ((char __user *)to) - optval; 58805fe467eeSIvan Skytte Jørgensen if (put_user(bytes_copied, optlen)) 58815fe467eeSIvan Skytte Jørgensen return -EFAULT; 58825fe467eeSIvan Skytte Jørgensen 58835fe467eeSIvan Skytte Jørgensen return 0; 58845fe467eeSIvan Skytte Jørgensen } 58855fe467eeSIvan Skytte Jørgensen 5886aad97f38SVlad Yasevich static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, 5887aad97f38SVlad Yasevich size_t space_left, int *bytes_copied) 58885fe467eeSIvan Skytte Jørgensen { 58895fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry *addr; 58905fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 58915fe467eeSIvan Skytte Jørgensen int cnt = 0; 58925fe467eeSIvan Skytte Jørgensen int addrlen; 58934db67e80SEric W. Biederman struct net *net = sock_net(sk); 58945fe467eeSIvan Skytte Jørgensen 589529303547SVlad Yasevich rcu_read_lock(); 58964db67e80SEric W. Biederman list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) { 589729303547SVlad Yasevich if (!addr->valid) 589829303547SVlad Yasevich continue; 589929303547SVlad Yasevich 59005fe467eeSIvan Skytte Jørgensen if ((PF_INET == sk->sk_family) && 59016244be4eSAl Viro (AF_INET6 == addr->a.sa.sa_family)) 59025fe467eeSIvan Skytte Jørgensen continue; 59037dab83deSVlad Yasevich if ((PF_INET6 == sk->sk_family) && 59047dab83deSVlad Yasevich inet_v6_ipv6only(sk) && 59057dab83deSVlad Yasevich (AF_INET == addr->a.sa.sa_family)) 59067dab83deSVlad Yasevich continue; 59076244be4eSAl Viro memcpy(&temp, &addr->a, sizeof(temp)); 5908b46ae36dSVlad Yasevich if (!temp.v4.sin_port) 5909b46ae36dSVlad Yasevich temp.v4.sin_port = htons(port); 5910b46ae36dSVlad Yasevich 5911299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 5912299ee123SJason Gunthorpe ->addr_to_user(sctp_sk(sk), &temp); 5913299ee123SJason Gunthorpe 591429303547SVlad Yasevich if (space_left < addrlen) { 591529303547SVlad Yasevich cnt = -ENOMEM; 591629303547SVlad Yasevich break; 591729303547SVlad Yasevich } 5918aad97f38SVlad Yasevich memcpy(to, &temp, addrlen); 591929c7cf96SSridhar Samudrala 5920aad97f38SVlad Yasevich to += addrlen; 59215fe467eeSIvan Skytte Jørgensen cnt++; 59225fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 59233663c306SVlad Yasevich *bytes_copied += addrlen; 59245fe467eeSIvan Skytte Jørgensen } 592529303547SVlad Yasevich rcu_read_unlock(); 59265fe467eeSIvan Skytte Jørgensen 59275fe467eeSIvan Skytte Jørgensen return cnt; 59285fe467eeSIvan Skytte Jørgensen } 59295fe467eeSIvan Skytte Jørgensen 59301da177e4SLinus Torvalds 59315fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_local_addrs(struct sock *sk, int len, 59325fe467eeSIvan Skytte Jørgensen char __user *optval, int __user *optlen) 59335fe467eeSIvan Skytte Jørgensen { 59345fe467eeSIvan Skytte Jørgensen struct sctp_bind_addr *bp; 59355fe467eeSIvan Skytte Jørgensen struct sctp_association *asoc; 59365fe467eeSIvan Skytte Jørgensen int cnt = 0; 59375fe467eeSIvan Skytte Jørgensen struct sctp_getaddrs getaddrs; 59385fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry *addr; 59395fe467eeSIvan Skytte Jørgensen void __user *to; 59405fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 59415fe467eeSIvan Skytte Jørgensen struct sctp_sock *sp = sctp_sk(sk); 59425fe467eeSIvan Skytte Jørgensen int addrlen; 59435fe467eeSIvan Skytte Jørgensen int err = 0; 59445fe467eeSIvan Skytte Jørgensen size_t space_left; 5945aad97f38SVlad Yasevich int bytes_copied = 0; 5946aad97f38SVlad Yasevich void *addrs; 594770b57b81SVlad Yasevich void *buf; 59485fe467eeSIvan Skytte Jørgensen 5949408f22e8SNeil Horman if (len < sizeof(struct sctp_getaddrs)) 59505fe467eeSIvan Skytte Jørgensen return -EINVAL; 59515fe467eeSIvan Skytte Jørgensen 59525fe467eeSIvan Skytte Jørgensen if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 59535fe467eeSIvan Skytte Jørgensen return -EFAULT; 59545fe467eeSIvan Skytte Jørgensen 59555fe467eeSIvan Skytte Jørgensen /* 59565fe467eeSIvan Skytte Jørgensen * For UDP-style sockets, id specifies the association to query. 59575fe467eeSIvan Skytte Jørgensen * If the id field is set to the value '0' then the locally bound 59585fe467eeSIvan Skytte Jørgensen * addresses are returned without regard to any particular 59595fe467eeSIvan Skytte Jørgensen * association. 59605fe467eeSIvan Skytte Jørgensen */ 59615fe467eeSIvan Skytte Jørgensen if (0 == getaddrs.assoc_id) { 59625fe467eeSIvan Skytte Jørgensen bp = &sctp_sk(sk)->ep->base.bind_addr; 59635fe467eeSIvan Skytte Jørgensen } else { 59645fe467eeSIvan Skytte Jørgensen asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 59655fe467eeSIvan Skytte Jørgensen if (!asoc) 59665fe467eeSIvan Skytte Jørgensen return -EINVAL; 59675fe467eeSIvan Skytte Jørgensen bp = &asoc->base.bind_addr; 59685fe467eeSIvan Skytte Jørgensen } 59695fe467eeSIvan Skytte Jørgensen 59705fe467eeSIvan Skytte Jørgensen to = optval + offsetof(struct sctp_getaddrs, addrs); 5971186e2343SNeil Horman space_left = len - offsetof(struct sctp_getaddrs, addrs); 5972186e2343SNeil Horman 5973cacc0621SMarcelo Ricardo Leitner addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN); 5974aad97f38SVlad Yasevich if (!addrs) 5975aad97f38SVlad Yasevich return -ENOMEM; 59765fe467eeSIvan Skytte Jørgensen 59775fe467eeSIvan Skytte Jørgensen /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid 59785fe467eeSIvan Skytte Jørgensen * addresses from the global local address list. 59795fe467eeSIvan Skytte Jørgensen */ 59805fe467eeSIvan Skytte Jørgensen if (sctp_list_single_entry(&bp->address_list)) { 59815fe467eeSIvan Skytte Jørgensen addr = list_entry(bp->address_list.next, 59825fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry, list); 598352cae8f0SVlad Yasevich if (sctp_is_any(sk, &addr->a)) { 5984aad97f38SVlad Yasevich cnt = sctp_copy_laddrs(sk, bp->port, addrs, 5985aad97f38SVlad Yasevich space_left, &bytes_copied); 59865fe467eeSIvan Skytte Jørgensen if (cnt < 0) { 59875fe467eeSIvan Skytte Jørgensen err = cnt; 5988559cf710SVlad Yasevich goto out; 59895fe467eeSIvan Skytte Jørgensen } 59905fe467eeSIvan Skytte Jørgensen goto copy_getaddrs; 59915fe467eeSIvan Skytte Jørgensen } 59925fe467eeSIvan Skytte Jørgensen } 59935fe467eeSIvan Skytte Jørgensen 599470b57b81SVlad Yasevich buf = addrs; 5995559cf710SVlad Yasevich /* Protection on the bound address list is not needed since 5996559cf710SVlad Yasevich * in the socket option context we hold a socket lock and 5997559cf710SVlad Yasevich * thus the bound address list can't change. 5998559cf710SVlad Yasevich */ 5999559cf710SVlad Yasevich list_for_each_entry(addr, &bp->address_list, list) { 60006244be4eSAl Viro memcpy(&temp, &addr->a, sizeof(temp)); 6001299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 6002299ee123SJason Gunthorpe ->addr_to_user(sp, &temp); 6003aad97f38SVlad Yasevich if (space_left < addrlen) { 6004aad97f38SVlad Yasevich err = -ENOMEM; /*fixme: right error?*/ 6005559cf710SVlad Yasevich goto out; 60065fe467eeSIvan Skytte Jørgensen } 600770b57b81SVlad Yasevich memcpy(buf, &temp, addrlen); 600870b57b81SVlad Yasevich buf += addrlen; 6009aad97f38SVlad Yasevich bytes_copied += addrlen; 60105fe467eeSIvan Skytte Jørgensen cnt++; 60115fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 60125fe467eeSIvan Skytte Jørgensen } 60135fe467eeSIvan Skytte Jørgensen 60145fe467eeSIvan Skytte Jørgensen copy_getaddrs: 6015aad97f38SVlad Yasevich if (copy_to_user(to, addrs, bytes_copied)) { 6016aad97f38SVlad Yasevich err = -EFAULT; 6017d6f9fdafSSebastian Siewior goto out; 6018aad97f38SVlad Yasevich } 6019fe979ac1SVlad Yasevich if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) { 6020fe979ac1SVlad Yasevich err = -EFAULT; 6021d6f9fdafSSebastian Siewior goto out; 6022fe979ac1SVlad Yasevich } 6023c76f97c9SMarcelo Ricardo Leitner /* XXX: We should have accounted for sizeof(struct sctp_getaddrs) too, 6024c76f97c9SMarcelo Ricardo Leitner * but we can't change it anymore. 6025c76f97c9SMarcelo Ricardo Leitner */ 60265fe467eeSIvan Skytte Jørgensen if (put_user(bytes_copied, optlen)) 6027fe979ac1SVlad Yasevich err = -EFAULT; 6028d6f9fdafSSebastian Siewior out: 6029aad97f38SVlad Yasevich kfree(addrs); 60305fe467eeSIvan Skytte Jørgensen return err; 60315fe467eeSIvan Skytte Jørgensen } 60325fe467eeSIvan Skytte Jørgensen 60331da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 60341da177e4SLinus Torvalds * 60351da177e4SLinus Torvalds * Requests that the local SCTP stack use the enclosed peer address as 60361da177e4SLinus Torvalds * the association primary. The enclosed address must be one of the 60371da177e4SLinus Torvalds * association peer's addresses. 60381da177e4SLinus Torvalds */ 60391da177e4SLinus Torvalds static int sctp_getsockopt_primary_addr(struct sock *sk, int len, 60401da177e4SLinus Torvalds char __user *optval, int __user *optlen) 60411da177e4SLinus Torvalds { 60421da177e4SLinus Torvalds struct sctp_prim prim; 60431da177e4SLinus Torvalds struct sctp_association *asoc; 60441da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 60451da177e4SLinus Torvalds 6046408f22e8SNeil Horman if (len < sizeof(struct sctp_prim)) 60471da177e4SLinus Torvalds return -EINVAL; 60481da177e4SLinus Torvalds 6049408f22e8SNeil Horman len = sizeof(struct sctp_prim); 6050408f22e8SNeil Horman 6051408f22e8SNeil Horman if (copy_from_user(&prim, optval, len)) 60521da177e4SLinus Torvalds return -EFAULT; 60531da177e4SLinus Torvalds 60541da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); 60551da177e4SLinus Torvalds if (!asoc) 60561da177e4SLinus Torvalds return -EINVAL; 60571da177e4SLinus Torvalds 60581da177e4SLinus Torvalds if (!asoc->peer.primary_path) 60591da177e4SLinus Torvalds return -ENOTCONN; 60601da177e4SLinus Torvalds 60618cec6b80SAl Viro memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, 60628cec6b80SAl Viro asoc->peer.primary_path->af_specific->sockaddr_len); 60631da177e4SLinus Torvalds 6064299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp, 60651da177e4SLinus Torvalds (union sctp_addr *)&prim.ssp_addr); 60661da177e4SLinus Torvalds 6067408f22e8SNeil Horman if (put_user(len, optlen)) 6068408f22e8SNeil Horman return -EFAULT; 6069408f22e8SNeil Horman if (copy_to_user(optval, &prim, len)) 60701da177e4SLinus Torvalds return -EFAULT; 60711da177e4SLinus Torvalds 60721da177e4SLinus Torvalds return 0; 60731da177e4SLinus Torvalds } 60741da177e4SLinus Torvalds 60751da177e4SLinus Torvalds /* 60760f3fffd8SIvan Skytte Jorgensen * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) 60771da177e4SLinus Torvalds * 60780f3fffd8SIvan Skytte Jorgensen * Requests that the local endpoint set the specified Adaptation Layer 60791da177e4SLinus Torvalds * Indication parameter for all future INIT and INIT-ACK exchanges. 60801da177e4SLinus Torvalds */ 60810f3fffd8SIvan Skytte Jorgensen static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len, 60821da177e4SLinus Torvalds char __user *optval, int __user *optlen) 60831da177e4SLinus Torvalds { 60840f3fffd8SIvan Skytte Jorgensen struct sctp_setadaptation adaptation; 60851da177e4SLinus Torvalds 6086408f22e8SNeil Horman if (len < sizeof(struct sctp_setadaptation)) 60871da177e4SLinus Torvalds return -EINVAL; 60881da177e4SLinus Torvalds 6089408f22e8SNeil Horman len = sizeof(struct sctp_setadaptation); 6090408f22e8SNeil Horman 60910f3fffd8SIvan Skytte Jorgensen adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind; 6092408f22e8SNeil Horman 6093408f22e8SNeil Horman if (put_user(len, optlen)) 6094408f22e8SNeil Horman return -EFAULT; 60950f3fffd8SIvan Skytte Jorgensen if (copy_to_user(optval, &adaptation, len)) 60961da177e4SLinus Torvalds return -EFAULT; 6097a1ab3582SIvan Skytte Jorgensen 60981da177e4SLinus Torvalds return 0; 60991da177e4SLinus Torvalds } 61001da177e4SLinus Torvalds 61011da177e4SLinus Torvalds /* 61021da177e4SLinus Torvalds * 61031da177e4SLinus Torvalds * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 61041da177e4SLinus Torvalds * 61051da177e4SLinus Torvalds * Applications that wish to use the sendto() system call may wish to 61061da177e4SLinus Torvalds * specify a default set of parameters that would normally be supplied 61071da177e4SLinus Torvalds * through the inclusion of ancillary data. This socket option allows 61081da177e4SLinus Torvalds * such an application to set the default sctp_sndrcvinfo structure. 61091da177e4SLinus Torvalds 61101da177e4SLinus Torvalds 61111da177e4SLinus Torvalds * The application that wishes to use this socket option simply passes 61121da177e4SLinus Torvalds * in to this call the sctp_sndrcvinfo structure defined in Section 61131da177e4SLinus Torvalds * 5.2.2) The input parameters accepted by this call include 61141da177e4SLinus Torvalds * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 61151da177e4SLinus Torvalds * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 61161da177e4SLinus Torvalds * to this call if the caller is using the UDP model. 61171da177e4SLinus Torvalds * 61181da177e4SLinus Torvalds * For getsockopt, it get the default sctp_sndrcvinfo structure. 61191da177e4SLinus Torvalds */ 61201da177e4SLinus Torvalds static int sctp_getsockopt_default_send_param(struct sock *sk, 61211da177e4SLinus Torvalds int len, char __user *optval, 61221da177e4SLinus Torvalds int __user *optlen) 61231da177e4SLinus Torvalds { 61241da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 61256b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 61266b3fd5f3SGeir Ola Vaagland struct sctp_sndrcvinfo info; 61271da177e4SLinus Torvalds 61286b3fd5f3SGeir Ola Vaagland if (len < sizeof(info)) 61291da177e4SLinus Torvalds return -EINVAL; 6130408f22e8SNeil Horman 61316b3fd5f3SGeir Ola Vaagland len = sizeof(info); 6132408f22e8SNeil Horman 6133408f22e8SNeil Horman if (copy_from_user(&info, optval, len)) 61341da177e4SLinus Torvalds return -EFAULT; 61351da177e4SLinus Torvalds 61361da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); 61371da177e4SLinus Torvalds if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) 61381da177e4SLinus Torvalds return -EINVAL; 61391da177e4SLinus Torvalds if (asoc) { 61401da177e4SLinus Torvalds info.sinfo_stream = asoc->default_stream; 61411da177e4SLinus Torvalds info.sinfo_flags = asoc->default_flags; 61421da177e4SLinus Torvalds info.sinfo_ppid = asoc->default_ppid; 61431da177e4SLinus Torvalds info.sinfo_context = asoc->default_context; 61441da177e4SLinus Torvalds info.sinfo_timetolive = asoc->default_timetolive; 61451da177e4SLinus Torvalds } else { 61461da177e4SLinus Torvalds info.sinfo_stream = sp->default_stream; 61471da177e4SLinus Torvalds info.sinfo_flags = sp->default_flags; 61481da177e4SLinus Torvalds info.sinfo_ppid = sp->default_ppid; 61491da177e4SLinus Torvalds info.sinfo_context = sp->default_context; 61501da177e4SLinus Torvalds info.sinfo_timetolive = sp->default_timetolive; 61511da177e4SLinus Torvalds } 61521da177e4SLinus Torvalds 6153408f22e8SNeil Horman if (put_user(len, optlen)) 6154408f22e8SNeil Horman return -EFAULT; 6155408f22e8SNeil Horman if (copy_to_user(optval, &info, len)) 61561da177e4SLinus Torvalds return -EFAULT; 61571da177e4SLinus Torvalds 61581da177e4SLinus Torvalds return 0; 61591da177e4SLinus Torvalds } 61601da177e4SLinus Torvalds 61616b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters 61626b3fd5f3SGeir Ola Vaagland * (SCTP_DEFAULT_SNDINFO) 61636b3fd5f3SGeir Ola Vaagland */ 61646b3fd5f3SGeir Ola Vaagland static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len, 61656b3fd5f3SGeir Ola Vaagland char __user *optval, 61666b3fd5f3SGeir Ola Vaagland int __user *optlen) 61676b3fd5f3SGeir Ola Vaagland { 61686b3fd5f3SGeir Ola Vaagland struct sctp_sock *sp = sctp_sk(sk); 61696b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 61706b3fd5f3SGeir Ola Vaagland struct sctp_sndinfo info; 61716b3fd5f3SGeir Ola Vaagland 61726b3fd5f3SGeir Ola Vaagland if (len < sizeof(info)) 61736b3fd5f3SGeir Ola Vaagland return -EINVAL; 61746b3fd5f3SGeir Ola Vaagland 61756b3fd5f3SGeir Ola Vaagland len = sizeof(info); 61766b3fd5f3SGeir Ola Vaagland 61776b3fd5f3SGeir Ola Vaagland if (copy_from_user(&info, optval, len)) 61786b3fd5f3SGeir Ola Vaagland return -EFAULT; 61796b3fd5f3SGeir Ola Vaagland 61806b3fd5f3SGeir Ola Vaagland asoc = sctp_id2assoc(sk, info.snd_assoc_id); 61816b3fd5f3SGeir Ola Vaagland if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) 61826b3fd5f3SGeir Ola Vaagland return -EINVAL; 61836b3fd5f3SGeir Ola Vaagland if (asoc) { 61846b3fd5f3SGeir Ola Vaagland info.snd_sid = asoc->default_stream; 61856b3fd5f3SGeir Ola Vaagland info.snd_flags = asoc->default_flags; 61866b3fd5f3SGeir Ola Vaagland info.snd_ppid = asoc->default_ppid; 61876b3fd5f3SGeir Ola Vaagland info.snd_context = asoc->default_context; 61886b3fd5f3SGeir Ola Vaagland } else { 61896b3fd5f3SGeir Ola Vaagland info.snd_sid = sp->default_stream; 61906b3fd5f3SGeir Ola Vaagland info.snd_flags = sp->default_flags; 61916b3fd5f3SGeir Ola Vaagland info.snd_ppid = sp->default_ppid; 61926b3fd5f3SGeir Ola Vaagland info.snd_context = sp->default_context; 61936b3fd5f3SGeir Ola Vaagland } 61946b3fd5f3SGeir Ola Vaagland 61956b3fd5f3SGeir Ola Vaagland if (put_user(len, optlen)) 61966b3fd5f3SGeir Ola Vaagland return -EFAULT; 61976b3fd5f3SGeir Ola Vaagland if (copy_to_user(optval, &info, len)) 61986b3fd5f3SGeir Ola Vaagland return -EFAULT; 61996b3fd5f3SGeir Ola Vaagland 62006b3fd5f3SGeir Ola Vaagland return 0; 62016b3fd5f3SGeir Ola Vaagland } 62026b3fd5f3SGeir Ola Vaagland 62031da177e4SLinus Torvalds /* 62041da177e4SLinus Torvalds * 62051da177e4SLinus Torvalds * 7.1.5 SCTP_NODELAY 62061da177e4SLinus Torvalds * 62071da177e4SLinus Torvalds * Turn on/off any Nagle-like algorithm. This means that packets are 62081da177e4SLinus Torvalds * generally sent as soon as possible and no unnecessary delays are 62091da177e4SLinus Torvalds * introduced, at the cost of more packets in the network. Expects an 62101da177e4SLinus Torvalds * integer boolean flag. 62111da177e4SLinus Torvalds */ 62121da177e4SLinus Torvalds 62131da177e4SLinus Torvalds static int sctp_getsockopt_nodelay(struct sock *sk, int len, 62141da177e4SLinus Torvalds char __user *optval, int __user *optlen) 62151da177e4SLinus Torvalds { 62161da177e4SLinus Torvalds int val; 62171da177e4SLinus Torvalds 62181da177e4SLinus Torvalds if (len < sizeof(int)) 62191da177e4SLinus Torvalds return -EINVAL; 62201da177e4SLinus Torvalds 62211da177e4SLinus Torvalds len = sizeof(int); 62221da177e4SLinus Torvalds val = (sctp_sk(sk)->nodelay == 1); 62231da177e4SLinus Torvalds if (put_user(len, optlen)) 62241da177e4SLinus Torvalds return -EFAULT; 62251da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 62261da177e4SLinus Torvalds return -EFAULT; 62271da177e4SLinus Torvalds return 0; 62281da177e4SLinus Torvalds } 62291da177e4SLinus Torvalds 62301da177e4SLinus Torvalds /* 62311da177e4SLinus Torvalds * 62321da177e4SLinus Torvalds * 7.1.1 SCTP_RTOINFO 62331da177e4SLinus Torvalds * 62341da177e4SLinus Torvalds * The protocol parameters used to initialize and bound retransmission 62351da177e4SLinus Torvalds * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 62361da177e4SLinus Torvalds * and modify these parameters. 62371da177e4SLinus Torvalds * All parameters are time values, in milliseconds. A value of 0, when 62381da177e4SLinus Torvalds * modifying the parameters, indicates that the current value should not 62391da177e4SLinus Torvalds * be changed. 62401da177e4SLinus Torvalds * 62411da177e4SLinus Torvalds */ 62421da177e4SLinus Torvalds static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, 62431da177e4SLinus Torvalds char __user *optval, 62441da177e4SLinus Torvalds int __user *optlen) { 62451da177e4SLinus Torvalds struct sctp_rtoinfo rtoinfo; 62461da177e4SLinus Torvalds struct sctp_association *asoc; 62471da177e4SLinus Torvalds 6248408f22e8SNeil Horman if (len < sizeof (struct sctp_rtoinfo)) 62491da177e4SLinus Torvalds return -EINVAL; 62501da177e4SLinus Torvalds 6251408f22e8SNeil Horman len = sizeof(struct sctp_rtoinfo); 6252408f22e8SNeil Horman 6253408f22e8SNeil Horman if (copy_from_user(&rtoinfo, optval, len)) 62541da177e4SLinus Torvalds return -EFAULT; 62551da177e4SLinus Torvalds 62561da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); 62571da177e4SLinus Torvalds 62581da177e4SLinus Torvalds if (!asoc && rtoinfo.srto_assoc_id && sctp_style(sk, UDP)) 62591da177e4SLinus Torvalds return -EINVAL; 62601da177e4SLinus Torvalds 62611da177e4SLinus Torvalds /* Values corresponding to the specific association. */ 62621da177e4SLinus Torvalds if (asoc) { 62631da177e4SLinus Torvalds rtoinfo.srto_initial = jiffies_to_msecs(asoc->rto_initial); 62641da177e4SLinus Torvalds rtoinfo.srto_max = jiffies_to_msecs(asoc->rto_max); 62651da177e4SLinus Torvalds rtoinfo.srto_min = jiffies_to_msecs(asoc->rto_min); 62661da177e4SLinus Torvalds } else { 62671da177e4SLinus Torvalds /* Values corresponding to the endpoint. */ 62681da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 62691da177e4SLinus Torvalds 62701da177e4SLinus Torvalds rtoinfo.srto_initial = sp->rtoinfo.srto_initial; 62711da177e4SLinus Torvalds rtoinfo.srto_max = sp->rtoinfo.srto_max; 62721da177e4SLinus Torvalds rtoinfo.srto_min = sp->rtoinfo.srto_min; 62731da177e4SLinus Torvalds } 62741da177e4SLinus Torvalds 62751da177e4SLinus Torvalds if (put_user(len, optlen)) 62761da177e4SLinus Torvalds return -EFAULT; 62771da177e4SLinus Torvalds 62781da177e4SLinus Torvalds if (copy_to_user(optval, &rtoinfo, len)) 62791da177e4SLinus Torvalds return -EFAULT; 62801da177e4SLinus Torvalds 62811da177e4SLinus Torvalds return 0; 62821da177e4SLinus Torvalds } 62831da177e4SLinus Torvalds 62841da177e4SLinus Torvalds /* 62851da177e4SLinus Torvalds * 62861da177e4SLinus Torvalds * 7.1.2 SCTP_ASSOCINFO 62871da177e4SLinus Torvalds * 628859c51591SMichael Opdenacker * This option is used to tune the maximum retransmission attempts 62891da177e4SLinus Torvalds * of the association. 62901da177e4SLinus Torvalds * Returns an error if the new association retransmission value is 62911da177e4SLinus Torvalds * greater than the sum of the retransmission value of the peer. 62921da177e4SLinus Torvalds * See [SCTP] for more information. 62931da177e4SLinus Torvalds * 62941da177e4SLinus Torvalds */ 62951da177e4SLinus Torvalds static int sctp_getsockopt_associnfo(struct sock *sk, int len, 62961da177e4SLinus Torvalds char __user *optval, 62971da177e4SLinus Torvalds int __user *optlen) 62981da177e4SLinus Torvalds { 62991da177e4SLinus Torvalds 63001da177e4SLinus Torvalds struct sctp_assocparams assocparams; 63011da177e4SLinus Torvalds struct sctp_association *asoc; 63021da177e4SLinus Torvalds struct list_head *pos; 63031da177e4SLinus Torvalds int cnt = 0; 63041da177e4SLinus Torvalds 6305408f22e8SNeil Horman if (len < sizeof (struct sctp_assocparams)) 63061da177e4SLinus Torvalds return -EINVAL; 63071da177e4SLinus Torvalds 6308408f22e8SNeil Horman len = sizeof(struct sctp_assocparams); 6309408f22e8SNeil Horman 6310408f22e8SNeil Horman if (copy_from_user(&assocparams, optval, len)) 63111da177e4SLinus Torvalds return -EFAULT; 63121da177e4SLinus Torvalds 63131da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); 63141da177e4SLinus Torvalds 63151da177e4SLinus Torvalds if (!asoc && assocparams.sasoc_assoc_id && sctp_style(sk, UDP)) 63161da177e4SLinus Torvalds return -EINVAL; 63171da177e4SLinus Torvalds 63181da177e4SLinus Torvalds /* Values correspoinding to the specific association */ 631917337216SVladislav Yasevich if (asoc) { 63201da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt = asoc->max_retrans; 63211da177e4SLinus Torvalds assocparams.sasoc_peer_rwnd = asoc->peer.rwnd; 63221da177e4SLinus Torvalds assocparams.sasoc_local_rwnd = asoc->a_rwnd; 632352db882fSDaniel Borkmann assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life); 63241da177e4SLinus Torvalds 63251da177e4SLinus Torvalds list_for_each(pos, &asoc->peer.transport_addr_list) { 63261da177e4SLinus Torvalds cnt++; 63271da177e4SLinus Torvalds } 63281da177e4SLinus Torvalds 63291da177e4SLinus Torvalds assocparams.sasoc_number_peer_destinations = cnt; 63301da177e4SLinus Torvalds } else { 63311da177e4SLinus Torvalds /* Values corresponding to the endpoint */ 63321da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 63331da177e4SLinus Torvalds 63341da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt; 63351da177e4SLinus Torvalds assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd; 63361da177e4SLinus Torvalds assocparams.sasoc_local_rwnd = sp->assocparams.sasoc_local_rwnd; 63371da177e4SLinus Torvalds assocparams.sasoc_cookie_life = 63381da177e4SLinus Torvalds sp->assocparams.sasoc_cookie_life; 63391da177e4SLinus Torvalds assocparams.sasoc_number_peer_destinations = 63401da177e4SLinus Torvalds sp->assocparams. 63411da177e4SLinus Torvalds sasoc_number_peer_destinations; 63421da177e4SLinus Torvalds } 63431da177e4SLinus Torvalds 63441da177e4SLinus Torvalds if (put_user(len, optlen)) 63451da177e4SLinus Torvalds return -EFAULT; 63461da177e4SLinus Torvalds 63471da177e4SLinus Torvalds if (copy_to_user(optval, &assocparams, len)) 63481da177e4SLinus Torvalds return -EFAULT; 63491da177e4SLinus Torvalds 63501da177e4SLinus Torvalds return 0; 63511da177e4SLinus Torvalds } 63521da177e4SLinus Torvalds 63531da177e4SLinus Torvalds /* 63541da177e4SLinus Torvalds * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 63551da177e4SLinus Torvalds * 63561da177e4SLinus Torvalds * This socket option is a boolean flag which turns on or off mapped V4 63571da177e4SLinus Torvalds * addresses. If this option is turned on and the socket is type 63581da177e4SLinus Torvalds * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 63591da177e4SLinus Torvalds * If this option is turned off, then no mapping will be done of V4 63601da177e4SLinus Torvalds * addresses and a user will receive both PF_INET6 and PF_INET type 63611da177e4SLinus Torvalds * addresses on the socket. 63621da177e4SLinus Torvalds */ 63631da177e4SLinus Torvalds static int sctp_getsockopt_mappedv4(struct sock *sk, int len, 63641da177e4SLinus Torvalds char __user *optval, int __user *optlen) 63651da177e4SLinus Torvalds { 63661da177e4SLinus Torvalds int val; 63671da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 63681da177e4SLinus Torvalds 63691da177e4SLinus Torvalds if (len < sizeof(int)) 63701da177e4SLinus Torvalds return -EINVAL; 63711da177e4SLinus Torvalds 63721da177e4SLinus Torvalds len = sizeof(int); 63731da177e4SLinus Torvalds val = sp->v4mapped; 63741da177e4SLinus Torvalds if (put_user(len, optlen)) 63751da177e4SLinus Torvalds return -EFAULT; 63761da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 63771da177e4SLinus Torvalds return -EFAULT; 63781da177e4SLinus Torvalds 63791da177e4SLinus Torvalds return 0; 63801da177e4SLinus Torvalds } 63811da177e4SLinus Torvalds 63821da177e4SLinus Torvalds /* 63836ab792f5SIvan Skytte Jorgensen * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 63846ab792f5SIvan Skytte Jorgensen * (chapter and verse is quoted at sctp_setsockopt_context()) 63856ab792f5SIvan Skytte Jorgensen */ 63866ab792f5SIvan Skytte Jorgensen static int sctp_getsockopt_context(struct sock *sk, int len, 63876ab792f5SIvan Skytte Jorgensen char __user *optval, int __user *optlen) 63886ab792f5SIvan Skytte Jorgensen { 63896ab792f5SIvan Skytte Jorgensen struct sctp_assoc_value params; 63906ab792f5SIvan Skytte Jorgensen struct sctp_sock *sp; 63916ab792f5SIvan Skytte Jorgensen struct sctp_association *asoc; 63926ab792f5SIvan Skytte Jorgensen 6393408f22e8SNeil Horman if (len < sizeof(struct sctp_assoc_value)) 63946ab792f5SIvan Skytte Jorgensen return -EINVAL; 63956ab792f5SIvan Skytte Jorgensen 6396408f22e8SNeil Horman len = sizeof(struct sctp_assoc_value); 6397408f22e8SNeil Horman 63986ab792f5SIvan Skytte Jorgensen if (copy_from_user(¶ms, optval, len)) 63996ab792f5SIvan Skytte Jorgensen return -EFAULT; 64006ab792f5SIvan Skytte Jorgensen 64016ab792f5SIvan Skytte Jorgensen sp = sctp_sk(sk); 64026ab792f5SIvan Skytte Jorgensen 64036ab792f5SIvan Skytte Jorgensen if (params.assoc_id != 0) { 64046ab792f5SIvan Skytte Jorgensen asoc = sctp_id2assoc(sk, params.assoc_id); 64056ab792f5SIvan Skytte Jorgensen if (!asoc) 64066ab792f5SIvan Skytte Jorgensen return -EINVAL; 64076ab792f5SIvan Skytte Jorgensen params.assoc_value = asoc->default_rcv_context; 64086ab792f5SIvan Skytte Jorgensen } else { 64096ab792f5SIvan Skytte Jorgensen params.assoc_value = sp->default_rcv_context; 64106ab792f5SIvan Skytte Jorgensen } 64116ab792f5SIvan Skytte Jorgensen 64126ab792f5SIvan Skytte Jorgensen if (put_user(len, optlen)) 64136ab792f5SIvan Skytte Jorgensen return -EFAULT; 64146ab792f5SIvan Skytte Jorgensen if (copy_to_user(optval, ¶ms, len)) 64156ab792f5SIvan Skytte Jorgensen return -EFAULT; 64166ab792f5SIvan Skytte Jorgensen 64176ab792f5SIvan Skytte Jorgensen return 0; 64186ab792f5SIvan Skytte Jorgensen } 64196ab792f5SIvan Skytte Jorgensen 64206ab792f5SIvan Skytte Jorgensen /* 6421e89c2095SWei Yongjun * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 6422e89c2095SWei Yongjun * This option will get or set the maximum size to put in any outgoing 6423e89c2095SWei Yongjun * SCTP DATA chunk. If a message is larger than this size it will be 64241da177e4SLinus Torvalds * fragmented by SCTP into the specified size. Note that the underlying 64251da177e4SLinus Torvalds * SCTP implementation may fragment into smaller sized chunks when the 64261da177e4SLinus Torvalds * PMTU of the underlying association is smaller than the value set by 6427e89c2095SWei Yongjun * the user. The default value for this option is '0' which indicates 6428e89c2095SWei Yongjun * the user is NOT limiting fragmentation and only the PMTU will effect 6429e89c2095SWei Yongjun * SCTP's choice of DATA chunk size. Note also that values set larger 6430e89c2095SWei Yongjun * than the maximum size of an IP datagram will effectively let SCTP 6431e89c2095SWei Yongjun * control fragmentation (i.e. the same as setting this option to 0). 6432e89c2095SWei Yongjun * 6433e89c2095SWei Yongjun * The following structure is used to access and modify this parameter: 6434e89c2095SWei Yongjun * 6435e89c2095SWei Yongjun * struct sctp_assoc_value { 6436e89c2095SWei Yongjun * sctp_assoc_t assoc_id; 6437e89c2095SWei Yongjun * uint32_t assoc_value; 6438e89c2095SWei Yongjun * }; 6439e89c2095SWei Yongjun * 6440e89c2095SWei Yongjun * assoc_id: This parameter is ignored for one-to-one style sockets. 6441e89c2095SWei Yongjun * For one-to-many style sockets this parameter indicates which 6442e89c2095SWei Yongjun * association the user is performing an action upon. Note that if 6443e89c2095SWei Yongjun * this field's value is zero then the endpoints default value is 6444e89c2095SWei Yongjun * changed (effecting future associations only). 6445e89c2095SWei Yongjun * assoc_value: This parameter specifies the maximum size in bytes. 64461da177e4SLinus Torvalds */ 64471da177e4SLinus Torvalds static int sctp_getsockopt_maxseg(struct sock *sk, int len, 64481da177e4SLinus Torvalds char __user *optval, int __user *optlen) 64491da177e4SLinus Torvalds { 6450e89c2095SWei Yongjun struct sctp_assoc_value params; 6451e89c2095SWei Yongjun struct sctp_association *asoc; 64521da177e4SLinus Torvalds 6453e89c2095SWei Yongjun if (len == sizeof(int)) { 645494f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 6455f916ec96SNeil Horman "%s (pid %d) " 645694f65193SNeil Horman "Use of int in maxseg socket option.\n" 6457f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 6458f916ec96SNeil Horman current->comm, task_pid_nr(current)); 6459e89c2095SWei Yongjun params.assoc_id = 0; 6460e89c2095SWei Yongjun } else if (len >= sizeof(struct sctp_assoc_value)) { 6461e89c2095SWei Yongjun len = sizeof(struct sctp_assoc_value); 6462c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, len)) 6463e89c2095SWei Yongjun return -EFAULT; 6464e89c2095SWei Yongjun } else 64651da177e4SLinus Torvalds return -EINVAL; 64661da177e4SLinus Torvalds 6467e89c2095SWei Yongjun asoc = sctp_id2assoc(sk, params.assoc_id); 6468e89c2095SWei Yongjun if (!asoc && params.assoc_id && sctp_style(sk, UDP)) 6469e89c2095SWei Yongjun return -EINVAL; 64701da177e4SLinus Torvalds 6471e89c2095SWei Yongjun if (asoc) 6472e89c2095SWei Yongjun params.assoc_value = asoc->frag_point; 6473e89c2095SWei Yongjun else 6474e89c2095SWei Yongjun params.assoc_value = sctp_sk(sk)->user_frag; 6475e89c2095SWei Yongjun 64761da177e4SLinus Torvalds if (put_user(len, optlen)) 64771da177e4SLinus Torvalds return -EFAULT; 6478e89c2095SWei Yongjun if (len == sizeof(int)) { 6479e89c2095SWei Yongjun if (copy_to_user(optval, ¶ms.assoc_value, len)) 64801da177e4SLinus Torvalds return -EFAULT; 6481e89c2095SWei Yongjun } else { 6482e89c2095SWei Yongjun if (copy_to_user(optval, ¶ms, len)) 6483e89c2095SWei Yongjun return -EFAULT; 6484e89c2095SWei Yongjun } 64851da177e4SLinus Torvalds 64861da177e4SLinus Torvalds return 0; 64871da177e4SLinus Torvalds } 64881da177e4SLinus Torvalds 6489b6e1331fSVlad Yasevich /* 6490b6e1331fSVlad Yasevich * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 6491b6e1331fSVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_fragment_interleave()) 6492b6e1331fSVlad Yasevich */ 6493b6e1331fSVlad Yasevich static int sctp_getsockopt_fragment_interleave(struct sock *sk, int len, 6494b6e1331fSVlad Yasevich char __user *optval, int __user *optlen) 6495b6e1331fSVlad Yasevich { 6496b6e1331fSVlad Yasevich int val; 6497b6e1331fSVlad Yasevich 6498b6e1331fSVlad Yasevich if (len < sizeof(int)) 6499b6e1331fSVlad Yasevich return -EINVAL; 6500b6e1331fSVlad Yasevich 6501b6e1331fSVlad Yasevich len = sizeof(int); 6502b6e1331fSVlad Yasevich 6503b6e1331fSVlad Yasevich val = sctp_sk(sk)->frag_interleave; 6504b6e1331fSVlad Yasevich if (put_user(len, optlen)) 6505b6e1331fSVlad Yasevich return -EFAULT; 6506b6e1331fSVlad Yasevich if (copy_to_user(optval, &val, len)) 6507b6e1331fSVlad Yasevich return -EFAULT; 6508b6e1331fSVlad Yasevich 6509b6e1331fSVlad Yasevich return 0; 6510b6e1331fSVlad Yasevich } 6511b6e1331fSVlad Yasevich 6512d49d91d7SVlad Yasevich /* 6513d49d91d7SVlad Yasevich * 7.1.25. Set or Get the sctp partial delivery point 6514d49d91d7SVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_partial_delivery_point()) 6515d49d91d7SVlad Yasevich */ 6516d49d91d7SVlad Yasevich static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len, 6517d49d91d7SVlad Yasevich char __user *optval, 6518d49d91d7SVlad Yasevich int __user *optlen) 6519d49d91d7SVlad Yasevich { 6520d49d91d7SVlad Yasevich u32 val; 6521d49d91d7SVlad Yasevich 6522d49d91d7SVlad Yasevich if (len < sizeof(u32)) 6523d49d91d7SVlad Yasevich return -EINVAL; 6524d49d91d7SVlad Yasevich 6525d49d91d7SVlad Yasevich len = sizeof(u32); 6526d49d91d7SVlad Yasevich 6527d49d91d7SVlad Yasevich val = sctp_sk(sk)->pd_point; 6528d49d91d7SVlad Yasevich if (put_user(len, optlen)) 6529d49d91d7SVlad Yasevich return -EFAULT; 6530d49d91d7SVlad Yasevich if (copy_to_user(optval, &val, len)) 6531d49d91d7SVlad Yasevich return -EFAULT; 6532d49d91d7SVlad Yasevich 65337d743b7eSWei Yongjun return 0; 6534d49d91d7SVlad Yasevich } 6535d49d91d7SVlad Yasevich 653670331571SVlad Yasevich /* 653770331571SVlad Yasevich * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 653870331571SVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_maxburst()) 653970331571SVlad Yasevich */ 654070331571SVlad Yasevich static int sctp_getsockopt_maxburst(struct sock *sk, int len, 654170331571SVlad Yasevich char __user *optval, 654270331571SVlad Yasevich int __user *optlen) 654370331571SVlad Yasevich { 6544219b99a9SNeil Horman struct sctp_assoc_value params; 6545219b99a9SNeil Horman struct sctp_sock *sp; 6546219b99a9SNeil Horman struct sctp_association *asoc; 654770331571SVlad Yasevich 6548219b99a9SNeil Horman if (len == sizeof(int)) { 654994f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 6550f916ec96SNeil Horman "%s (pid %d) " 655194f65193SNeil Horman "Use of int in max_burst socket option.\n" 6552f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 6553f916ec96SNeil Horman current->comm, task_pid_nr(current)); 6554219b99a9SNeil Horman params.assoc_id = 0; 6555c6db93a5SWei Yongjun } else if (len >= sizeof(struct sctp_assoc_value)) { 6556c6db93a5SWei Yongjun len = sizeof(struct sctp_assoc_value); 6557219b99a9SNeil Horman if (copy_from_user(¶ms, optval, len)) 655870331571SVlad Yasevich return -EFAULT; 6559219b99a9SNeil Horman } else 6560219b99a9SNeil Horman return -EINVAL; 656170331571SVlad Yasevich 6562219b99a9SNeil Horman sp = sctp_sk(sk); 6563219b99a9SNeil Horman 6564219b99a9SNeil Horman if (params.assoc_id != 0) { 6565219b99a9SNeil Horman asoc = sctp_id2assoc(sk, params.assoc_id); 6566219b99a9SNeil Horman if (!asoc) 6567219b99a9SNeil Horman return -EINVAL; 6568219b99a9SNeil Horman params.assoc_value = asoc->max_burst; 6569219b99a9SNeil Horman } else 6570219b99a9SNeil Horman params.assoc_value = sp->max_burst; 6571219b99a9SNeil Horman 6572219b99a9SNeil Horman if (len == sizeof(int)) { 6573219b99a9SNeil Horman if (copy_to_user(optval, ¶ms.assoc_value, len)) 6574219b99a9SNeil Horman return -EFAULT; 6575219b99a9SNeil Horman } else { 6576219b99a9SNeil Horman if (copy_to_user(optval, ¶ms, len)) 6577219b99a9SNeil Horman return -EFAULT; 6578219b99a9SNeil Horman } 6579219b99a9SNeil Horman 6580219b99a9SNeil Horman return 0; 6581219b99a9SNeil Horman 658270331571SVlad Yasevich } 658370331571SVlad Yasevich 658465b07e5dSVlad Yasevich static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, 658565b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 658665b07e5dSVlad Yasevich { 6587b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 65885e739d17SVlad Yasevich struct sctp_hmacalgo __user *p = (void __user *)optval; 658965b07e5dSVlad Yasevich struct sctp_hmac_algo_param *hmacs; 65905e739d17SVlad Yasevich __u16 data_len = 0; 65915e739d17SVlad Yasevich u32 num_idents; 65927a84bd46SXin Long int i; 65935e739d17SVlad Yasevich 6594b14878ccSVlad Yasevich if (!ep->auth_enable) 65955e739d17SVlad Yasevich return -EACCES; 659665b07e5dSVlad Yasevich 6597b14878ccSVlad Yasevich hmacs = ep->auth_hmacs_list; 65983c918704SXin Long data_len = ntohs(hmacs->param_hdr.length) - 65993c918704SXin Long sizeof(struct sctp_paramhdr); 660065b07e5dSVlad Yasevich 66015e739d17SVlad Yasevich if (len < sizeof(struct sctp_hmacalgo) + data_len) 660265b07e5dSVlad Yasevich return -EINVAL; 66035e739d17SVlad Yasevich 66045e739d17SVlad Yasevich len = sizeof(struct sctp_hmacalgo) + data_len; 66055e739d17SVlad Yasevich num_idents = data_len / sizeof(u16); 66065e739d17SVlad Yasevich 660765b07e5dSVlad Yasevich if (put_user(len, optlen)) 660865b07e5dSVlad Yasevich return -EFAULT; 66095e739d17SVlad Yasevich if (put_user(num_idents, &p->shmac_num_idents)) 661065b07e5dSVlad Yasevich return -EFAULT; 66117a84bd46SXin Long for (i = 0; i < num_idents; i++) { 66127a84bd46SXin Long __u16 hmacid = ntohs(hmacs->hmac_ids[i]); 66137a84bd46SXin Long 66147a84bd46SXin Long if (copy_to_user(&p->shmac_idents[i], &hmacid, sizeof(__u16))) 66155e739d17SVlad Yasevich return -EFAULT; 66167a84bd46SXin Long } 661765b07e5dSVlad Yasevich return 0; 661865b07e5dSVlad Yasevich } 661965b07e5dSVlad Yasevich 662065b07e5dSVlad Yasevich static int sctp_getsockopt_active_key(struct sock *sk, int len, 662165b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 662265b07e5dSVlad Yasevich { 6623b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 662465b07e5dSVlad Yasevich struct sctp_authkeyid val; 662565b07e5dSVlad Yasevich struct sctp_association *asoc; 662665b07e5dSVlad Yasevich 6627b14878ccSVlad Yasevich if (!ep->auth_enable) 66285e739d17SVlad Yasevich return -EACCES; 66295e739d17SVlad Yasevich 663065b07e5dSVlad Yasevich if (len < sizeof(struct sctp_authkeyid)) 663165b07e5dSVlad Yasevich return -EINVAL; 6632c76f97c9SMarcelo Ricardo Leitner 6633c76f97c9SMarcelo Ricardo Leitner len = sizeof(struct sctp_authkeyid); 6634c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(&val, optval, len)) 663565b07e5dSVlad Yasevich return -EFAULT; 663665b07e5dSVlad Yasevich 663765b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 663865b07e5dSVlad Yasevich if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 663965b07e5dSVlad Yasevich return -EINVAL; 664065b07e5dSVlad Yasevich 664165b07e5dSVlad Yasevich if (asoc) 664265b07e5dSVlad Yasevich val.scact_keynumber = asoc->active_key_id; 664365b07e5dSVlad Yasevich else 6644b14878ccSVlad Yasevich val.scact_keynumber = ep->active_key_id; 664565b07e5dSVlad Yasevich 66465e739d17SVlad Yasevich if (put_user(len, optlen)) 66475e739d17SVlad Yasevich return -EFAULT; 66485e739d17SVlad Yasevich if (copy_to_user(optval, &val, len)) 66495e739d17SVlad Yasevich return -EFAULT; 66505e739d17SVlad Yasevich 665165b07e5dSVlad Yasevich return 0; 665265b07e5dSVlad Yasevich } 665365b07e5dSVlad Yasevich 665465b07e5dSVlad Yasevich static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, 665565b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 665665b07e5dSVlad Yasevich { 6657b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 6658411223c0SAl Viro struct sctp_authchunks __user *p = (void __user *)optval; 665965b07e5dSVlad Yasevich struct sctp_authchunks val; 666065b07e5dSVlad Yasevich struct sctp_association *asoc; 666165b07e5dSVlad Yasevich struct sctp_chunks_param *ch; 66625e739d17SVlad Yasevich u32 num_chunks = 0; 666365b07e5dSVlad Yasevich char __user *to; 666465b07e5dSVlad Yasevich 6665b14878ccSVlad Yasevich if (!ep->auth_enable) 66665e739d17SVlad Yasevich return -EACCES; 66675e739d17SVlad Yasevich 66685e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks)) 666965b07e5dSVlad Yasevich return -EINVAL; 667065b07e5dSVlad Yasevich 6671c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(&val, optval, sizeof(val))) 667265b07e5dSVlad Yasevich return -EFAULT; 667365b07e5dSVlad Yasevich 6674411223c0SAl Viro to = p->gauth_chunks; 667565b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 667665b07e5dSVlad Yasevich if (!asoc) 667765b07e5dSVlad Yasevich return -EINVAL; 667865b07e5dSVlad Yasevich 667965b07e5dSVlad Yasevich ch = asoc->peer.peer_chunks; 66805e739d17SVlad Yasevich if (!ch) 66815e739d17SVlad Yasevich goto num; 668265b07e5dSVlad Yasevich 668365b07e5dSVlad Yasevich /* See if the user provided enough room for all the data */ 66843c918704SXin Long num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); 6685b40db684SVlad Yasevich if (len < num_chunks) 668665b07e5dSVlad Yasevich return -EINVAL; 668765b07e5dSVlad Yasevich 66885e739d17SVlad Yasevich if (copy_to_user(to, ch->chunks, num_chunks)) 668965b07e5dSVlad Yasevich return -EFAULT; 66905e739d17SVlad Yasevich num: 66915e739d17SVlad Yasevich len = sizeof(struct sctp_authchunks) + num_chunks; 66928d72651dSwangweidong if (put_user(len, optlen)) 66938d72651dSwangweidong return -EFAULT; 66947e8616d8SVlad Yasevich if (put_user(num_chunks, &p->gauth_number_of_chunks)) 66957e8616d8SVlad Yasevich return -EFAULT; 669665b07e5dSVlad Yasevich return 0; 669765b07e5dSVlad Yasevich } 669865b07e5dSVlad Yasevich 669965b07e5dSVlad Yasevich static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, 670065b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 670165b07e5dSVlad Yasevich { 6702b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 6703411223c0SAl Viro struct sctp_authchunks __user *p = (void __user *)optval; 670465b07e5dSVlad Yasevich struct sctp_authchunks val; 670565b07e5dSVlad Yasevich struct sctp_association *asoc; 670665b07e5dSVlad Yasevich struct sctp_chunks_param *ch; 67075e739d17SVlad Yasevich u32 num_chunks = 0; 670865b07e5dSVlad Yasevich char __user *to; 670965b07e5dSVlad Yasevich 6710b14878ccSVlad Yasevich if (!ep->auth_enable) 67115e739d17SVlad Yasevich return -EACCES; 67125e739d17SVlad Yasevich 67135e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks)) 671465b07e5dSVlad Yasevich return -EINVAL; 671565b07e5dSVlad Yasevich 6716c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(&val, optval, sizeof(val))) 671765b07e5dSVlad Yasevich return -EFAULT; 671865b07e5dSVlad Yasevich 6719411223c0SAl Viro to = p->gauth_chunks; 672065b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 672165b07e5dSVlad Yasevich if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP)) 672265b07e5dSVlad Yasevich return -EINVAL; 672365b07e5dSVlad Yasevich 672465b07e5dSVlad Yasevich if (asoc) 672565b07e5dSVlad Yasevich ch = (struct sctp_chunks_param *)asoc->c.auth_chunks; 672665b07e5dSVlad Yasevich else 6727b14878ccSVlad Yasevich ch = ep->auth_chunk_list; 672865b07e5dSVlad Yasevich 67295e739d17SVlad Yasevich if (!ch) 67305e739d17SVlad Yasevich goto num; 67315e739d17SVlad Yasevich 67323c918704SXin Long num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); 67335e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks) + num_chunks) 673465b07e5dSVlad Yasevich return -EINVAL; 673565b07e5dSVlad Yasevich 67365e739d17SVlad Yasevich if (copy_to_user(to, ch->chunks, num_chunks)) 67375e739d17SVlad Yasevich return -EFAULT; 67385e739d17SVlad Yasevich num: 67395e739d17SVlad Yasevich len = sizeof(struct sctp_authchunks) + num_chunks; 674065b07e5dSVlad Yasevich if (put_user(len, optlen)) 674165b07e5dSVlad Yasevich return -EFAULT; 67427e8616d8SVlad Yasevich if (put_user(num_chunks, &p->gauth_number_of_chunks)) 67437e8616d8SVlad Yasevich return -EFAULT; 674465b07e5dSVlad Yasevich 674565b07e5dSVlad Yasevich return 0; 674665b07e5dSVlad Yasevich } 674765b07e5dSVlad Yasevich 6748aea3c5c0SWei Yongjun /* 6749aea3c5c0SWei Yongjun * 8.2.5. Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER) 6750aea3c5c0SWei Yongjun * This option gets the current number of associations that are attached 6751aea3c5c0SWei Yongjun * to a one-to-many style socket. The option value is an uint32_t. 6752aea3c5c0SWei Yongjun */ 6753aea3c5c0SWei Yongjun static int sctp_getsockopt_assoc_number(struct sock *sk, int len, 6754aea3c5c0SWei Yongjun char __user *optval, int __user *optlen) 6755aea3c5c0SWei Yongjun { 6756aea3c5c0SWei Yongjun struct sctp_sock *sp = sctp_sk(sk); 6757aea3c5c0SWei Yongjun struct sctp_association *asoc; 6758aea3c5c0SWei Yongjun u32 val = 0; 6759aea3c5c0SWei Yongjun 6760aea3c5c0SWei Yongjun if (sctp_style(sk, TCP)) 6761aea3c5c0SWei Yongjun return -EOPNOTSUPP; 6762aea3c5c0SWei Yongjun 6763aea3c5c0SWei Yongjun if (len < sizeof(u32)) 6764aea3c5c0SWei Yongjun return -EINVAL; 6765aea3c5c0SWei Yongjun 6766aea3c5c0SWei Yongjun len = sizeof(u32); 6767aea3c5c0SWei Yongjun 6768aea3c5c0SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 6769aea3c5c0SWei Yongjun val++; 6770aea3c5c0SWei Yongjun } 6771aea3c5c0SWei Yongjun 6772aea3c5c0SWei Yongjun if (put_user(len, optlen)) 6773aea3c5c0SWei Yongjun return -EFAULT; 6774aea3c5c0SWei Yongjun if (copy_to_user(optval, &val, len)) 6775aea3c5c0SWei Yongjun return -EFAULT; 6776aea3c5c0SWei Yongjun 6777aea3c5c0SWei Yongjun return 0; 6778aea3c5c0SWei Yongjun } 6779aea3c5c0SWei Yongjun 6780209ba424SWei Yongjun /* 67817dc04d71SMichio Honda * 8.1.23 SCTP_AUTO_ASCONF 67827dc04d71SMichio Honda * See the corresponding setsockopt entry as description 67837dc04d71SMichio Honda */ 67847dc04d71SMichio Honda static int sctp_getsockopt_auto_asconf(struct sock *sk, int len, 67857dc04d71SMichio Honda char __user *optval, int __user *optlen) 67867dc04d71SMichio Honda { 67877dc04d71SMichio Honda int val = 0; 67887dc04d71SMichio Honda 67897dc04d71SMichio Honda if (len < sizeof(int)) 67907dc04d71SMichio Honda return -EINVAL; 67917dc04d71SMichio Honda 67927dc04d71SMichio Honda len = sizeof(int); 67937dc04d71SMichio Honda if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk)) 67947dc04d71SMichio Honda val = 1; 67957dc04d71SMichio Honda if (put_user(len, optlen)) 67967dc04d71SMichio Honda return -EFAULT; 67977dc04d71SMichio Honda if (copy_to_user(optval, &val, len)) 67987dc04d71SMichio Honda return -EFAULT; 67997dc04d71SMichio Honda return 0; 68007dc04d71SMichio Honda } 68017dc04d71SMichio Honda 68027dc04d71SMichio Honda /* 6803209ba424SWei Yongjun * 8.2.6. Get the Current Identifiers of Associations 6804209ba424SWei Yongjun * (SCTP_GET_ASSOC_ID_LIST) 6805209ba424SWei Yongjun * 6806209ba424SWei Yongjun * This option gets the current list of SCTP association identifiers of 6807209ba424SWei Yongjun * the SCTP associations handled by a one-to-many style socket. 6808209ba424SWei Yongjun */ 6809209ba424SWei Yongjun static int sctp_getsockopt_assoc_ids(struct sock *sk, int len, 6810209ba424SWei Yongjun char __user *optval, int __user *optlen) 6811209ba424SWei Yongjun { 6812209ba424SWei Yongjun struct sctp_sock *sp = sctp_sk(sk); 6813209ba424SWei Yongjun struct sctp_association *asoc; 6814209ba424SWei Yongjun struct sctp_assoc_ids *ids; 6815209ba424SWei Yongjun u32 num = 0; 6816209ba424SWei Yongjun 6817209ba424SWei Yongjun if (sctp_style(sk, TCP)) 6818209ba424SWei Yongjun return -EOPNOTSUPP; 6819209ba424SWei Yongjun 6820209ba424SWei Yongjun if (len < sizeof(struct sctp_assoc_ids)) 6821209ba424SWei Yongjun return -EINVAL; 6822209ba424SWei Yongjun 6823209ba424SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 6824209ba424SWei Yongjun num++; 6825209ba424SWei Yongjun } 6826209ba424SWei Yongjun 6827209ba424SWei Yongjun if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num) 6828209ba424SWei Yongjun return -EINVAL; 6829209ba424SWei Yongjun 6830209ba424SWei Yongjun len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num; 6831209ba424SWei Yongjun 68329ba0b963SMarcelo Ricardo Leitner ids = kmalloc(len, GFP_USER | __GFP_NOWARN); 6833209ba424SWei Yongjun if (unlikely(!ids)) 6834209ba424SWei Yongjun return -ENOMEM; 6835209ba424SWei Yongjun 6836209ba424SWei Yongjun ids->gaids_number_of_ids = num; 6837209ba424SWei Yongjun num = 0; 6838209ba424SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 6839209ba424SWei Yongjun ids->gaids_assoc_id[num++] = asoc->assoc_id; 6840209ba424SWei Yongjun } 6841209ba424SWei Yongjun 6842209ba424SWei Yongjun if (put_user(len, optlen) || copy_to_user(optval, ids, len)) { 6843209ba424SWei Yongjun kfree(ids); 6844209ba424SWei Yongjun return -EFAULT; 6845209ba424SWei Yongjun } 6846209ba424SWei Yongjun 6847209ba424SWei Yongjun kfree(ids); 6848209ba424SWei Yongjun return 0; 6849209ba424SWei Yongjun } 6850209ba424SWei Yongjun 68515aa93bcfSNeil Horman /* 68525aa93bcfSNeil Horman * SCTP_PEER_ADDR_THLDS 68535aa93bcfSNeil Horman * 68545aa93bcfSNeil Horman * This option allows us to fetch the partially failed threshold for one or all 68555aa93bcfSNeil Horman * transports in an association. See Section 6.1 of: 68565aa93bcfSNeil Horman * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 68575aa93bcfSNeil Horman */ 68585aa93bcfSNeil Horman static int sctp_getsockopt_paddr_thresholds(struct sock *sk, 68595aa93bcfSNeil Horman char __user *optval, 68605aa93bcfSNeil Horman int len, 68615aa93bcfSNeil Horman int __user *optlen) 68625aa93bcfSNeil Horman { 68635aa93bcfSNeil Horman struct sctp_paddrthlds val; 68645aa93bcfSNeil Horman struct sctp_transport *trans; 68655aa93bcfSNeil Horman struct sctp_association *asoc; 68665aa93bcfSNeil Horman 68675aa93bcfSNeil Horman if (len < sizeof(struct sctp_paddrthlds)) 68685aa93bcfSNeil Horman return -EINVAL; 68695aa93bcfSNeil Horman len = sizeof(struct sctp_paddrthlds); 68705aa93bcfSNeil Horman if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, len)) 68715aa93bcfSNeil Horman return -EFAULT; 68725aa93bcfSNeil Horman 68735aa93bcfSNeil Horman if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { 68745aa93bcfSNeil Horman asoc = sctp_id2assoc(sk, val.spt_assoc_id); 68755aa93bcfSNeil Horman if (!asoc) 68765aa93bcfSNeil Horman return -ENOENT; 68775aa93bcfSNeil Horman 68785aa93bcfSNeil Horman val.spt_pathpfthld = asoc->pf_retrans; 68795aa93bcfSNeil Horman val.spt_pathmaxrxt = asoc->pathmaxrxt; 68805aa93bcfSNeil Horman } else { 68815aa93bcfSNeil Horman trans = sctp_addr_id2transport(sk, &val.spt_address, 68825aa93bcfSNeil Horman val.spt_assoc_id); 68835aa93bcfSNeil Horman if (!trans) 68845aa93bcfSNeil Horman return -ENOENT; 68855aa93bcfSNeil Horman 68865aa93bcfSNeil Horman val.spt_pathmaxrxt = trans->pathmaxrxt; 68875aa93bcfSNeil Horman val.spt_pathpfthld = trans->pf_retrans; 68885aa93bcfSNeil Horman } 68895aa93bcfSNeil Horman 68905aa93bcfSNeil Horman if (put_user(len, optlen) || copy_to_user(optval, &val, len)) 68915aa93bcfSNeil Horman return -EFAULT; 68925aa93bcfSNeil Horman 68935aa93bcfSNeil Horman return 0; 68945aa93bcfSNeil Horman } 68955aa93bcfSNeil Horman 6896196d6759SMichele Baldessari /* 6897196d6759SMichele Baldessari * SCTP_GET_ASSOC_STATS 6898196d6759SMichele Baldessari * 6899196d6759SMichele Baldessari * This option retrieves local per endpoint statistics. It is modeled 6900196d6759SMichele Baldessari * after OpenSolaris' implementation 6901196d6759SMichele Baldessari */ 6902196d6759SMichele Baldessari static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, 6903196d6759SMichele Baldessari char __user *optval, 6904196d6759SMichele Baldessari int __user *optlen) 6905196d6759SMichele Baldessari { 6906196d6759SMichele Baldessari struct sctp_assoc_stats sas; 6907196d6759SMichele Baldessari struct sctp_association *asoc = NULL; 6908196d6759SMichele Baldessari 6909196d6759SMichele Baldessari /* User must provide at least the assoc id */ 6910196d6759SMichele Baldessari if (len < sizeof(sctp_assoc_t)) 6911196d6759SMichele Baldessari return -EINVAL; 6912196d6759SMichele Baldessari 6913726bc6b0SGuenter Roeck /* Allow the struct to grow and fill in as much as possible */ 6914726bc6b0SGuenter Roeck len = min_t(size_t, len, sizeof(sas)); 6915726bc6b0SGuenter Roeck 6916196d6759SMichele Baldessari if (copy_from_user(&sas, optval, len)) 6917196d6759SMichele Baldessari return -EFAULT; 6918196d6759SMichele Baldessari 6919196d6759SMichele Baldessari asoc = sctp_id2assoc(sk, sas.sas_assoc_id); 6920196d6759SMichele Baldessari if (!asoc) 6921196d6759SMichele Baldessari return -EINVAL; 6922196d6759SMichele Baldessari 6923196d6759SMichele Baldessari sas.sas_rtxchunks = asoc->stats.rtxchunks; 6924196d6759SMichele Baldessari sas.sas_gapcnt = asoc->stats.gapcnt; 6925196d6759SMichele Baldessari sas.sas_outofseqtsns = asoc->stats.outofseqtsns; 6926196d6759SMichele Baldessari sas.sas_osacks = asoc->stats.osacks; 6927196d6759SMichele Baldessari sas.sas_isacks = asoc->stats.isacks; 6928196d6759SMichele Baldessari sas.sas_octrlchunks = asoc->stats.octrlchunks; 6929196d6759SMichele Baldessari sas.sas_ictrlchunks = asoc->stats.ictrlchunks; 6930196d6759SMichele Baldessari sas.sas_oodchunks = asoc->stats.oodchunks; 6931196d6759SMichele Baldessari sas.sas_iodchunks = asoc->stats.iodchunks; 6932196d6759SMichele Baldessari sas.sas_ouodchunks = asoc->stats.ouodchunks; 6933196d6759SMichele Baldessari sas.sas_iuodchunks = asoc->stats.iuodchunks; 6934196d6759SMichele Baldessari sas.sas_idupchunks = asoc->stats.idupchunks; 6935196d6759SMichele Baldessari sas.sas_opackets = asoc->stats.opackets; 6936196d6759SMichele Baldessari sas.sas_ipackets = asoc->stats.ipackets; 6937196d6759SMichele Baldessari 6938196d6759SMichele Baldessari /* New high max rto observed, will return 0 if not a single 6939196d6759SMichele Baldessari * RTO update took place. obs_rto_ipaddr will be bogus 6940196d6759SMichele Baldessari * in such a case 6941196d6759SMichele Baldessari */ 6942196d6759SMichele Baldessari sas.sas_maxrto = asoc->stats.max_obs_rto; 6943196d6759SMichele Baldessari memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr, 6944196d6759SMichele Baldessari sizeof(struct sockaddr_storage)); 6945196d6759SMichele Baldessari 6946196d6759SMichele Baldessari /* Mark beginning of a new observation period */ 6947196d6759SMichele Baldessari asoc->stats.max_obs_rto = asoc->rto_min; 6948196d6759SMichele Baldessari 6949196d6759SMichele Baldessari if (put_user(len, optlen)) 6950196d6759SMichele Baldessari return -EFAULT; 6951196d6759SMichele Baldessari 6952bb33381dSDaniel Borkmann pr_debug("%s: len:%d, assoc_id:%d\n", __func__, len, sas.sas_assoc_id); 6953196d6759SMichele Baldessari 6954196d6759SMichele Baldessari if (copy_to_user(optval, &sas, len)) 6955196d6759SMichele Baldessari return -EFAULT; 6956196d6759SMichele Baldessari 6957196d6759SMichele Baldessari return 0; 6958196d6759SMichele Baldessari } 6959196d6759SMichele Baldessari 69600d3a421dSGeir Ola Vaagland static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, 69610d3a421dSGeir Ola Vaagland char __user *optval, 69620d3a421dSGeir Ola Vaagland int __user *optlen) 69630d3a421dSGeir Ola Vaagland { 69640d3a421dSGeir Ola Vaagland int val = 0; 69650d3a421dSGeir Ola Vaagland 69660d3a421dSGeir Ola Vaagland if (len < sizeof(int)) 69670d3a421dSGeir Ola Vaagland return -EINVAL; 69680d3a421dSGeir Ola Vaagland 69690d3a421dSGeir Ola Vaagland len = sizeof(int); 69700d3a421dSGeir Ola Vaagland if (sctp_sk(sk)->recvrcvinfo) 69710d3a421dSGeir Ola Vaagland val = 1; 69720d3a421dSGeir Ola Vaagland if (put_user(len, optlen)) 69730d3a421dSGeir Ola Vaagland return -EFAULT; 69740d3a421dSGeir Ola Vaagland if (copy_to_user(optval, &val, len)) 69750d3a421dSGeir Ola Vaagland return -EFAULT; 69760d3a421dSGeir Ola Vaagland 69770d3a421dSGeir Ola Vaagland return 0; 69780d3a421dSGeir Ola Vaagland } 69790d3a421dSGeir Ola Vaagland 69802347c80fSGeir Ola Vaagland static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len, 69812347c80fSGeir Ola Vaagland char __user *optval, 69822347c80fSGeir Ola Vaagland int __user *optlen) 69832347c80fSGeir Ola Vaagland { 69842347c80fSGeir Ola Vaagland int val = 0; 69852347c80fSGeir Ola Vaagland 69862347c80fSGeir Ola Vaagland if (len < sizeof(int)) 69872347c80fSGeir Ola Vaagland return -EINVAL; 69882347c80fSGeir Ola Vaagland 69892347c80fSGeir Ola Vaagland len = sizeof(int); 69902347c80fSGeir Ola Vaagland if (sctp_sk(sk)->recvnxtinfo) 69912347c80fSGeir Ola Vaagland val = 1; 69922347c80fSGeir Ola Vaagland if (put_user(len, optlen)) 69932347c80fSGeir Ola Vaagland return -EFAULT; 69942347c80fSGeir Ola Vaagland if (copy_to_user(optval, &val, len)) 69952347c80fSGeir Ola Vaagland return -EFAULT; 69962347c80fSGeir Ola Vaagland 69972347c80fSGeir Ola Vaagland return 0; 69982347c80fSGeir Ola Vaagland } 69992347c80fSGeir Ola Vaagland 700028aa4c26SXin Long static int sctp_getsockopt_pr_supported(struct sock *sk, int len, 700128aa4c26SXin Long char __user *optval, 700228aa4c26SXin Long int __user *optlen) 700328aa4c26SXin Long { 700428aa4c26SXin Long struct sctp_assoc_value params; 700528aa4c26SXin Long struct sctp_association *asoc; 700628aa4c26SXin Long int retval = -EFAULT; 700728aa4c26SXin Long 700828aa4c26SXin Long if (len < sizeof(params)) { 700928aa4c26SXin Long retval = -EINVAL; 701028aa4c26SXin Long goto out; 701128aa4c26SXin Long } 701228aa4c26SXin Long 701328aa4c26SXin Long len = sizeof(params); 701428aa4c26SXin Long if (copy_from_user(¶ms, optval, len)) 701528aa4c26SXin Long goto out; 701628aa4c26SXin Long 701728aa4c26SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 701828aa4c26SXin Long if (asoc) { 701928aa4c26SXin Long params.assoc_value = asoc->prsctp_enable; 702028aa4c26SXin Long } else if (!params.assoc_id) { 702128aa4c26SXin Long struct sctp_sock *sp = sctp_sk(sk); 702228aa4c26SXin Long 702328aa4c26SXin Long params.assoc_value = sp->ep->prsctp_enable; 702428aa4c26SXin Long } else { 702528aa4c26SXin Long retval = -EINVAL; 702628aa4c26SXin Long goto out; 702728aa4c26SXin Long } 702828aa4c26SXin Long 702928aa4c26SXin Long if (put_user(len, optlen)) 703028aa4c26SXin Long goto out; 703128aa4c26SXin Long 703228aa4c26SXin Long if (copy_to_user(optval, ¶ms, len)) 703328aa4c26SXin Long goto out; 703428aa4c26SXin Long 703528aa4c26SXin Long retval = 0; 703628aa4c26SXin Long 703728aa4c26SXin Long out: 703828aa4c26SXin Long return retval; 703928aa4c26SXin Long } 704028aa4c26SXin Long 7041f959fb44SXin Long static int sctp_getsockopt_default_prinfo(struct sock *sk, int len, 7042f959fb44SXin Long char __user *optval, 7043f959fb44SXin Long int __user *optlen) 7044f959fb44SXin Long { 7045f959fb44SXin Long struct sctp_default_prinfo info; 7046f959fb44SXin Long struct sctp_association *asoc; 7047f959fb44SXin Long int retval = -EFAULT; 7048f959fb44SXin Long 7049f959fb44SXin Long if (len < sizeof(info)) { 7050f959fb44SXin Long retval = -EINVAL; 7051f959fb44SXin Long goto out; 7052f959fb44SXin Long } 7053f959fb44SXin Long 7054f959fb44SXin Long len = sizeof(info); 7055f959fb44SXin Long if (copy_from_user(&info, optval, len)) 7056f959fb44SXin Long goto out; 7057f959fb44SXin Long 7058f959fb44SXin Long asoc = sctp_id2assoc(sk, info.pr_assoc_id); 7059f959fb44SXin Long if (asoc) { 7060f959fb44SXin Long info.pr_policy = SCTP_PR_POLICY(asoc->default_flags); 7061f959fb44SXin Long info.pr_value = asoc->default_timetolive; 7062f959fb44SXin Long } else if (!info.pr_assoc_id) { 7063f959fb44SXin Long struct sctp_sock *sp = sctp_sk(sk); 7064f959fb44SXin Long 7065f959fb44SXin Long info.pr_policy = SCTP_PR_POLICY(sp->default_flags); 7066f959fb44SXin Long info.pr_value = sp->default_timetolive; 7067f959fb44SXin Long } else { 7068f959fb44SXin Long retval = -EINVAL; 7069f959fb44SXin Long goto out; 7070f959fb44SXin Long } 7071f959fb44SXin Long 7072f959fb44SXin Long if (put_user(len, optlen)) 7073f959fb44SXin Long goto out; 7074f959fb44SXin Long 7075f959fb44SXin Long if (copy_to_user(optval, &info, len)) 7076f959fb44SXin Long goto out; 7077f959fb44SXin Long 7078f959fb44SXin Long retval = 0; 7079f959fb44SXin Long 7080f959fb44SXin Long out: 7081f959fb44SXin Long return retval; 7082f959fb44SXin Long } 7083f959fb44SXin Long 7084826d253dSXin Long static int sctp_getsockopt_pr_assocstatus(struct sock *sk, int len, 7085826d253dSXin Long char __user *optval, 7086826d253dSXin Long int __user *optlen) 7087826d253dSXin Long { 7088826d253dSXin Long struct sctp_prstatus params; 7089826d253dSXin Long struct sctp_association *asoc; 7090826d253dSXin Long int policy; 7091826d253dSXin Long int retval = -EINVAL; 7092826d253dSXin Long 7093826d253dSXin Long if (len < sizeof(params)) 7094826d253dSXin Long goto out; 7095826d253dSXin Long 7096826d253dSXin Long len = sizeof(params); 7097826d253dSXin Long if (copy_from_user(¶ms, optval, len)) { 7098826d253dSXin Long retval = -EFAULT; 7099826d253dSXin Long goto out; 7100826d253dSXin Long } 7101826d253dSXin Long 7102826d253dSXin Long policy = params.sprstat_policy; 7103*0ac1077eSXin Long if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL))) 7104826d253dSXin Long goto out; 7105826d253dSXin Long 7106826d253dSXin Long asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); 7107826d253dSXin Long if (!asoc) 7108826d253dSXin Long goto out; 7109826d253dSXin Long 7110*0ac1077eSXin Long if (policy & SCTP_PR_SCTP_ALL) { 7111826d253dSXin Long params.sprstat_abandoned_unsent = 0; 7112826d253dSXin Long params.sprstat_abandoned_sent = 0; 7113826d253dSXin Long for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { 7114826d253dSXin Long params.sprstat_abandoned_unsent += 7115826d253dSXin Long asoc->abandoned_unsent[policy]; 7116826d253dSXin Long params.sprstat_abandoned_sent += 7117826d253dSXin Long asoc->abandoned_sent[policy]; 7118826d253dSXin Long } 7119826d253dSXin Long } else { 7120826d253dSXin Long params.sprstat_abandoned_unsent = 7121826d253dSXin Long asoc->abandoned_unsent[__SCTP_PR_INDEX(policy)]; 7122826d253dSXin Long params.sprstat_abandoned_sent = 7123826d253dSXin Long asoc->abandoned_sent[__SCTP_PR_INDEX(policy)]; 7124826d253dSXin Long } 7125826d253dSXin Long 7126826d253dSXin Long if (put_user(len, optlen)) { 7127826d253dSXin Long retval = -EFAULT; 7128826d253dSXin Long goto out; 7129826d253dSXin Long } 7130826d253dSXin Long 7131826d253dSXin Long if (copy_to_user(optval, ¶ms, len)) { 7132826d253dSXin Long retval = -EFAULT; 7133826d253dSXin Long goto out; 7134826d253dSXin Long } 7135826d253dSXin Long 7136826d253dSXin Long retval = 0; 7137826d253dSXin Long 7138826d253dSXin Long out: 7139826d253dSXin Long return retval; 7140826d253dSXin Long } 7141826d253dSXin Long 7142d229d48dSXin Long static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len, 7143d229d48dSXin Long char __user *optval, 7144d229d48dSXin Long int __user *optlen) 7145d229d48dSXin Long { 7146f952be79SMarcelo Ricardo Leitner struct sctp_stream_out_ext *streamoute; 7147d229d48dSXin Long struct sctp_association *asoc; 7148d229d48dSXin Long struct sctp_prstatus params; 7149d229d48dSXin Long int retval = -EINVAL; 7150d229d48dSXin Long int policy; 7151d229d48dSXin Long 7152d229d48dSXin Long if (len < sizeof(params)) 7153d229d48dSXin Long goto out; 7154d229d48dSXin Long 7155d229d48dSXin Long len = sizeof(params); 7156d229d48dSXin Long if (copy_from_user(¶ms, optval, len)) { 7157d229d48dSXin Long retval = -EFAULT; 7158d229d48dSXin Long goto out; 7159d229d48dSXin Long } 7160d229d48dSXin Long 7161d229d48dSXin Long policy = params.sprstat_policy; 7162*0ac1077eSXin Long if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL))) 7163d229d48dSXin Long goto out; 7164d229d48dSXin Long 7165d229d48dSXin Long asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); 7166cee360abSXin Long if (!asoc || params.sprstat_sid >= asoc->stream.outcnt) 7167d229d48dSXin Long goto out; 7168d229d48dSXin Long 716905364ca0SKonstantin Khorenko streamoute = SCTP_SO(&asoc->stream, params.sprstat_sid)->ext; 7170f952be79SMarcelo Ricardo Leitner if (!streamoute) { 7171f952be79SMarcelo Ricardo Leitner /* Not allocated yet, means all stats are 0 */ 7172f952be79SMarcelo Ricardo Leitner params.sprstat_abandoned_unsent = 0; 7173f952be79SMarcelo Ricardo Leitner params.sprstat_abandoned_sent = 0; 7174f952be79SMarcelo Ricardo Leitner retval = 0; 7175f952be79SMarcelo Ricardo Leitner goto out; 7176f952be79SMarcelo Ricardo Leitner } 7177f952be79SMarcelo Ricardo Leitner 7178*0ac1077eSXin Long if (policy == SCTP_PR_SCTP_ALL) { 7179d229d48dSXin Long params.sprstat_abandoned_unsent = 0; 7180d229d48dSXin Long params.sprstat_abandoned_sent = 0; 7181d229d48dSXin Long for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { 7182d229d48dSXin Long params.sprstat_abandoned_unsent += 7183f952be79SMarcelo Ricardo Leitner streamoute->abandoned_unsent[policy]; 7184d229d48dSXin Long params.sprstat_abandoned_sent += 7185f952be79SMarcelo Ricardo Leitner streamoute->abandoned_sent[policy]; 7186d229d48dSXin Long } 7187d229d48dSXin Long } else { 7188d229d48dSXin Long params.sprstat_abandoned_unsent = 7189f952be79SMarcelo Ricardo Leitner streamoute->abandoned_unsent[__SCTP_PR_INDEX(policy)]; 7190d229d48dSXin Long params.sprstat_abandoned_sent = 7191f952be79SMarcelo Ricardo Leitner streamoute->abandoned_sent[__SCTP_PR_INDEX(policy)]; 7192d229d48dSXin Long } 7193d229d48dSXin Long 7194d229d48dSXin Long if (put_user(len, optlen) || copy_to_user(optval, ¶ms, len)) { 7195d229d48dSXin Long retval = -EFAULT; 7196d229d48dSXin Long goto out; 7197d229d48dSXin Long } 7198d229d48dSXin Long 7199d229d48dSXin Long retval = 0; 7200d229d48dSXin Long 7201d229d48dSXin Long out: 7202d229d48dSXin Long return retval; 7203d229d48dSXin Long } 7204d229d48dSXin Long 7205c0d8bab6SXin Long static int sctp_getsockopt_reconfig_supported(struct sock *sk, int len, 7206c0d8bab6SXin Long char __user *optval, 7207c0d8bab6SXin Long int __user *optlen) 7208c0d8bab6SXin Long { 7209c0d8bab6SXin Long struct sctp_assoc_value params; 7210c0d8bab6SXin Long struct sctp_association *asoc; 7211c0d8bab6SXin Long int retval = -EFAULT; 7212c0d8bab6SXin Long 7213c0d8bab6SXin Long if (len < sizeof(params)) { 7214c0d8bab6SXin Long retval = -EINVAL; 7215c0d8bab6SXin Long goto out; 7216c0d8bab6SXin Long } 7217c0d8bab6SXin Long 7218c0d8bab6SXin Long len = sizeof(params); 7219c0d8bab6SXin Long if (copy_from_user(¶ms, optval, len)) 7220c0d8bab6SXin Long goto out; 7221c0d8bab6SXin Long 7222c0d8bab6SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7223c0d8bab6SXin Long if (asoc) { 7224c0d8bab6SXin Long params.assoc_value = asoc->reconf_enable; 7225c0d8bab6SXin Long } else if (!params.assoc_id) { 7226c0d8bab6SXin Long struct sctp_sock *sp = sctp_sk(sk); 7227c0d8bab6SXin Long 7228c0d8bab6SXin Long params.assoc_value = sp->ep->reconf_enable; 7229c0d8bab6SXin Long } else { 7230c0d8bab6SXin Long retval = -EINVAL; 7231c0d8bab6SXin Long goto out; 7232c0d8bab6SXin Long } 7233c0d8bab6SXin Long 7234c0d8bab6SXin Long if (put_user(len, optlen)) 7235c0d8bab6SXin Long goto out; 7236c0d8bab6SXin Long 7237c0d8bab6SXin Long if (copy_to_user(optval, ¶ms, len)) 7238c0d8bab6SXin Long goto out; 7239c0d8bab6SXin Long 7240c0d8bab6SXin Long retval = 0; 7241c0d8bab6SXin Long 7242c0d8bab6SXin Long out: 7243c0d8bab6SXin Long return retval; 7244c0d8bab6SXin Long } 7245c0d8bab6SXin Long 72469fb657aeSXin Long static int sctp_getsockopt_enable_strreset(struct sock *sk, int len, 72479fb657aeSXin Long char __user *optval, 72489fb657aeSXin Long int __user *optlen) 72499fb657aeSXin Long { 72509fb657aeSXin Long struct sctp_assoc_value params; 72519fb657aeSXin Long struct sctp_association *asoc; 72529fb657aeSXin Long int retval = -EFAULT; 72539fb657aeSXin Long 72549fb657aeSXin Long if (len < sizeof(params)) { 72559fb657aeSXin Long retval = -EINVAL; 72569fb657aeSXin Long goto out; 72579fb657aeSXin Long } 72589fb657aeSXin Long 72599fb657aeSXin Long len = sizeof(params); 72609fb657aeSXin Long if (copy_from_user(¶ms, optval, len)) 72619fb657aeSXin Long goto out; 72629fb657aeSXin Long 72639fb657aeSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 72649fb657aeSXin Long if (asoc) { 72659fb657aeSXin Long params.assoc_value = asoc->strreset_enable; 72669fb657aeSXin Long } else if (!params.assoc_id) { 72679fb657aeSXin Long struct sctp_sock *sp = sctp_sk(sk); 72689fb657aeSXin Long 72699fb657aeSXin Long params.assoc_value = sp->ep->strreset_enable; 72709fb657aeSXin Long } else { 72719fb657aeSXin Long retval = -EINVAL; 72729fb657aeSXin Long goto out; 72739fb657aeSXin Long } 72749fb657aeSXin Long 72759fb657aeSXin Long if (put_user(len, optlen)) 72769fb657aeSXin Long goto out; 72779fb657aeSXin Long 72789fb657aeSXin Long if (copy_to_user(optval, ¶ms, len)) 72799fb657aeSXin Long goto out; 72809fb657aeSXin Long 72819fb657aeSXin Long retval = 0; 72829fb657aeSXin Long 72839fb657aeSXin Long out: 72849fb657aeSXin Long return retval; 72859fb657aeSXin Long } 72869fb657aeSXin Long 728713aa8770SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler(struct sock *sk, int len, 728813aa8770SMarcelo Ricardo Leitner char __user *optval, 728913aa8770SMarcelo Ricardo Leitner int __user *optlen) 729013aa8770SMarcelo Ricardo Leitner { 729113aa8770SMarcelo Ricardo Leitner struct sctp_assoc_value params; 729213aa8770SMarcelo Ricardo Leitner struct sctp_association *asoc; 729313aa8770SMarcelo Ricardo Leitner int retval = -EFAULT; 729413aa8770SMarcelo Ricardo Leitner 729513aa8770SMarcelo Ricardo Leitner if (len < sizeof(params)) { 729613aa8770SMarcelo Ricardo Leitner retval = -EINVAL; 729713aa8770SMarcelo Ricardo Leitner goto out; 729813aa8770SMarcelo Ricardo Leitner } 729913aa8770SMarcelo Ricardo Leitner 730013aa8770SMarcelo Ricardo Leitner len = sizeof(params); 730113aa8770SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, len)) 730213aa8770SMarcelo Ricardo Leitner goto out; 730313aa8770SMarcelo Ricardo Leitner 730413aa8770SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 730513aa8770SMarcelo Ricardo Leitner if (!asoc) { 730613aa8770SMarcelo Ricardo Leitner retval = -EINVAL; 730713aa8770SMarcelo Ricardo Leitner goto out; 730813aa8770SMarcelo Ricardo Leitner } 730913aa8770SMarcelo Ricardo Leitner 731013aa8770SMarcelo Ricardo Leitner params.assoc_value = sctp_sched_get_sched(asoc); 731113aa8770SMarcelo Ricardo Leitner 731213aa8770SMarcelo Ricardo Leitner if (put_user(len, optlen)) 731313aa8770SMarcelo Ricardo Leitner goto out; 731413aa8770SMarcelo Ricardo Leitner 731513aa8770SMarcelo Ricardo Leitner if (copy_to_user(optval, ¶ms, len)) 731613aa8770SMarcelo Ricardo Leitner goto out; 731713aa8770SMarcelo Ricardo Leitner 731813aa8770SMarcelo Ricardo Leitner retval = 0; 731913aa8770SMarcelo Ricardo Leitner 732013aa8770SMarcelo Ricardo Leitner out: 732113aa8770SMarcelo Ricardo Leitner return retval; 732213aa8770SMarcelo Ricardo Leitner } 732313aa8770SMarcelo Ricardo Leitner 73240ccdf3c7SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler_value(struct sock *sk, int len, 73250ccdf3c7SMarcelo Ricardo Leitner char __user *optval, 73260ccdf3c7SMarcelo Ricardo Leitner int __user *optlen) 73270ccdf3c7SMarcelo Ricardo Leitner { 73280ccdf3c7SMarcelo Ricardo Leitner struct sctp_stream_value params; 73290ccdf3c7SMarcelo Ricardo Leitner struct sctp_association *asoc; 73300ccdf3c7SMarcelo Ricardo Leitner int retval = -EFAULT; 73310ccdf3c7SMarcelo Ricardo Leitner 73320ccdf3c7SMarcelo Ricardo Leitner if (len < sizeof(params)) { 73330ccdf3c7SMarcelo Ricardo Leitner retval = -EINVAL; 73340ccdf3c7SMarcelo Ricardo Leitner goto out; 73350ccdf3c7SMarcelo Ricardo Leitner } 73360ccdf3c7SMarcelo Ricardo Leitner 73370ccdf3c7SMarcelo Ricardo Leitner len = sizeof(params); 73380ccdf3c7SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, len)) 73390ccdf3c7SMarcelo Ricardo Leitner goto out; 73400ccdf3c7SMarcelo Ricardo Leitner 73410ccdf3c7SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 73420ccdf3c7SMarcelo Ricardo Leitner if (!asoc) { 73430ccdf3c7SMarcelo Ricardo Leitner retval = -EINVAL; 73440ccdf3c7SMarcelo Ricardo Leitner goto out; 73450ccdf3c7SMarcelo Ricardo Leitner } 73460ccdf3c7SMarcelo Ricardo Leitner 73470ccdf3c7SMarcelo Ricardo Leitner retval = sctp_sched_get_value(asoc, params.stream_id, 73480ccdf3c7SMarcelo Ricardo Leitner ¶ms.stream_value); 73490ccdf3c7SMarcelo Ricardo Leitner if (retval) 73500ccdf3c7SMarcelo Ricardo Leitner goto out; 73510ccdf3c7SMarcelo Ricardo Leitner 73520ccdf3c7SMarcelo Ricardo Leitner if (put_user(len, optlen)) { 73530ccdf3c7SMarcelo Ricardo Leitner retval = -EFAULT; 73540ccdf3c7SMarcelo Ricardo Leitner goto out; 73550ccdf3c7SMarcelo Ricardo Leitner } 73560ccdf3c7SMarcelo Ricardo Leitner 73570ccdf3c7SMarcelo Ricardo Leitner if (copy_to_user(optval, ¶ms, len)) { 73580ccdf3c7SMarcelo Ricardo Leitner retval = -EFAULT; 73590ccdf3c7SMarcelo Ricardo Leitner goto out; 73600ccdf3c7SMarcelo Ricardo Leitner } 73610ccdf3c7SMarcelo Ricardo Leitner 73620ccdf3c7SMarcelo Ricardo Leitner out: 73630ccdf3c7SMarcelo Ricardo Leitner return retval; 73640ccdf3c7SMarcelo Ricardo Leitner } 73650ccdf3c7SMarcelo Ricardo Leitner 7366772a5869SXin Long static int sctp_getsockopt_interleaving_supported(struct sock *sk, int len, 7367772a5869SXin Long char __user *optval, 7368772a5869SXin Long int __user *optlen) 7369772a5869SXin Long { 7370772a5869SXin Long struct sctp_assoc_value params; 7371772a5869SXin Long struct sctp_association *asoc; 7372772a5869SXin Long int retval = -EFAULT; 7373772a5869SXin Long 7374772a5869SXin Long if (len < sizeof(params)) { 7375772a5869SXin Long retval = -EINVAL; 7376772a5869SXin Long goto out; 7377772a5869SXin Long } 7378772a5869SXin Long 7379772a5869SXin Long len = sizeof(params); 7380772a5869SXin Long if (copy_from_user(¶ms, optval, len)) 7381772a5869SXin Long goto out; 7382772a5869SXin Long 7383772a5869SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7384772a5869SXin Long if (asoc) { 7385772a5869SXin Long params.assoc_value = asoc->intl_enable; 7386772a5869SXin Long } else if (!params.assoc_id) { 7387772a5869SXin Long struct sctp_sock *sp = sctp_sk(sk); 7388772a5869SXin Long 7389772a5869SXin Long params.assoc_value = sp->strm_interleave; 7390772a5869SXin Long } else { 7391772a5869SXin Long retval = -EINVAL; 7392772a5869SXin Long goto out; 7393772a5869SXin Long } 7394772a5869SXin Long 7395772a5869SXin Long if (put_user(len, optlen)) 7396772a5869SXin Long goto out; 7397772a5869SXin Long 7398772a5869SXin Long if (copy_to_user(optval, ¶ms, len)) 7399772a5869SXin Long goto out; 7400772a5869SXin Long 7401772a5869SXin Long retval = 0; 7402772a5869SXin Long 7403772a5869SXin Long out: 7404772a5869SXin Long return retval; 7405772a5869SXin Long } 7406772a5869SXin Long 7407b0e9a2feSXin Long static int sctp_getsockopt_reuse_port(struct sock *sk, int len, 7408b0e9a2feSXin Long char __user *optval, 7409b0e9a2feSXin Long int __user *optlen) 7410b0e9a2feSXin Long { 7411b0e9a2feSXin Long int val; 7412b0e9a2feSXin Long 7413b0e9a2feSXin Long if (len < sizeof(int)) 7414b0e9a2feSXin Long return -EINVAL; 7415b0e9a2feSXin Long 7416b0e9a2feSXin Long len = sizeof(int); 7417b0e9a2feSXin Long val = sctp_sk(sk)->reuse; 7418b0e9a2feSXin Long if (put_user(len, optlen)) 7419b0e9a2feSXin Long return -EFAULT; 7420b0e9a2feSXin Long 7421b0e9a2feSXin Long if (copy_to_user(optval, &val, len)) 7422b0e9a2feSXin Long return -EFAULT; 7423b0e9a2feSXin Long 7424b0e9a2feSXin Long return 0; 7425b0e9a2feSXin Long } 7426b0e9a2feSXin Long 7427dda91928SDaniel Borkmann static int sctp_getsockopt(struct sock *sk, int level, int optname, 74281da177e4SLinus Torvalds char __user *optval, int __user *optlen) 74291da177e4SLinus Torvalds { 74301da177e4SLinus Torvalds int retval = 0; 74311da177e4SLinus Torvalds int len; 74321da177e4SLinus Torvalds 7433bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 74341da177e4SLinus Torvalds 74351da177e4SLinus Torvalds /* I can hardly begin to describe how wrong this is. This is 74361da177e4SLinus Torvalds * so broken as to be worse than useless. The API draft 74371da177e4SLinus Torvalds * REALLY is NOT helpful here... I am not convinced that the 74381da177e4SLinus Torvalds * semantics of getsockopt() with a level OTHER THAN SOL_SCTP 74391da177e4SLinus Torvalds * are at all well-founded. 74401da177e4SLinus Torvalds */ 74411da177e4SLinus Torvalds if (level != SOL_SCTP) { 74421da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 74431da177e4SLinus Torvalds 74441da177e4SLinus Torvalds retval = af->getsockopt(sk, level, optname, optval, optlen); 74451da177e4SLinus Torvalds return retval; 74461da177e4SLinus Torvalds } 74471da177e4SLinus Torvalds 74481da177e4SLinus Torvalds if (get_user(len, optlen)) 74491da177e4SLinus Torvalds return -EFAULT; 74501da177e4SLinus Torvalds 7451a4b8e71bSJiri Slaby if (len < 0) 7452a4b8e71bSJiri Slaby return -EINVAL; 7453a4b8e71bSJiri Slaby 7454048ed4b6Swangweidong lock_sock(sk); 74551da177e4SLinus Torvalds 74561da177e4SLinus Torvalds switch (optname) { 74571da177e4SLinus Torvalds case SCTP_STATUS: 74581da177e4SLinus Torvalds retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); 74591da177e4SLinus Torvalds break; 74601da177e4SLinus Torvalds case SCTP_DISABLE_FRAGMENTS: 74611da177e4SLinus Torvalds retval = sctp_getsockopt_disable_fragments(sk, len, optval, 74621da177e4SLinus Torvalds optlen); 74631da177e4SLinus Torvalds break; 74641da177e4SLinus Torvalds case SCTP_EVENTS: 74651da177e4SLinus Torvalds retval = sctp_getsockopt_events(sk, len, optval, optlen); 74661da177e4SLinus Torvalds break; 74671da177e4SLinus Torvalds case SCTP_AUTOCLOSE: 74681da177e4SLinus Torvalds retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); 74691da177e4SLinus Torvalds break; 74701da177e4SLinus Torvalds case SCTP_SOCKOPT_PEELOFF: 74711da177e4SLinus Torvalds retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); 74721da177e4SLinus Torvalds break; 74732cb5c8e3SNeil Horman case SCTP_SOCKOPT_PEELOFF_FLAGS: 74742cb5c8e3SNeil Horman retval = sctp_getsockopt_peeloff_flags(sk, len, optval, optlen); 74752cb5c8e3SNeil Horman break; 74761da177e4SLinus Torvalds case SCTP_PEER_ADDR_PARAMS: 74771da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addr_params(sk, len, optval, 74781da177e4SLinus Torvalds optlen); 74791da177e4SLinus Torvalds break; 74804580ccc0SShan Wei case SCTP_DELAYED_SACK: 7481d364d927SWei Yongjun retval = sctp_getsockopt_delayed_ack(sk, len, optval, 74827708610bSFrank Filz optlen); 74837708610bSFrank Filz break; 74841da177e4SLinus Torvalds case SCTP_INITMSG: 74851da177e4SLinus Torvalds retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); 74861da177e4SLinus Torvalds break; 74871da177e4SLinus Torvalds case SCTP_GET_PEER_ADDRS: 74881da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addrs(sk, len, optval, 74891da177e4SLinus Torvalds optlen); 74901da177e4SLinus Torvalds break; 74911da177e4SLinus Torvalds case SCTP_GET_LOCAL_ADDRS: 74921da177e4SLinus Torvalds retval = sctp_getsockopt_local_addrs(sk, len, optval, 74931da177e4SLinus Torvalds optlen); 74941da177e4SLinus Torvalds break; 7495c6ba68a2SVlad Yasevich case SCTP_SOCKOPT_CONNECTX3: 7496c6ba68a2SVlad Yasevich retval = sctp_getsockopt_connectx3(sk, len, optval, optlen); 7497c6ba68a2SVlad Yasevich break; 74981da177e4SLinus Torvalds case SCTP_DEFAULT_SEND_PARAM: 74991da177e4SLinus Torvalds retval = sctp_getsockopt_default_send_param(sk, len, 75001da177e4SLinus Torvalds optval, optlen); 75011da177e4SLinus Torvalds break; 75026b3fd5f3SGeir Ola Vaagland case SCTP_DEFAULT_SNDINFO: 75036b3fd5f3SGeir Ola Vaagland retval = sctp_getsockopt_default_sndinfo(sk, len, 75046b3fd5f3SGeir Ola Vaagland optval, optlen); 75056b3fd5f3SGeir Ola Vaagland break; 75061da177e4SLinus Torvalds case SCTP_PRIMARY_ADDR: 75071da177e4SLinus Torvalds retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); 75081da177e4SLinus Torvalds break; 75091da177e4SLinus Torvalds case SCTP_NODELAY: 75101da177e4SLinus Torvalds retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); 75111da177e4SLinus Torvalds break; 75121da177e4SLinus Torvalds case SCTP_RTOINFO: 75131da177e4SLinus Torvalds retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen); 75141da177e4SLinus Torvalds break; 75151da177e4SLinus Torvalds case SCTP_ASSOCINFO: 75161da177e4SLinus Torvalds retval = sctp_getsockopt_associnfo(sk, len, optval, optlen); 75171da177e4SLinus Torvalds break; 75181da177e4SLinus Torvalds case SCTP_I_WANT_MAPPED_V4_ADDR: 75191da177e4SLinus Torvalds retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); 75201da177e4SLinus Torvalds break; 75211da177e4SLinus Torvalds case SCTP_MAXSEG: 75221da177e4SLinus Torvalds retval = sctp_getsockopt_maxseg(sk, len, optval, optlen); 75231da177e4SLinus Torvalds break; 75241da177e4SLinus Torvalds case SCTP_GET_PEER_ADDR_INFO: 75251da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addr_info(sk, len, optval, 75261da177e4SLinus Torvalds optlen); 75271da177e4SLinus Torvalds break; 75280f3fffd8SIvan Skytte Jorgensen case SCTP_ADAPTATION_LAYER: 75290f3fffd8SIvan Skytte Jorgensen retval = sctp_getsockopt_adaptation_layer(sk, len, optval, 75301da177e4SLinus Torvalds optlen); 75311da177e4SLinus Torvalds break; 75326ab792f5SIvan Skytte Jorgensen case SCTP_CONTEXT: 75336ab792f5SIvan Skytte Jorgensen retval = sctp_getsockopt_context(sk, len, optval, optlen); 75346ab792f5SIvan Skytte Jorgensen break; 7535b6e1331fSVlad Yasevich case SCTP_FRAGMENT_INTERLEAVE: 7536b6e1331fSVlad Yasevich retval = sctp_getsockopt_fragment_interleave(sk, len, optval, 7537b6e1331fSVlad Yasevich optlen); 7538b6e1331fSVlad Yasevich break; 7539d49d91d7SVlad Yasevich case SCTP_PARTIAL_DELIVERY_POINT: 7540d49d91d7SVlad Yasevich retval = sctp_getsockopt_partial_delivery_point(sk, len, optval, 7541d49d91d7SVlad Yasevich optlen); 7542d49d91d7SVlad Yasevich break; 754370331571SVlad Yasevich case SCTP_MAX_BURST: 754470331571SVlad Yasevich retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); 754570331571SVlad Yasevich break; 754665b07e5dSVlad Yasevich case SCTP_AUTH_KEY: 754765b07e5dSVlad Yasevich case SCTP_AUTH_CHUNK: 754865b07e5dSVlad Yasevich case SCTP_AUTH_DELETE_KEY: 7549601590ecSXin Long case SCTP_AUTH_DEACTIVATE_KEY: 755065b07e5dSVlad Yasevich retval = -EOPNOTSUPP; 755165b07e5dSVlad Yasevich break; 755265b07e5dSVlad Yasevich case SCTP_HMAC_IDENT: 755365b07e5dSVlad Yasevich retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen); 755465b07e5dSVlad Yasevich break; 755565b07e5dSVlad Yasevich case SCTP_AUTH_ACTIVE_KEY: 755665b07e5dSVlad Yasevich retval = sctp_getsockopt_active_key(sk, len, optval, optlen); 755765b07e5dSVlad Yasevich break; 755865b07e5dSVlad Yasevich case SCTP_PEER_AUTH_CHUNKS: 755965b07e5dSVlad Yasevich retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval, 756065b07e5dSVlad Yasevich optlen); 756165b07e5dSVlad Yasevich break; 756265b07e5dSVlad Yasevich case SCTP_LOCAL_AUTH_CHUNKS: 756365b07e5dSVlad Yasevich retval = sctp_getsockopt_local_auth_chunks(sk, len, optval, 756465b07e5dSVlad Yasevich optlen); 756565b07e5dSVlad Yasevich break; 7566aea3c5c0SWei Yongjun case SCTP_GET_ASSOC_NUMBER: 7567aea3c5c0SWei Yongjun retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); 7568aea3c5c0SWei Yongjun break; 7569209ba424SWei Yongjun case SCTP_GET_ASSOC_ID_LIST: 7570209ba424SWei Yongjun retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); 7571209ba424SWei Yongjun break; 75727dc04d71SMichio Honda case SCTP_AUTO_ASCONF: 75737dc04d71SMichio Honda retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); 75747dc04d71SMichio Honda break; 75755aa93bcfSNeil Horman case SCTP_PEER_ADDR_THLDS: 75765aa93bcfSNeil Horman retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); 75775aa93bcfSNeil Horman break; 7578196d6759SMichele Baldessari case SCTP_GET_ASSOC_STATS: 7579196d6759SMichele Baldessari retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); 7580196d6759SMichele Baldessari break; 75810d3a421dSGeir Ola Vaagland case SCTP_RECVRCVINFO: 75820d3a421dSGeir Ola Vaagland retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); 75830d3a421dSGeir Ola Vaagland break; 75842347c80fSGeir Ola Vaagland case SCTP_RECVNXTINFO: 75852347c80fSGeir Ola Vaagland retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen); 75862347c80fSGeir Ola Vaagland break; 758728aa4c26SXin Long case SCTP_PR_SUPPORTED: 758828aa4c26SXin Long retval = sctp_getsockopt_pr_supported(sk, len, optval, optlen); 758928aa4c26SXin Long break; 7590f959fb44SXin Long case SCTP_DEFAULT_PRINFO: 7591f959fb44SXin Long retval = sctp_getsockopt_default_prinfo(sk, len, optval, 7592f959fb44SXin Long optlen); 7593f959fb44SXin Long break; 7594826d253dSXin Long case SCTP_PR_ASSOC_STATUS: 7595826d253dSXin Long retval = sctp_getsockopt_pr_assocstatus(sk, len, optval, 7596826d253dSXin Long optlen); 7597826d253dSXin Long break; 7598d229d48dSXin Long case SCTP_PR_STREAM_STATUS: 7599d229d48dSXin Long retval = sctp_getsockopt_pr_streamstatus(sk, len, optval, 7600d229d48dSXin Long optlen); 7601d229d48dSXin Long break; 7602c0d8bab6SXin Long case SCTP_RECONFIG_SUPPORTED: 7603c0d8bab6SXin Long retval = sctp_getsockopt_reconfig_supported(sk, len, optval, 7604c0d8bab6SXin Long optlen); 7605c0d8bab6SXin Long break; 76069fb657aeSXin Long case SCTP_ENABLE_STREAM_RESET: 76079fb657aeSXin Long retval = sctp_getsockopt_enable_strreset(sk, len, optval, 76089fb657aeSXin Long optlen); 76099fb657aeSXin Long break; 761013aa8770SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER: 761113aa8770SMarcelo Ricardo Leitner retval = sctp_getsockopt_scheduler(sk, len, optval, 761213aa8770SMarcelo Ricardo Leitner optlen); 761313aa8770SMarcelo Ricardo Leitner break; 76140ccdf3c7SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER_VALUE: 76150ccdf3c7SMarcelo Ricardo Leitner retval = sctp_getsockopt_scheduler_value(sk, len, optval, 76160ccdf3c7SMarcelo Ricardo Leitner optlen); 76170ccdf3c7SMarcelo Ricardo Leitner break; 7618772a5869SXin Long case SCTP_INTERLEAVING_SUPPORTED: 7619772a5869SXin Long retval = sctp_getsockopt_interleaving_supported(sk, len, optval, 7620772a5869SXin Long optlen); 7621772a5869SXin Long break; 7622b0e9a2feSXin Long case SCTP_REUSE_PORT: 7623b0e9a2feSXin Long retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen); 7624b0e9a2feSXin Long break; 76251da177e4SLinus Torvalds default: 76261da177e4SLinus Torvalds retval = -ENOPROTOOPT; 76271da177e4SLinus Torvalds break; 76283ff50b79SStephen Hemminger } 76291da177e4SLinus Torvalds 7630048ed4b6Swangweidong release_sock(sk); 76311da177e4SLinus Torvalds return retval; 76321da177e4SLinus Torvalds } 76331da177e4SLinus Torvalds 7634086c653fSCraig Gallek static int sctp_hash(struct sock *sk) 76351da177e4SLinus Torvalds { 76361da177e4SLinus Torvalds /* STUB */ 7637086c653fSCraig Gallek return 0; 76381da177e4SLinus Torvalds } 76391da177e4SLinus Torvalds 76401da177e4SLinus Torvalds static void sctp_unhash(struct sock *sk) 76411da177e4SLinus Torvalds { 76421da177e4SLinus Torvalds /* STUB */ 76431da177e4SLinus Torvalds } 76441da177e4SLinus Torvalds 76451da177e4SLinus Torvalds /* Check if port is acceptable. Possibly find first available port. 76461da177e4SLinus Torvalds * 76471da177e4SLinus Torvalds * The port hash table (contained in the 'global' SCTP protocol storage 76481da177e4SLinus Torvalds * returned by struct sctp_protocol *sctp_get_protocol()). The hash 76491da177e4SLinus Torvalds * table is an array of 4096 lists (sctp_bind_hashbucket). Each 76501da177e4SLinus Torvalds * list (the list number is the port number hashed out, so as you 76511da177e4SLinus Torvalds * would expect from a hash function, all the ports in a given list have 76521da177e4SLinus Torvalds * such a number that hashes out to the same list number; you were 76531da177e4SLinus Torvalds * expecting that, right?); so each list has a set of ports, with a 76541da177e4SLinus Torvalds * link to the socket (struct sock) that uses it, the port number and 76551da177e4SLinus Torvalds * a fastreuse flag (FIXME: NPI ipg). 76561da177e4SLinus Torvalds */ 76571da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create( 7658f1f43763SEric W. Biederman struct sctp_bind_hashbucket *head, struct net *, unsigned short snum); 76591da177e4SLinus Torvalds 76601da177e4SLinus Torvalds static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) 76611da177e4SLinus Torvalds { 7662b0e9a2feSXin Long bool reuse = (sk->sk_reuse || sctp_sk(sk)->reuse); 76631da177e4SLinus Torvalds struct sctp_bind_hashbucket *head; /* hash list */ 7664b67bfe0dSSasha Levin struct sctp_bind_bucket *pp; 76651da177e4SLinus Torvalds unsigned short snum; 76661da177e4SLinus Torvalds int ret; 76671da177e4SLinus Torvalds 766804afd8b2SAl Viro snum = ntohs(addr->v4.sin_port); 76691da177e4SLinus Torvalds 7670bb33381dSDaniel Borkmann pr_debug("%s: begins, snum:%d\n", __func__, snum); 7671bb33381dSDaniel Borkmann 767279b91130Swangweidong local_bh_disable(); 76731da177e4SLinus Torvalds 76741da177e4SLinus Torvalds if (snum == 0) { 767506393009SStephen Hemminger /* Search for an available port. */ 7676227b60f5SStephen Hemminger int low, high, remaining, index; 7677227b60f5SStephen Hemminger unsigned int rover; 7678122ff243SWANG Cong struct net *net = sock_net(sk); 7679227b60f5SStephen Hemminger 7680122ff243SWANG Cong inet_get_local_port_range(net, &low, &high); 7681227b60f5SStephen Hemminger remaining = (high - low) + 1; 768263862b5bSAruna-Hewapathirane rover = prandom_u32() % remaining + low; 76831da177e4SLinus Torvalds 76841da177e4SLinus Torvalds do { 76851da177e4SLinus Torvalds rover++; 76861da177e4SLinus Torvalds if ((rover < low) || (rover > high)) 76871da177e4SLinus Torvalds rover = low; 7688122ff243SWANG Cong if (inet_is_local_reserved_port(net, rover)) 7689e3826f1eSAmerigo Wang continue; 7690f1f43763SEric W. Biederman index = sctp_phashfn(sock_net(sk), rover); 76911da177e4SLinus Torvalds head = &sctp_port_hashtable[index]; 76923c8e43baSwangweidong spin_lock(&head->lock); 7693b67bfe0dSSasha Levin sctp_for_each_hentry(pp, &head->chain) 7694f1f43763SEric W. Biederman if ((pp->port == rover) && 7695f1f43763SEric W. Biederman net_eq(sock_net(sk), pp->net)) 76961da177e4SLinus Torvalds goto next; 76971da177e4SLinus Torvalds break; 76981da177e4SLinus Torvalds next: 76993c8e43baSwangweidong spin_unlock(&head->lock); 77001da177e4SLinus Torvalds } while (--remaining > 0); 77011da177e4SLinus Torvalds 77021da177e4SLinus Torvalds /* Exhausted local port range during search? */ 77031da177e4SLinus Torvalds ret = 1; 77041da177e4SLinus Torvalds if (remaining <= 0) 77051da177e4SLinus Torvalds goto fail; 77061da177e4SLinus Torvalds 77071da177e4SLinus Torvalds /* OK, here is the one we will use. HEAD (the port 77081da177e4SLinus Torvalds * hash table list entry) is non-NULL and we hold it's 77091da177e4SLinus Torvalds * mutex. 77101da177e4SLinus Torvalds */ 77111da177e4SLinus Torvalds snum = rover; 77121da177e4SLinus Torvalds } else { 77131da177e4SLinus Torvalds /* We are given an specific port number; we verify 77141da177e4SLinus Torvalds * that it is not being used. If it is used, we will 77151da177e4SLinus Torvalds * exahust the search in the hash list corresponding 77161da177e4SLinus Torvalds * to the port number (snum) - we detect that with the 77171da177e4SLinus Torvalds * port iterator, pp being NULL. 77181da177e4SLinus Torvalds */ 7719f1f43763SEric W. Biederman head = &sctp_port_hashtable[sctp_phashfn(sock_net(sk), snum)]; 77203c8e43baSwangweidong spin_lock(&head->lock); 7721b67bfe0dSSasha Levin sctp_for_each_hentry(pp, &head->chain) { 7722f1f43763SEric W. Biederman if ((pp->port == snum) && net_eq(pp->net, sock_net(sk))) 77231da177e4SLinus Torvalds goto pp_found; 77241da177e4SLinus Torvalds } 77251da177e4SLinus Torvalds } 77261da177e4SLinus Torvalds pp = NULL; 77271da177e4SLinus Torvalds goto pp_not_found; 77281da177e4SLinus Torvalds pp_found: 77291da177e4SLinus Torvalds if (!hlist_empty(&pp->owner)) { 77301da177e4SLinus Torvalds /* We had a port hash table hit - there is an 77311da177e4SLinus Torvalds * available port (pp != NULL) and it is being 77321da177e4SLinus Torvalds * used by other socket (pp->owner not empty); that other 77331da177e4SLinus Torvalds * socket is going to be sk2. 77341da177e4SLinus Torvalds */ 77351da177e4SLinus Torvalds struct sock *sk2; 77361da177e4SLinus Torvalds 7737bb33381dSDaniel Borkmann pr_debug("%s: found a possible match\n", __func__); 7738bb33381dSDaniel Borkmann 7739b0e9a2feSXin Long if (pp->fastreuse && reuse && sk->sk_state != SCTP_SS_LISTENING) 77401da177e4SLinus Torvalds goto success; 77411da177e4SLinus Torvalds 77421da177e4SLinus Torvalds /* Run through the list of sockets bound to the port 77431da177e4SLinus Torvalds * (pp->port) [via the pointers bind_next and 77441da177e4SLinus Torvalds * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one, 77451da177e4SLinus Torvalds * we get the endpoint they describe and run through 77461da177e4SLinus Torvalds * the endpoint's list of IP (v4 or v6) addresses, 77471da177e4SLinus Torvalds * comparing each of the addresses with the address of 77481da177e4SLinus Torvalds * the socket sk. If we find a match, then that means 77491da177e4SLinus Torvalds * that this port/socket (sk) combination are already 77501da177e4SLinus Torvalds * in an endpoint. 77511da177e4SLinus Torvalds */ 7752b67bfe0dSSasha Levin sk_for_each_bound(sk2, &pp->owner) { 77531da177e4SLinus Torvalds struct sctp_endpoint *ep2; 77541da177e4SLinus Torvalds ep2 = sctp_sk(sk2)->ep; 77551da177e4SLinus Torvalds 77564e54064eSVlad Yasevich if (sk == sk2 || 7757b0e9a2feSXin Long (reuse && (sk2->sk_reuse || sctp_sk(sk2)->reuse) && 77584e54064eSVlad Yasevich sk2->sk_state != SCTP_SS_LISTENING)) 77591da177e4SLinus Torvalds continue; 77601da177e4SLinus Torvalds 77617dab83deSVlad Yasevich if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr, 77627dab83deSVlad Yasevich sctp_sk(sk2), sctp_sk(sk))) { 77631da177e4SLinus Torvalds ret = (long)sk2; 77641da177e4SLinus Torvalds goto fail_unlock; 77651da177e4SLinus Torvalds } 77661da177e4SLinus Torvalds } 7767bb33381dSDaniel Borkmann 7768bb33381dSDaniel Borkmann pr_debug("%s: found a match\n", __func__); 77691da177e4SLinus Torvalds } 77701da177e4SLinus Torvalds pp_not_found: 77711da177e4SLinus Torvalds /* If there was a hash table miss, create a new port. */ 77721da177e4SLinus Torvalds ret = 1; 7773f1f43763SEric W. Biederman if (!pp && !(pp = sctp_bucket_create(head, sock_net(sk), snum))) 77741da177e4SLinus Torvalds goto fail_unlock; 77751da177e4SLinus Torvalds 77761da177e4SLinus Torvalds /* In either case (hit or miss), make sure fastreuse is 1 only 77771da177e4SLinus Torvalds * if sk->sk_reuse is too (that is, if the caller requested 77781da177e4SLinus Torvalds * SO_REUSEADDR on this socket -sk-). 77791da177e4SLinus Torvalds */ 7780ce5325c1SVlad Yasevich if (hlist_empty(&pp->owner)) { 7781b0e9a2feSXin Long if (reuse && sk->sk_state != SCTP_SS_LISTENING) 7782ce5325c1SVlad Yasevich pp->fastreuse = 1; 7783ce5325c1SVlad Yasevich else 7784ce5325c1SVlad Yasevich pp->fastreuse = 0; 7785ce5325c1SVlad Yasevich } else if (pp->fastreuse && 7786b0e9a2feSXin Long (!reuse || sk->sk_state == SCTP_SS_LISTENING)) 77871da177e4SLinus Torvalds pp->fastreuse = 0; 77881da177e4SLinus Torvalds 77891da177e4SLinus Torvalds /* We are set, so fill up all the data in the hash table 77901da177e4SLinus Torvalds * entry, tie the socket list information with the rest of the 77911da177e4SLinus Torvalds * sockets FIXME: Blurry, NPI (ipg). 77921da177e4SLinus Torvalds */ 77931da177e4SLinus Torvalds success: 77941da177e4SLinus Torvalds if (!sctp_sk(sk)->bind_hash) { 7795c720c7e8SEric Dumazet inet_sk(sk)->inet_num = snum; 77961da177e4SLinus Torvalds sk_add_bind_node(sk, &pp->owner); 77971da177e4SLinus Torvalds sctp_sk(sk)->bind_hash = pp; 77981da177e4SLinus Torvalds } 77991da177e4SLinus Torvalds ret = 0; 78001da177e4SLinus Torvalds 78011da177e4SLinus Torvalds fail_unlock: 78023c8e43baSwangweidong spin_unlock(&head->lock); 78031da177e4SLinus Torvalds 78041da177e4SLinus Torvalds fail: 780579b91130Swangweidong local_bh_enable(); 78061da177e4SLinus Torvalds return ret; 78071da177e4SLinus Torvalds } 78081da177e4SLinus Torvalds 78091da177e4SLinus Torvalds /* Assign a 'snum' port to the socket. If snum == 0, an ephemeral 78101da177e4SLinus Torvalds * port is requested. 78111da177e4SLinus Torvalds */ 78121da177e4SLinus Torvalds static int sctp_get_port(struct sock *sk, unsigned short snum) 78131da177e4SLinus Torvalds { 78141da177e4SLinus Torvalds union sctp_addr addr; 78151da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 78161da177e4SLinus Torvalds 78171da177e4SLinus Torvalds /* Set up a dummy address struct from the sk. */ 78181da177e4SLinus Torvalds af->from_sk(&addr, sk); 78191da177e4SLinus Torvalds addr.v4.sin_port = htons(snum); 78201da177e4SLinus Torvalds 78211da177e4SLinus Torvalds /* Note: sk->sk_num gets filled in if ephemeral port request. */ 782262208f12SDaniel Borkmann return !!sctp_get_port_local(sk, &addr); 78231da177e4SLinus Torvalds } 78241da177e4SLinus Torvalds 78251da177e4SLinus Torvalds /* 78261da177e4SLinus Torvalds * Move a socket to LISTENING state. 78271da177e4SLinus Torvalds */ 7828dda91928SDaniel Borkmann static int sctp_listen_start(struct sock *sk, int backlog) 78291da177e4SLinus Torvalds { 78305e8f3f70SVlad Yasevich struct sctp_sock *sp = sctp_sk(sk); 78315e8f3f70SVlad Yasevich struct sctp_endpoint *ep = sp->ep; 78325821c769SHerbert Xu struct crypto_shash *tfm = NULL; 78333c68198eSNeil Horman char alg[32]; 78341da177e4SLinus Torvalds 78351da177e4SLinus Torvalds /* Allocate HMAC for generating cookie. */ 78363c68198eSNeil Horman if (!sp->hmac && sp->sctp_hmac_alg) { 78373c68198eSNeil Horman sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg); 78385821c769SHerbert Xu tfm = crypto_alloc_shash(alg, 0, 0); 78398dc4984aSVlad Yasevich if (IS_ERR(tfm)) { 7840e87cc472SJoe Perches net_info_ratelimited("failed to load transform for %s: %ld\n", 78413c68198eSNeil Horman sp->sctp_hmac_alg, PTR_ERR(tfm)); 78425e8f3f70SVlad Yasevich return -ENOSYS; 78435e8f3f70SVlad Yasevich } 78445e8f3f70SVlad Yasevich sctp_sk(sk)->hmac = tfm; 78455e8f3f70SVlad Yasevich } 78465e8f3f70SVlad Yasevich 78475e8f3f70SVlad Yasevich /* 78485e8f3f70SVlad Yasevich * If a bind() or sctp_bindx() is not called prior to a listen() 78495e8f3f70SVlad Yasevich * call that allows new associations to be accepted, the system 78505e8f3f70SVlad Yasevich * picks an ephemeral port and will choose an address set equivalent 78515e8f3f70SVlad Yasevich * to binding with a wildcard address. 78525e8f3f70SVlad Yasevich * 78535e8f3f70SVlad Yasevich * This is not currently spelled out in the SCTP sockets 78545e8f3f70SVlad Yasevich * extensions draft, but follows the practice as seen in TCP 78555e8f3f70SVlad Yasevich * sockets. 78565e8f3f70SVlad Yasevich * 78575e8f3f70SVlad Yasevich */ 7858cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_LISTENING); 78595e8f3f70SVlad Yasevich if (!ep->base.bind_addr.port) { 78605e8f3f70SVlad Yasevich if (sctp_autobind(sk)) 78615e8f3f70SVlad Yasevich return -EAGAIN; 78625e8f3f70SVlad Yasevich } else { 7863c720c7e8SEric Dumazet if (sctp_get_port(sk, inet_sk(sk)->inet_num)) { 7864cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_CLOSED); 78655e8f3f70SVlad Yasevich return -EADDRINUSE; 78665e8f3f70SVlad Yasevich } 78675e8f3f70SVlad Yasevich } 78685e8f3f70SVlad Yasevich 78695e8f3f70SVlad Yasevich sk->sk_max_ack_backlog = backlog; 78705e8f3f70SVlad Yasevich sctp_hash_endpoint(ep); 78715e8f3f70SVlad Yasevich return 0; 78725e8f3f70SVlad Yasevich } 78735e8f3f70SVlad Yasevich 78745e8f3f70SVlad Yasevich /* 78755e8f3f70SVlad Yasevich * 4.1.3 / 5.1.3 listen() 78765e8f3f70SVlad Yasevich * 78775e8f3f70SVlad Yasevich * By default, new associations are not accepted for UDP style sockets. 78785e8f3f70SVlad Yasevich * An application uses listen() to mark a socket as being able to 78795e8f3f70SVlad Yasevich * accept new associations. 78805e8f3f70SVlad Yasevich * 78815e8f3f70SVlad Yasevich * On TCP style sockets, applications use listen() to ready the SCTP 78825e8f3f70SVlad Yasevich * endpoint for accepting inbound associations. 78835e8f3f70SVlad Yasevich * 78845e8f3f70SVlad Yasevich * On both types of endpoints a backlog of '0' disables listening. 78855e8f3f70SVlad Yasevich * 78865e8f3f70SVlad Yasevich * Move a socket to LISTENING state. 78875e8f3f70SVlad Yasevich */ 78885e8f3f70SVlad Yasevich int sctp_inet_listen(struct socket *sock, int backlog) 78895e8f3f70SVlad Yasevich { 78905e8f3f70SVlad Yasevich struct sock *sk = sock->sk; 78915e8f3f70SVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 78925e8f3f70SVlad Yasevich int err = -EINVAL; 78935e8f3f70SVlad Yasevich 78945e8f3f70SVlad Yasevich if (unlikely(backlog < 0)) 78955e8f3f70SVlad Yasevich return err; 78965e8f3f70SVlad Yasevich 7897048ed4b6Swangweidong lock_sock(sk); 78985e8f3f70SVlad Yasevich 78995e8f3f70SVlad Yasevich /* Peeled-off sockets are not allowed to listen(). */ 79005e8f3f70SVlad Yasevich if (sctp_style(sk, UDP_HIGH_BANDWIDTH)) 79015e8f3f70SVlad Yasevich goto out; 79025e8f3f70SVlad Yasevich 79035e8f3f70SVlad Yasevich if (sock->state != SS_UNCONNECTED) 79045e8f3f70SVlad Yasevich goto out; 79055e8f3f70SVlad Yasevich 790634b2789fSXin Long if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED)) 790734b2789fSXin Long goto out; 790834b2789fSXin Long 79095e8f3f70SVlad Yasevich /* If backlog is zero, disable listening. */ 79105e8f3f70SVlad Yasevich if (!backlog) { 79115e8f3f70SVlad Yasevich if (sctp_sstate(sk, CLOSED)) 79125e8f3f70SVlad Yasevich goto out; 79135e8f3f70SVlad Yasevich 79145e8f3f70SVlad Yasevich err = 0; 79155e8f3f70SVlad Yasevich sctp_unhash_endpoint(ep); 79165e8f3f70SVlad Yasevich sk->sk_state = SCTP_SS_CLOSED; 7917b0e9a2feSXin Long if (sk->sk_reuse || sctp_sk(sk)->reuse) 79185e8f3f70SVlad Yasevich sctp_sk(sk)->bind_hash->fastreuse = 1; 79191da177e4SLinus Torvalds goto out; 79201da177e4SLinus Torvalds } 79211da177e4SLinus Torvalds 79225e8f3f70SVlad Yasevich /* If we are already listening, just update the backlog */ 79235e8f3f70SVlad Yasevich if (sctp_sstate(sk, LISTENING)) 79245e8f3f70SVlad Yasevich sk->sk_max_ack_backlog = backlog; 79255e8f3f70SVlad Yasevich else { 79265e8f3f70SVlad Yasevich err = sctp_listen_start(sk, backlog); 79271da177e4SLinus Torvalds if (err) 79285e8f3f70SVlad Yasevich goto out; 79295e8f3f70SVlad Yasevich } 79301da177e4SLinus Torvalds 79315e8f3f70SVlad Yasevich err = 0; 79321da177e4SLinus Torvalds out: 7933048ed4b6Swangweidong release_sock(sk); 79341da177e4SLinus Torvalds return err; 79351da177e4SLinus Torvalds } 79361da177e4SLinus Torvalds 79371da177e4SLinus Torvalds /* 79381da177e4SLinus Torvalds * This function is done by modeling the current datagram_poll() and the 79391da177e4SLinus Torvalds * tcp_poll(). Note that, based on these implementations, we don't 79401da177e4SLinus Torvalds * lock the socket in this function, even though it seems that, 79411da177e4SLinus Torvalds * ideally, locking or some other mechanisms can be used to ensure 79429bffc4acSNeil Horman * the integrity of the counters (sndbuf and wmem_alloc) used 79431da177e4SLinus Torvalds * in this place. We assume that we don't need locks either until proven 79441da177e4SLinus Torvalds * otherwise. 79451da177e4SLinus Torvalds * 79461da177e4SLinus Torvalds * Another thing to note is that we include the Async I/O support 79471da177e4SLinus Torvalds * here, again, by modeling the current TCP/UDP code. We don't have 79481da177e4SLinus Torvalds * a good way to test with it yet. 79491da177e4SLinus Torvalds */ 7950a11e1d43SLinus Torvalds __poll_t sctp_poll(struct file *file, struct socket *sock, poll_table *wait) 79511da177e4SLinus Torvalds { 79521da177e4SLinus Torvalds struct sock *sk = sock->sk; 79531da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 7954ade994f4SAl Viro __poll_t mask; 79551da177e4SLinus Torvalds 7956a11e1d43SLinus Torvalds poll_wait(file, sk_sleep(sk), wait); 7957a11e1d43SLinus Torvalds 7958486bdee0SMarcelo Ricardo Leitner sock_rps_record_flow(sk); 7959486bdee0SMarcelo Ricardo Leitner 79601da177e4SLinus Torvalds /* A TCP-style listening socket becomes readable when the accept queue 79611da177e4SLinus Torvalds * is not empty. 79621da177e4SLinus Torvalds */ 79631da177e4SLinus Torvalds if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 79641da177e4SLinus Torvalds return (!list_empty(&sp->ep->asocs)) ? 7965a9a08845SLinus Torvalds (EPOLLIN | EPOLLRDNORM) : 0; 79661da177e4SLinus Torvalds 79671da177e4SLinus Torvalds mask = 0; 79681da177e4SLinus Torvalds 79691da177e4SLinus Torvalds /* Is there any exceptional events? */ 79701da177e4SLinus Torvalds if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) 7971a9a08845SLinus Torvalds mask |= EPOLLERR | 7972a9a08845SLinus Torvalds (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0); 7973f348d70aSDavide Libenzi if (sk->sk_shutdown & RCV_SHUTDOWN) 7974a9a08845SLinus Torvalds mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; 79751da177e4SLinus Torvalds if (sk->sk_shutdown == SHUTDOWN_MASK) 7976a9a08845SLinus Torvalds mask |= EPOLLHUP; 79771da177e4SLinus Torvalds 79781da177e4SLinus Torvalds /* Is it readable? Reconsider this code with TCP-style support. */ 7979db40980fSEric Dumazet if (!skb_queue_empty(&sk->sk_receive_queue)) 7980a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 79811da177e4SLinus Torvalds 79821da177e4SLinus Torvalds /* The association is either gone or not ready. */ 79831da177e4SLinus Torvalds if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED)) 79841da177e4SLinus Torvalds return mask; 79851da177e4SLinus Torvalds 79861da177e4SLinus Torvalds /* Is it writable? */ 79871da177e4SLinus Torvalds if (sctp_writeable(sk)) { 7988a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 79891da177e4SLinus Torvalds } else { 79909cd3e072SEric Dumazet sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 79911da177e4SLinus Torvalds /* 79921da177e4SLinus Torvalds * Since the socket is not locked, the buffer 79931da177e4SLinus Torvalds * might be made available after the writeable check and 79941da177e4SLinus Torvalds * before the bit is set. This could cause a lost I/O 79951da177e4SLinus Torvalds * signal. tcp_poll() has a race breaker for this race 79961da177e4SLinus Torvalds * condition. Based on their implementation, we put 79971da177e4SLinus Torvalds * in the following code to cover it as well. 79981da177e4SLinus Torvalds */ 79991da177e4SLinus Torvalds if (sctp_writeable(sk)) 8000a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 80011da177e4SLinus Torvalds } 80021da177e4SLinus Torvalds return mask; 80031da177e4SLinus Torvalds } 80041da177e4SLinus Torvalds 80051da177e4SLinus Torvalds /******************************************************************** 80061da177e4SLinus Torvalds * 2nd Level Abstractions 80071da177e4SLinus Torvalds ********************************************************************/ 80081da177e4SLinus Torvalds 80091da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create( 8010f1f43763SEric W. Biederman struct sctp_bind_hashbucket *head, struct net *net, unsigned short snum) 80111da177e4SLinus Torvalds { 80121da177e4SLinus Torvalds struct sctp_bind_bucket *pp; 80131da177e4SLinus Torvalds 801454e6ecb2SChristoph Lameter pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC); 80151da177e4SLinus Torvalds if (pp) { 8016935a7f6eSLi Zefan SCTP_DBG_OBJCNT_INC(bind_bucket); 80171da177e4SLinus Torvalds pp->port = snum; 80181da177e4SLinus Torvalds pp->fastreuse = 0; 80191da177e4SLinus Torvalds INIT_HLIST_HEAD(&pp->owner); 8020f1f43763SEric W. Biederman pp->net = net; 8021d970dbf8SVlad Yasevich hlist_add_head(&pp->node, &head->chain); 80221da177e4SLinus Torvalds } 80231da177e4SLinus Torvalds return pp; 80241da177e4SLinus Torvalds } 80251da177e4SLinus Torvalds 80261da177e4SLinus Torvalds /* Caller must hold hashbucket lock for this tb with local BH disabled */ 80271da177e4SLinus Torvalds static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) 80281da177e4SLinus Torvalds { 802937fa6878SSridhar Samudrala if (pp && hlist_empty(&pp->owner)) { 8030d970dbf8SVlad Yasevich __hlist_del(&pp->node); 80311da177e4SLinus Torvalds kmem_cache_free(sctp_bucket_cachep, pp); 80321da177e4SLinus Torvalds SCTP_DBG_OBJCNT_DEC(bind_bucket); 80331da177e4SLinus Torvalds } 80341da177e4SLinus Torvalds } 80351da177e4SLinus Torvalds 80361da177e4SLinus Torvalds /* Release this socket's reference to a local port. */ 80371da177e4SLinus Torvalds static inline void __sctp_put_port(struct sock *sk) 80381da177e4SLinus Torvalds { 80391da177e4SLinus Torvalds struct sctp_bind_hashbucket *head = 8040f1f43763SEric W. Biederman &sctp_port_hashtable[sctp_phashfn(sock_net(sk), 8041f1f43763SEric W. Biederman inet_sk(sk)->inet_num)]; 80421da177e4SLinus Torvalds struct sctp_bind_bucket *pp; 80431da177e4SLinus Torvalds 80443c8e43baSwangweidong spin_lock(&head->lock); 80451da177e4SLinus Torvalds pp = sctp_sk(sk)->bind_hash; 80461da177e4SLinus Torvalds __sk_del_bind_node(sk); 80471da177e4SLinus Torvalds sctp_sk(sk)->bind_hash = NULL; 8048c720c7e8SEric Dumazet inet_sk(sk)->inet_num = 0; 80491da177e4SLinus Torvalds sctp_bucket_destroy(pp); 80503c8e43baSwangweidong spin_unlock(&head->lock); 80511da177e4SLinus Torvalds } 80521da177e4SLinus Torvalds 80531da177e4SLinus Torvalds void sctp_put_port(struct sock *sk) 80541da177e4SLinus Torvalds { 805579b91130Swangweidong local_bh_disable(); 80561da177e4SLinus Torvalds __sctp_put_port(sk); 805779b91130Swangweidong local_bh_enable(); 80581da177e4SLinus Torvalds } 80591da177e4SLinus Torvalds 80601da177e4SLinus Torvalds /* 80611da177e4SLinus Torvalds * The system picks an ephemeral port and choose an address set equivalent 80621da177e4SLinus Torvalds * to binding with a wildcard address. 80631da177e4SLinus Torvalds * One of those addresses will be the primary address for the association. 80641da177e4SLinus Torvalds * This automatically enables the multihoming capability of SCTP. 80651da177e4SLinus Torvalds */ 80661da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk) 80671da177e4SLinus Torvalds { 80681da177e4SLinus Torvalds union sctp_addr autoaddr; 80691da177e4SLinus Torvalds struct sctp_af *af; 80706fbfa9f9SAl Viro __be16 port; 80711da177e4SLinus Torvalds 80721da177e4SLinus Torvalds /* Initialize a local sockaddr structure to INADDR_ANY. */ 80731da177e4SLinus Torvalds af = sctp_sk(sk)->pf->af; 80741da177e4SLinus Torvalds 8075c720c7e8SEric Dumazet port = htons(inet_sk(sk)->inet_num); 80761da177e4SLinus Torvalds af->inaddr_any(&autoaddr, port); 80771da177e4SLinus Torvalds 80781da177e4SLinus Torvalds return sctp_do_bind(sk, &autoaddr, af->sockaddr_len); 80791da177e4SLinus Torvalds } 80801da177e4SLinus Torvalds 80811da177e4SLinus Torvalds /* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. 80821da177e4SLinus Torvalds * 80831da177e4SLinus Torvalds * From RFC 2292 80841da177e4SLinus Torvalds * 4.2 The cmsghdr Structure * 80851da177e4SLinus Torvalds * 80861da177e4SLinus Torvalds * When ancillary data is sent or received, any number of ancillary data 80871da177e4SLinus Torvalds * objects can be specified by the msg_control and msg_controllen members of 80881da177e4SLinus Torvalds * the msghdr structure, because each object is preceded by 80891da177e4SLinus Torvalds * a cmsghdr structure defining the object's length (the cmsg_len member). 80901da177e4SLinus Torvalds * Historically Berkeley-derived implementations have passed only one object 80911da177e4SLinus Torvalds * at a time, but this API allows multiple objects to be 80921da177e4SLinus Torvalds * passed in a single call to sendmsg() or recvmsg(). The following example 80931da177e4SLinus Torvalds * shows two ancillary data objects in a control buffer. 80941da177e4SLinus Torvalds * 80951da177e4SLinus Torvalds * |<--------------------------- msg_controllen -------------------------->| 80961da177e4SLinus Torvalds * | | 80971da177e4SLinus Torvalds * 80981da177e4SLinus Torvalds * |<----- ancillary data object ----->|<----- ancillary data object ----->| 80991da177e4SLinus Torvalds * 81001da177e4SLinus Torvalds * |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->| 81011da177e4SLinus Torvalds * | | | 81021da177e4SLinus Torvalds * 81031da177e4SLinus Torvalds * |<---------- cmsg_len ---------->| |<--------- cmsg_len ----------->| | 81041da177e4SLinus Torvalds * 81051da177e4SLinus Torvalds * |<--------- CMSG_LEN() --------->| |<-------- CMSG_LEN() ---------->| | 81061da177e4SLinus Torvalds * | | | | | 81071da177e4SLinus Torvalds * 81081da177e4SLinus Torvalds * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 81091da177e4SLinus Torvalds * |cmsg_|cmsg_|cmsg_|XX| |XX|cmsg_|cmsg_|cmsg_|XX| |XX| 81101da177e4SLinus Torvalds * 81111da177e4SLinus Torvalds * |len |level|type |XX|cmsg_data[]|XX|len |level|type |XX|cmsg_data[]|XX| 81121da177e4SLinus Torvalds * 81131da177e4SLinus Torvalds * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 81141da177e4SLinus Torvalds * ^ 81151da177e4SLinus Torvalds * | 81161da177e4SLinus Torvalds * 81171da177e4SLinus Torvalds * msg_control 81181da177e4SLinus Torvalds * points here 81191da177e4SLinus Torvalds */ 8120a05437acSXin Long static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs) 81211da177e4SLinus Torvalds { 8122ab38fb04SVlad Yasevich struct msghdr *my_msg = (struct msghdr *)msg; 8123a05437acSXin Long struct cmsghdr *cmsg; 81241da177e4SLinus Torvalds 8125f95b414eSGu Zheng for_each_cmsghdr(cmsg, my_msg) { 8126ab38fb04SVlad Yasevich if (!CMSG_OK(my_msg, cmsg)) 81271da177e4SLinus Torvalds return -EINVAL; 81281da177e4SLinus Torvalds 81291da177e4SLinus Torvalds /* Should we parse this header or ignore? */ 81301da177e4SLinus Torvalds if (cmsg->cmsg_level != IPPROTO_SCTP) 81311da177e4SLinus Torvalds continue; 81321da177e4SLinus Torvalds 81331da177e4SLinus Torvalds /* Strictly check lengths following example in SCM code. */ 81341da177e4SLinus Torvalds switch (cmsg->cmsg_type) { 81351da177e4SLinus Torvalds case SCTP_INIT: 81361da177e4SLinus Torvalds /* SCTP Socket API Extension 813763b94938SGeir Ola Vaagland * 5.3.1 SCTP Initiation Structure (SCTP_INIT) 81381da177e4SLinus Torvalds * 81391da177e4SLinus Torvalds * This cmsghdr structure provides information for 81401da177e4SLinus Torvalds * initializing new SCTP associations with sendmsg(). 81411da177e4SLinus Torvalds * The SCTP_INITMSG socket option uses this same data 81421da177e4SLinus Torvalds * structure. This structure is not used for 81431da177e4SLinus Torvalds * recvmsg(). 81441da177e4SLinus Torvalds * 81451da177e4SLinus Torvalds * cmsg_level cmsg_type cmsg_data[] 81461da177e4SLinus Torvalds * ------------ ------------ ---------------------- 81471da177e4SLinus Torvalds * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg 81481da177e4SLinus Torvalds */ 814963b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg))) 81501da177e4SLinus Torvalds return -EINVAL; 815163b94938SGeir Ola Vaagland 815263b94938SGeir Ola Vaagland cmsgs->init = CMSG_DATA(cmsg); 81531da177e4SLinus Torvalds break; 81541da177e4SLinus Torvalds 81551da177e4SLinus Torvalds case SCTP_SNDRCV: 81561da177e4SLinus Torvalds /* SCTP Socket API Extension 815763b94938SGeir Ola Vaagland * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV) 81581da177e4SLinus Torvalds * 81591da177e4SLinus Torvalds * This cmsghdr structure specifies SCTP options for 81601da177e4SLinus Torvalds * sendmsg() and describes SCTP header information 81611da177e4SLinus Torvalds * about a received message through recvmsg(). 81621da177e4SLinus Torvalds * 81631da177e4SLinus Torvalds * cmsg_level cmsg_type cmsg_data[] 81641da177e4SLinus Torvalds * ------------ ------------ ---------------------- 81651da177e4SLinus Torvalds * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo 81661da177e4SLinus Torvalds */ 816763b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) 81681da177e4SLinus Torvalds return -EINVAL; 81691da177e4SLinus Torvalds 817063b94938SGeir Ola Vaagland cmsgs->srinfo = CMSG_DATA(cmsg); 81711da177e4SLinus Torvalds 817263b94938SGeir Ola Vaagland if (cmsgs->srinfo->sinfo_flags & 8173eaa5c54dSIvan Skytte Jorgensen ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 817449102805SXin Long SCTP_SACK_IMMEDIATELY | SCTP_SENDALL | 817549102805SXin Long SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF)) 81761da177e4SLinus Torvalds return -EINVAL; 81771da177e4SLinus Torvalds break; 81781da177e4SLinus Torvalds 817963b94938SGeir Ola Vaagland case SCTP_SNDINFO: 818063b94938SGeir Ola Vaagland /* SCTP Socket API Extension 818163b94938SGeir Ola Vaagland * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) 818263b94938SGeir Ola Vaagland * 818363b94938SGeir Ola Vaagland * This cmsghdr structure specifies SCTP options for 818463b94938SGeir Ola Vaagland * sendmsg(). This structure and SCTP_RCVINFO replaces 818563b94938SGeir Ola Vaagland * SCTP_SNDRCV which has been deprecated. 818663b94938SGeir Ola Vaagland * 818763b94938SGeir Ola Vaagland * cmsg_level cmsg_type cmsg_data[] 818863b94938SGeir Ola Vaagland * ------------ ------------ --------------------- 818963b94938SGeir Ola Vaagland * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo 819063b94938SGeir Ola Vaagland */ 819163b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo))) 819263b94938SGeir Ola Vaagland return -EINVAL; 819363b94938SGeir Ola Vaagland 819463b94938SGeir Ola Vaagland cmsgs->sinfo = CMSG_DATA(cmsg); 819563b94938SGeir Ola Vaagland 819663b94938SGeir Ola Vaagland if (cmsgs->sinfo->snd_flags & 819763b94938SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 819849102805SXin Long SCTP_SACK_IMMEDIATELY | SCTP_SENDALL | 819949102805SXin Long SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF)) 820063b94938SGeir Ola Vaagland return -EINVAL; 820163b94938SGeir Ola Vaagland break; 8202ed63afb8SXin Long case SCTP_PRINFO: 8203ed63afb8SXin Long /* SCTP Socket API Extension 8204ed63afb8SXin Long * 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO) 8205ed63afb8SXin Long * 8206ed63afb8SXin Long * This cmsghdr structure specifies SCTP options for sendmsg(). 8207ed63afb8SXin Long * 8208ed63afb8SXin Long * cmsg_level cmsg_type cmsg_data[] 8209ed63afb8SXin Long * ------------ ------------ --------------------- 8210ed63afb8SXin Long * IPPROTO_SCTP SCTP_PRINFO struct sctp_prinfo 8211ed63afb8SXin Long */ 8212ed63afb8SXin Long if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_prinfo))) 8213ed63afb8SXin Long return -EINVAL; 8214ed63afb8SXin Long 8215ed63afb8SXin Long cmsgs->prinfo = CMSG_DATA(cmsg); 8216ed63afb8SXin Long if (cmsgs->prinfo->pr_policy & ~SCTP_PR_SCTP_MASK) 8217ed63afb8SXin Long return -EINVAL; 8218ed63afb8SXin Long 8219ed63afb8SXin Long if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE) 8220ed63afb8SXin Long cmsgs->prinfo->pr_value = 0; 8221ed63afb8SXin Long break; 82223ff547c0SXin Long case SCTP_AUTHINFO: 82233ff547c0SXin Long /* SCTP Socket API Extension 82243ff547c0SXin Long * 5.3.8 SCTP AUTH Information Structure (SCTP_AUTHINFO) 82253ff547c0SXin Long * 82263ff547c0SXin Long * This cmsghdr structure specifies SCTP options for sendmsg(). 82273ff547c0SXin Long * 82283ff547c0SXin Long * cmsg_level cmsg_type cmsg_data[] 82293ff547c0SXin Long * ------------ ------------ --------------------- 82303ff547c0SXin Long * IPPROTO_SCTP SCTP_AUTHINFO struct sctp_authinfo 82313ff547c0SXin Long */ 82323ff547c0SXin Long if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_authinfo))) 82333ff547c0SXin Long return -EINVAL; 82343ff547c0SXin Long 82353ff547c0SXin Long cmsgs->authinfo = CMSG_DATA(cmsg); 82363ff547c0SXin Long break; 82372c0dbaa0SXin Long case SCTP_DSTADDRV4: 82382c0dbaa0SXin Long case SCTP_DSTADDRV6: 82392c0dbaa0SXin Long /* SCTP Socket API Extension 82402c0dbaa0SXin Long * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6) 82412c0dbaa0SXin Long * 82422c0dbaa0SXin Long * This cmsghdr structure specifies SCTP options for sendmsg(). 82432c0dbaa0SXin Long * 82442c0dbaa0SXin Long * cmsg_level cmsg_type cmsg_data[] 82452c0dbaa0SXin Long * ------------ ------------ --------------------- 82462c0dbaa0SXin Long * IPPROTO_SCTP SCTP_DSTADDRV4 struct in_addr 82472c0dbaa0SXin Long * ------------ ------------ --------------------- 82482c0dbaa0SXin Long * IPPROTO_SCTP SCTP_DSTADDRV6 struct in6_addr 82492c0dbaa0SXin Long */ 82502c0dbaa0SXin Long cmsgs->addrs_msg = my_msg; 82512c0dbaa0SXin Long break; 82521da177e4SLinus Torvalds default: 82531da177e4SLinus Torvalds return -EINVAL; 82543ff50b79SStephen Hemminger } 82551da177e4SLinus Torvalds } 825663b94938SGeir Ola Vaagland 82571da177e4SLinus Torvalds return 0; 82581da177e4SLinus Torvalds } 82591da177e4SLinus Torvalds 82601da177e4SLinus Torvalds /* 82611da177e4SLinus Torvalds * Wait for a packet.. 82621da177e4SLinus Torvalds * Note: This function is the same function as in core/datagram.c 82631da177e4SLinus Torvalds * with a few modifications to make lksctp work. 82641da177e4SLinus Torvalds */ 82651da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p) 82661da177e4SLinus Torvalds { 82671da177e4SLinus Torvalds int error; 82681da177e4SLinus Torvalds DEFINE_WAIT(wait); 82691da177e4SLinus Torvalds 8270aa395145SEric Dumazet prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 82711da177e4SLinus Torvalds 82721da177e4SLinus Torvalds /* Socket errors? */ 82731da177e4SLinus Torvalds error = sock_error(sk); 82741da177e4SLinus Torvalds if (error) 82751da177e4SLinus Torvalds goto out; 82761da177e4SLinus Torvalds 82771da177e4SLinus Torvalds if (!skb_queue_empty(&sk->sk_receive_queue)) 82781da177e4SLinus Torvalds goto ready; 82791da177e4SLinus Torvalds 82801da177e4SLinus Torvalds /* Socket shut down? */ 82811da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 82821da177e4SLinus Torvalds goto out; 82831da177e4SLinus Torvalds 82841da177e4SLinus Torvalds /* Sequenced packets can come disconnected. If so we report the 82851da177e4SLinus Torvalds * problem. 82861da177e4SLinus Torvalds */ 82871da177e4SLinus Torvalds error = -ENOTCONN; 82881da177e4SLinus Torvalds 82891da177e4SLinus Torvalds /* Is there a good reason to think that we may receive some data? */ 82901da177e4SLinus Torvalds if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING)) 82911da177e4SLinus Torvalds goto out; 82921da177e4SLinus Torvalds 82931da177e4SLinus Torvalds /* Handle signals. */ 82941da177e4SLinus Torvalds if (signal_pending(current)) 82951da177e4SLinus Torvalds goto interrupted; 82961da177e4SLinus Torvalds 82971da177e4SLinus Torvalds /* Let another process have a go. Since we are going to sleep 82981da177e4SLinus Torvalds * anyway. Note: This may cause odd behaviors if the message 82991da177e4SLinus Torvalds * does not fit in the user's buffer, but this seems to be the 83001da177e4SLinus Torvalds * only way to honor MSG_DONTWAIT realistically. 83011da177e4SLinus Torvalds */ 8302048ed4b6Swangweidong release_sock(sk); 83031da177e4SLinus Torvalds *timeo_p = schedule_timeout(*timeo_p); 8304048ed4b6Swangweidong lock_sock(sk); 83051da177e4SLinus Torvalds 83061da177e4SLinus Torvalds ready: 8307aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 83081da177e4SLinus Torvalds return 0; 83091da177e4SLinus Torvalds 83101da177e4SLinus Torvalds interrupted: 83111da177e4SLinus Torvalds error = sock_intr_errno(*timeo_p); 83121da177e4SLinus Torvalds 83131da177e4SLinus Torvalds out: 8314aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 83151da177e4SLinus Torvalds *err = error; 83161da177e4SLinus Torvalds return error; 83171da177e4SLinus Torvalds } 83181da177e4SLinus Torvalds 83191da177e4SLinus Torvalds /* Receive a datagram. 83201da177e4SLinus Torvalds * Note: This is pretty much the same routine as in core/datagram.c 83211da177e4SLinus Torvalds * with a few changes to make lksctp work. 83221da177e4SLinus Torvalds */ 83232347c80fSGeir Ola Vaagland struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, 83241da177e4SLinus Torvalds int noblock, int *err) 83251da177e4SLinus Torvalds { 83261da177e4SLinus Torvalds int error; 83271da177e4SLinus Torvalds struct sk_buff *skb; 83281da177e4SLinus Torvalds long timeo; 83291da177e4SLinus Torvalds 83301da177e4SLinus Torvalds timeo = sock_rcvtimeo(sk, noblock); 83311da177e4SLinus Torvalds 8332bb33381dSDaniel Borkmann pr_debug("%s: timeo:%ld, max:%ld\n", __func__, timeo, 8333bb33381dSDaniel Borkmann MAX_SCHEDULE_TIMEOUT); 83341da177e4SLinus Torvalds 83351da177e4SLinus Torvalds do { 83361da177e4SLinus Torvalds /* Again only user level code calls this function, 83371da177e4SLinus Torvalds * so nothing interrupt level 83381da177e4SLinus Torvalds * will suddenly eat the receive_queue. 83391da177e4SLinus Torvalds * 83401da177e4SLinus Torvalds * Look at current nfs client by the way... 83418917a3c0SDavid Shwatrz * However, this function was correct in any case. 8) 83421da177e4SLinus Torvalds */ 83431da177e4SLinus Torvalds if (flags & MSG_PEEK) { 83441da177e4SLinus Torvalds skb = skb_peek(&sk->sk_receive_queue); 83451da177e4SLinus Torvalds if (skb) 834663354797SReshetova, Elena refcount_inc(&skb->users); 83471da177e4SLinus Torvalds } else { 8348311b2177SMarcelo Ricardo Leitner skb = __skb_dequeue(&sk->sk_receive_queue); 83491da177e4SLinus Torvalds } 83501da177e4SLinus Torvalds 83511da177e4SLinus Torvalds if (skb) 83521da177e4SLinus Torvalds return skb; 83531da177e4SLinus Torvalds 83546736dc35SNeil Horman /* Caller is allowed not to check sk->sk_err before calling. */ 83556736dc35SNeil Horman error = sock_error(sk); 83566736dc35SNeil Horman if (error) 83576736dc35SNeil Horman goto no_packet; 83586736dc35SNeil Horman 83591da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 83601da177e4SLinus Torvalds break; 83611da177e4SLinus Torvalds 83622b5cd0dfSAlexander Duyck if (sk_can_busy_loop(sk)) { 83632b5cd0dfSAlexander Duyck sk_busy_loop(sk, noblock); 83642b5cd0dfSAlexander Duyck 83652b5cd0dfSAlexander Duyck if (!skb_queue_empty(&sk->sk_receive_queue)) 83668465a5fcSNeil Horman continue; 83672b5cd0dfSAlexander Duyck } 83688465a5fcSNeil Horman 83691da177e4SLinus Torvalds /* User doesn't want to wait. */ 83701da177e4SLinus Torvalds error = -EAGAIN; 83711da177e4SLinus Torvalds if (!timeo) 83721da177e4SLinus Torvalds goto no_packet; 83731da177e4SLinus Torvalds } while (sctp_wait_for_packet(sk, err, &timeo) == 0); 83741da177e4SLinus Torvalds 83751da177e4SLinus Torvalds return NULL; 83761da177e4SLinus Torvalds 83771da177e4SLinus Torvalds no_packet: 83781da177e4SLinus Torvalds *err = error; 83791da177e4SLinus Torvalds return NULL; 83801da177e4SLinus Torvalds } 83811da177e4SLinus Torvalds 83821da177e4SLinus Torvalds /* If sndbuf has changed, wake up per association sndbuf waiters. */ 83831da177e4SLinus Torvalds static void __sctp_write_space(struct sctp_association *asoc) 83841da177e4SLinus Torvalds { 83851da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 83861da177e4SLinus Torvalds 8387ceb5d58bSEric Dumazet if (sctp_wspace(asoc) <= 0) 8388ceb5d58bSEric Dumazet return; 8389ceb5d58bSEric Dumazet 83901da177e4SLinus Torvalds if (waitqueue_active(&asoc->wait)) 83911da177e4SLinus Torvalds wake_up_interruptible(&asoc->wait); 83921da177e4SLinus Torvalds 83931da177e4SLinus Torvalds if (sctp_writeable(sk)) { 8394ceb5d58bSEric Dumazet struct socket_wq *wq; 8395eaefd110SEric Dumazet 8396ceb5d58bSEric Dumazet rcu_read_lock(); 8397ceb5d58bSEric Dumazet wq = rcu_dereference(sk->sk_wq); 8398ceb5d58bSEric Dumazet if (wq) { 8399ceb5d58bSEric Dumazet if (waitqueue_active(&wq->wait)) 8400ceb5d58bSEric Dumazet wake_up_interruptible(&wq->wait); 84011da177e4SLinus Torvalds 84021da177e4SLinus Torvalds /* Note that we try to include the Async I/O support 84031da177e4SLinus Torvalds * here by modeling from the current TCP/UDP code. 84041da177e4SLinus Torvalds * We have not tested with it yet. 84051da177e4SLinus Torvalds */ 8406eaefd110SEric Dumazet if (!(sk->sk_shutdown & SEND_SHUTDOWN)) 8407ceb5d58bSEric Dumazet sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT); 84081da177e4SLinus Torvalds } 8409ceb5d58bSEric Dumazet rcu_read_unlock(); 84101da177e4SLinus Torvalds } 84111da177e4SLinus Torvalds } 84121da177e4SLinus Torvalds 841352c35befSDaniel Borkmann static void sctp_wake_up_waiters(struct sock *sk, 841452c35befSDaniel Borkmann struct sctp_association *asoc) 841552c35befSDaniel Borkmann { 841652c35befSDaniel Borkmann struct sctp_association *tmp = asoc; 841752c35befSDaniel Borkmann 841852c35befSDaniel Borkmann /* We do accounting for the sndbuf space per association, 841952c35befSDaniel Borkmann * so we only need to wake our own association. 842052c35befSDaniel Borkmann */ 842152c35befSDaniel Borkmann if (asoc->ep->sndbuf_policy) 842252c35befSDaniel Borkmann return __sctp_write_space(asoc); 842352c35befSDaniel Borkmann 84241e1cdf8aSDaniel Borkmann /* If association goes down and is just flushing its 84251e1cdf8aSDaniel Borkmann * outq, then just normally notify others. 84261e1cdf8aSDaniel Borkmann */ 84271e1cdf8aSDaniel Borkmann if (asoc->base.dead) 84281e1cdf8aSDaniel Borkmann return sctp_write_space(sk); 84291e1cdf8aSDaniel Borkmann 843052c35befSDaniel Borkmann /* Accounting for the sndbuf space is per socket, so we 843152c35befSDaniel Borkmann * need to wake up others, try to be fair and in case of 843252c35befSDaniel Borkmann * other associations, let them have a go first instead 843352c35befSDaniel Borkmann * of just doing a sctp_write_space() call. 843452c35befSDaniel Borkmann * 843552c35befSDaniel Borkmann * Note that we reach sctp_wake_up_waiters() only when 843652c35befSDaniel Borkmann * associations free up queued chunks, thus we are under 843752c35befSDaniel Borkmann * lock and the list of associations on a socket is 843852c35befSDaniel Borkmann * guaranteed not to change. 843952c35befSDaniel Borkmann */ 844052c35befSDaniel Borkmann for (tmp = list_next_entry(tmp, asocs); 1; 844152c35befSDaniel Borkmann tmp = list_next_entry(tmp, asocs)) { 844252c35befSDaniel Borkmann /* Manually skip the head element. */ 844352c35befSDaniel Borkmann if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs)) 844452c35befSDaniel Borkmann continue; 844552c35befSDaniel Borkmann /* Wake up association. */ 844652c35befSDaniel Borkmann __sctp_write_space(tmp); 844752c35befSDaniel Borkmann /* We've reached the end. */ 844852c35befSDaniel Borkmann if (tmp == asoc) 844952c35befSDaniel Borkmann break; 845052c35befSDaniel Borkmann } 845152c35befSDaniel Borkmann } 845252c35befSDaniel Borkmann 84531da177e4SLinus Torvalds /* Do accounting for the sndbuf space. 84541da177e4SLinus Torvalds * Decrement the used sndbuf space of the corresponding association by the 84551da177e4SLinus Torvalds * data size which was just transmitted(freed). 84561da177e4SLinus Torvalds */ 84571da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb) 84581da177e4SLinus Torvalds { 8459f869c912SDaniel Borkmann struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg; 8460f869c912SDaniel Borkmann struct sctp_association *asoc = chunk->asoc; 8461f869c912SDaniel Borkmann struct sock *sk = asoc->base.sk; 84621da177e4SLinus Torvalds 84634eb701dfSNeil Horman asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) + 84644eb701dfSNeil Horman sizeof(struct sk_buff) + 84654eb701dfSNeil Horman sizeof(struct sctp_chunk); 84664eb701dfSNeil Horman 846714afee4bSReshetova, Elena WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc)); 84684eb701dfSNeil Horman 84694d93df0aSNeil Horman /* 84703ab224beSHideo Aoki * This undoes what is done via sctp_set_owner_w and sk_mem_charge 84714d93df0aSNeil Horman */ 84724d93df0aSNeil Horman sk->sk_wmem_queued -= skb->truesize; 84733ab224beSHideo Aoki sk_mem_uncharge(sk, skb->truesize); 84744d93df0aSNeil Horman 8475ec2e506cSXin Long if (chunk->shkey) { 8476ec2e506cSXin Long struct sctp_shared_key *shkey = chunk->shkey; 8477ec2e506cSXin Long 8478ec2e506cSXin Long /* refcnt == 2 and !list_empty mean after this release, it's 8479ec2e506cSXin Long * not being used anywhere, and it's time to notify userland 8480ec2e506cSXin Long * that this shkey can be freed if it's been deactivated. 8481ec2e506cSXin Long */ 8482ec2e506cSXin Long if (shkey->deactivated && !list_empty(&shkey->key_list) && 8483ec2e506cSXin Long refcount_read(&shkey->refcnt) == 2) { 8484ec2e506cSXin Long struct sctp_ulpevent *ev; 8485ec2e506cSXin Long 8486ec2e506cSXin Long ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id, 8487ec2e506cSXin Long SCTP_AUTH_FREE_KEY, 8488ec2e506cSXin Long GFP_KERNEL); 8489ec2e506cSXin Long if (ev) 8490ec2e506cSXin Long asoc->stream.si->enqueue_event(&asoc->ulpq, ev); 8491ec2e506cSXin Long } 84921b1e0bc9SXin Long sctp_auth_shkey_release(chunk->shkey); 8493ec2e506cSXin Long } 84941b1e0bc9SXin Long 84954eb701dfSNeil Horman sock_wfree(skb); 849652c35befSDaniel Borkmann sctp_wake_up_waiters(sk, asoc); 84971da177e4SLinus Torvalds 84981da177e4SLinus Torvalds sctp_association_put(asoc); 84991da177e4SLinus Torvalds } 85001da177e4SLinus Torvalds 8501331c4ee7SVlad Yasevich /* Do accounting for the receive space on the socket. 8502331c4ee7SVlad Yasevich * Accounting for the association is done in ulpevent.c 8503331c4ee7SVlad Yasevich * We set this as a destructor for the cloned data skbs so that 8504331c4ee7SVlad Yasevich * accounting is done at the correct time. 8505331c4ee7SVlad Yasevich */ 8506331c4ee7SVlad Yasevich void sctp_sock_rfree(struct sk_buff *skb) 8507331c4ee7SVlad Yasevich { 8508331c4ee7SVlad Yasevich struct sock *sk = skb->sk; 8509331c4ee7SVlad Yasevich struct sctp_ulpevent *event = sctp_skb2event(skb); 8510331c4ee7SVlad Yasevich 8511331c4ee7SVlad Yasevich atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); 85124d93df0aSNeil Horman 85134d93df0aSNeil Horman /* 85143ab224beSHideo Aoki * Mimic the behavior of sock_rfree 85154d93df0aSNeil Horman */ 85163ab224beSHideo Aoki sk_mem_uncharge(sk, event->rmem_len); 8517331c4ee7SVlad Yasevich } 8518331c4ee7SVlad Yasevich 8519331c4ee7SVlad Yasevich 85201da177e4SLinus Torvalds /* Helper function to wait for space in the sndbuf. */ 85211da177e4SLinus Torvalds static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 8522a0ff6600SXin Long size_t msg_len) 85231da177e4SLinus Torvalds { 85241da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 85251da177e4SLinus Torvalds long current_timeo = *timeo_p; 85261da177e4SLinus Torvalds DEFINE_WAIT(wait); 8527a0ff6600SXin Long int err = 0; 85281da177e4SLinus Torvalds 8529bb33381dSDaniel Borkmann pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc, 8530bb33381dSDaniel Borkmann *timeo_p, msg_len); 85311da177e4SLinus Torvalds 85321da177e4SLinus Torvalds /* Increment the association's refcnt. */ 85331da177e4SLinus Torvalds sctp_association_hold(asoc); 85341da177e4SLinus Torvalds 85351da177e4SLinus Torvalds /* Wait on the association specific sndbuf space. */ 85361da177e4SLinus Torvalds for (;;) { 85371da177e4SLinus Torvalds prepare_to_wait_exclusive(&asoc->wait, &wait, 85381da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 8539ca3af4ddSXin Long if (asoc->base.dead) 8540ca3af4ddSXin Long goto do_dead; 85411da177e4SLinus Torvalds if (!*timeo_p) 85421da177e4SLinus Torvalds goto do_nonblock; 8543ca3af4ddSXin Long if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING) 85441da177e4SLinus Torvalds goto do_error; 85451da177e4SLinus Torvalds if (signal_pending(current)) 85461da177e4SLinus Torvalds goto do_interrupted; 85471da177e4SLinus Torvalds if (msg_len <= sctp_wspace(asoc)) 85481da177e4SLinus Torvalds break; 85491da177e4SLinus Torvalds 85501da177e4SLinus Torvalds /* Let another process have a go. Since we are going 85511da177e4SLinus Torvalds * to sleep anyway. 85521da177e4SLinus Torvalds */ 8553048ed4b6Swangweidong release_sock(sk); 85541da177e4SLinus Torvalds current_timeo = schedule_timeout(current_timeo); 8555048ed4b6Swangweidong lock_sock(sk); 8556a0ff6600SXin Long if (sk != asoc->base.sk) 8557a0ff6600SXin Long goto do_error; 85581da177e4SLinus Torvalds 85591da177e4SLinus Torvalds *timeo_p = current_timeo; 85601da177e4SLinus Torvalds } 85611da177e4SLinus Torvalds 85621da177e4SLinus Torvalds out: 85631da177e4SLinus Torvalds finish_wait(&asoc->wait, &wait); 85641da177e4SLinus Torvalds 85651da177e4SLinus Torvalds /* Release the association's refcnt. */ 85661da177e4SLinus Torvalds sctp_association_put(asoc); 85671da177e4SLinus Torvalds 85681da177e4SLinus Torvalds return err; 85691da177e4SLinus Torvalds 8570ca3af4ddSXin Long do_dead: 8571ca3af4ddSXin Long err = -ESRCH; 8572ca3af4ddSXin Long goto out; 8573ca3af4ddSXin Long 85741da177e4SLinus Torvalds do_error: 85751da177e4SLinus Torvalds err = -EPIPE; 85761da177e4SLinus Torvalds goto out; 85771da177e4SLinus Torvalds 85781da177e4SLinus Torvalds do_interrupted: 85791da177e4SLinus Torvalds err = sock_intr_errno(*timeo_p); 85801da177e4SLinus Torvalds goto out; 85811da177e4SLinus Torvalds 85821da177e4SLinus Torvalds do_nonblock: 85831da177e4SLinus Torvalds err = -EAGAIN; 85841da177e4SLinus Torvalds goto out; 85851da177e4SLinus Torvalds } 85861da177e4SLinus Torvalds 8587676d2369SDavid S. Miller void sctp_data_ready(struct sock *sk) 8588561b1733SWei Yongjun { 85897ef52737SDavid S. Miller struct socket_wq *wq; 85907ef52737SDavid S. Miller 85917ef52737SDavid S. Miller rcu_read_lock(); 85927ef52737SDavid S. Miller wq = rcu_dereference(sk->sk_wq); 85931ce0bf50SHerbert Xu if (skwq_has_sleeper(wq)) 8594a9a08845SLinus Torvalds wake_up_interruptible_sync_poll(&wq->wait, EPOLLIN | 8595a9a08845SLinus Torvalds EPOLLRDNORM | EPOLLRDBAND); 8596561b1733SWei Yongjun sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); 85977ef52737SDavid S. Miller rcu_read_unlock(); 8598561b1733SWei Yongjun } 8599561b1733SWei Yongjun 86001da177e4SLinus Torvalds /* If socket sndbuf has changed, wake up all per association waiters. */ 86011da177e4SLinus Torvalds void sctp_write_space(struct sock *sk) 86021da177e4SLinus Torvalds { 86031da177e4SLinus Torvalds struct sctp_association *asoc; 86041da177e4SLinus Torvalds 86051da177e4SLinus Torvalds /* Wake up the tasks in each wait queue. */ 86069dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) { 86071da177e4SLinus Torvalds __sctp_write_space(asoc); 86081da177e4SLinus Torvalds } 86091da177e4SLinus Torvalds } 86101da177e4SLinus Torvalds 86111da177e4SLinus Torvalds /* Is there any sndbuf space available on the socket? 86121da177e4SLinus Torvalds * 86139bffc4acSNeil Horman * Note that sk_wmem_alloc is the sum of the send buffers on all of the 86141da177e4SLinus Torvalds * associations on the same socket. For a UDP-style socket with 86151da177e4SLinus Torvalds * multiple associations, it is possible for it to be "unwriteable" 86161da177e4SLinus Torvalds * prematurely. I assume that this is acceptable because 86171da177e4SLinus Torvalds * a premature "unwriteable" is better than an accidental "writeable" which 86181da177e4SLinus Torvalds * would cause an unwanted block under certain circumstances. For the 1-1 86191da177e4SLinus Torvalds * UDP-style sockets or TCP-style sockets, this code should work. 86201da177e4SLinus Torvalds * - Daisy 86211da177e4SLinus Torvalds */ 86221da177e4SLinus Torvalds static int sctp_writeable(struct sock *sk) 86231da177e4SLinus Torvalds { 86241da177e4SLinus Torvalds int amt = 0; 86251da177e4SLinus Torvalds 862631e6d363SEric Dumazet amt = sk->sk_sndbuf - sk_wmem_alloc_get(sk); 86271da177e4SLinus Torvalds if (amt < 0) 86281da177e4SLinus Torvalds amt = 0; 86291da177e4SLinus Torvalds return amt; 86301da177e4SLinus Torvalds } 86311da177e4SLinus Torvalds 86321da177e4SLinus Torvalds /* Wait for an association to go into ESTABLISHED state. If timeout is 0, 86331da177e4SLinus Torvalds * returns immediately with EINPROGRESS. 86341da177e4SLinus Torvalds */ 86351da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) 86361da177e4SLinus Torvalds { 86371da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 86381da177e4SLinus Torvalds int err = 0; 86391da177e4SLinus Torvalds long current_timeo = *timeo_p; 86401da177e4SLinus Torvalds DEFINE_WAIT(wait); 86411da177e4SLinus Torvalds 8642bb33381dSDaniel Borkmann pr_debug("%s: asoc:%p, timeo:%ld\n", __func__, asoc, *timeo_p); 86431da177e4SLinus Torvalds 86441da177e4SLinus Torvalds /* Increment the association's refcnt. */ 86451da177e4SLinus Torvalds sctp_association_hold(asoc); 86461da177e4SLinus Torvalds 86471da177e4SLinus Torvalds for (;;) { 86481da177e4SLinus Torvalds prepare_to_wait_exclusive(&asoc->wait, &wait, 86491da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 86501da177e4SLinus Torvalds if (!*timeo_p) 86511da177e4SLinus Torvalds goto do_nonblock; 86521da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 86531da177e4SLinus Torvalds break; 86541da177e4SLinus Torvalds if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || 86551da177e4SLinus Torvalds asoc->base.dead) 86561da177e4SLinus Torvalds goto do_error; 86571da177e4SLinus Torvalds if (signal_pending(current)) 86581da177e4SLinus Torvalds goto do_interrupted; 86591da177e4SLinus Torvalds 86601da177e4SLinus Torvalds if (sctp_state(asoc, ESTABLISHED)) 86611da177e4SLinus Torvalds break; 86621da177e4SLinus Torvalds 86631da177e4SLinus Torvalds /* Let another process have a go. Since we are going 86641da177e4SLinus Torvalds * to sleep anyway. 86651da177e4SLinus Torvalds */ 8666048ed4b6Swangweidong release_sock(sk); 86671da177e4SLinus Torvalds current_timeo = schedule_timeout(current_timeo); 8668048ed4b6Swangweidong lock_sock(sk); 86691da177e4SLinus Torvalds 86701da177e4SLinus Torvalds *timeo_p = current_timeo; 86711da177e4SLinus Torvalds } 86721da177e4SLinus Torvalds 86731da177e4SLinus Torvalds out: 86741da177e4SLinus Torvalds finish_wait(&asoc->wait, &wait); 86751da177e4SLinus Torvalds 86761da177e4SLinus Torvalds /* Release the association's refcnt. */ 86771da177e4SLinus Torvalds sctp_association_put(asoc); 86781da177e4SLinus Torvalds 86791da177e4SLinus Torvalds return err; 86801da177e4SLinus Torvalds 86811da177e4SLinus Torvalds do_error: 868281845c21SVlad Yasevich if (asoc->init_err_counter + 1 > asoc->max_init_attempts) 86831da177e4SLinus Torvalds err = -ETIMEDOUT; 86841da177e4SLinus Torvalds else 86851da177e4SLinus Torvalds err = -ECONNREFUSED; 86861da177e4SLinus Torvalds goto out; 86871da177e4SLinus Torvalds 86881da177e4SLinus Torvalds do_interrupted: 86891da177e4SLinus Torvalds err = sock_intr_errno(*timeo_p); 86901da177e4SLinus Torvalds goto out; 86911da177e4SLinus Torvalds 86921da177e4SLinus Torvalds do_nonblock: 86931da177e4SLinus Torvalds err = -EINPROGRESS; 86941da177e4SLinus Torvalds goto out; 86951da177e4SLinus Torvalds } 86961da177e4SLinus Torvalds 86971da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo) 86981da177e4SLinus Torvalds { 86991da177e4SLinus Torvalds struct sctp_endpoint *ep; 87001da177e4SLinus Torvalds int err = 0; 87011da177e4SLinus Torvalds DEFINE_WAIT(wait); 87021da177e4SLinus Torvalds 87031da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 87041da177e4SLinus Torvalds 87051da177e4SLinus Torvalds 87061da177e4SLinus Torvalds for (;;) { 8707aa395145SEric Dumazet prepare_to_wait_exclusive(sk_sleep(sk), &wait, 87081da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 87091da177e4SLinus Torvalds 87101da177e4SLinus Torvalds if (list_empty(&ep->asocs)) { 8711048ed4b6Swangweidong release_sock(sk); 87121da177e4SLinus Torvalds timeo = schedule_timeout(timeo); 8713048ed4b6Swangweidong lock_sock(sk); 87141da177e4SLinus Torvalds } 87151da177e4SLinus Torvalds 87161da177e4SLinus Torvalds err = -EINVAL; 87171da177e4SLinus Torvalds if (!sctp_sstate(sk, LISTENING)) 87181da177e4SLinus Torvalds break; 87191da177e4SLinus Torvalds 87201da177e4SLinus Torvalds err = 0; 87211da177e4SLinus Torvalds if (!list_empty(&ep->asocs)) 87221da177e4SLinus Torvalds break; 87231da177e4SLinus Torvalds 87241da177e4SLinus Torvalds err = sock_intr_errno(timeo); 87251da177e4SLinus Torvalds if (signal_pending(current)) 87261da177e4SLinus Torvalds break; 87271da177e4SLinus Torvalds 87281da177e4SLinus Torvalds err = -EAGAIN; 87291da177e4SLinus Torvalds if (!timeo) 87301da177e4SLinus Torvalds break; 87311da177e4SLinus Torvalds } 87321da177e4SLinus Torvalds 8733aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 87341da177e4SLinus Torvalds 87351da177e4SLinus Torvalds return err; 87361da177e4SLinus Torvalds } 87371da177e4SLinus Torvalds 873804675210Ssebastian@breakpoint.cc static void sctp_wait_for_close(struct sock *sk, long timeout) 87391da177e4SLinus Torvalds { 87401da177e4SLinus Torvalds DEFINE_WAIT(wait); 87411da177e4SLinus Torvalds 87421da177e4SLinus Torvalds do { 8743aa395145SEric Dumazet prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 87441da177e4SLinus Torvalds if (list_empty(&sctp_sk(sk)->ep->asocs)) 87451da177e4SLinus Torvalds break; 8746048ed4b6Swangweidong release_sock(sk); 87471da177e4SLinus Torvalds timeout = schedule_timeout(timeout); 8748048ed4b6Swangweidong lock_sock(sk); 87491da177e4SLinus Torvalds } while (!signal_pending(current) && timeout); 87501da177e4SLinus Torvalds 8751aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 87521da177e4SLinus Torvalds } 87531da177e4SLinus Torvalds 8754ea2bc483STsutomu Fujii static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) 8755ea2bc483STsutomu Fujii { 8756ea2bc483STsutomu Fujii struct sk_buff *frag; 8757ea2bc483STsutomu Fujii 8758ea2bc483STsutomu Fujii if (!skb->data_len) 8759ea2bc483STsutomu Fujii goto done; 8760ea2bc483STsutomu Fujii 8761ea2bc483STsutomu Fujii /* Don't forget the fragments. */ 87621b003be3SDavid S. Miller skb_walk_frags(skb, frag) 8763ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(frag, sk); 8764ea2bc483STsutomu Fujii 8765ea2bc483STsutomu Fujii done: 8766ea2bc483STsutomu Fujii sctp_skb_set_owner_r(skb, sk); 8767ea2bc483STsutomu Fujii } 8768ea2bc483STsutomu Fujii 8769914e1c8bSVlad Yasevich void sctp_copy_sock(struct sock *newsk, struct sock *sk, 8770914e1c8bSVlad Yasevich struct sctp_association *asoc) 8771914e1c8bSVlad Yasevich { 8772914e1c8bSVlad Yasevich struct inet_sock *inet = inet_sk(sk); 877309cb47a2SJulia Lawall struct inet_sock *newinet; 87742277c7cdSRichard Haines struct sctp_sock *sp = sctp_sk(sk); 87752277c7cdSRichard Haines struct sctp_endpoint *ep = sp->ep; 8776914e1c8bSVlad Yasevich 8777914e1c8bSVlad Yasevich newsk->sk_type = sk->sk_type; 8778914e1c8bSVlad Yasevich newsk->sk_bound_dev_if = sk->sk_bound_dev_if; 8779914e1c8bSVlad Yasevich newsk->sk_flags = sk->sk_flags; 878050a5ffb1SMarcelo Ricardo Leitner newsk->sk_tsflags = sk->sk_tsflags; 878128448b80STom Herbert newsk->sk_no_check_tx = sk->sk_no_check_tx; 878228448b80STom Herbert newsk->sk_no_check_rx = sk->sk_no_check_rx; 8783914e1c8bSVlad Yasevich newsk->sk_reuse = sk->sk_reuse; 8784b0e9a2feSXin Long sctp_sk(newsk)->reuse = sp->reuse; 8785914e1c8bSVlad Yasevich 8786914e1c8bSVlad Yasevich newsk->sk_shutdown = sk->sk_shutdown; 87870a2fbac1SDaniel Borkmann newsk->sk_destruct = sctp_destruct_sock; 8788914e1c8bSVlad Yasevich newsk->sk_family = sk->sk_family; 8789914e1c8bSVlad Yasevich newsk->sk_protocol = IPPROTO_SCTP; 8790914e1c8bSVlad Yasevich newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; 8791914e1c8bSVlad Yasevich newsk->sk_sndbuf = sk->sk_sndbuf; 8792914e1c8bSVlad Yasevich newsk->sk_rcvbuf = sk->sk_rcvbuf; 8793914e1c8bSVlad Yasevich newsk->sk_lingertime = sk->sk_lingertime; 8794914e1c8bSVlad Yasevich newsk->sk_rcvtimeo = sk->sk_rcvtimeo; 8795914e1c8bSVlad Yasevich newsk->sk_sndtimeo = sk->sk_sndtimeo; 8796486bdee0SMarcelo Ricardo Leitner newsk->sk_rxhash = sk->sk_rxhash; 8797914e1c8bSVlad Yasevich 8798914e1c8bSVlad Yasevich newinet = inet_sk(newsk); 8799914e1c8bSVlad Yasevich 8800914e1c8bSVlad Yasevich /* Initialize sk's sport, dport, rcv_saddr and daddr for 8801914e1c8bSVlad Yasevich * getsockname() and getpeername() 8802914e1c8bSVlad Yasevich */ 8803c720c7e8SEric Dumazet newinet->inet_sport = inet->inet_sport; 8804c720c7e8SEric Dumazet newinet->inet_saddr = inet->inet_saddr; 8805c720c7e8SEric Dumazet newinet->inet_rcv_saddr = inet->inet_rcv_saddr; 8806c720c7e8SEric Dumazet newinet->inet_dport = htons(asoc->peer.port); 8807914e1c8bSVlad Yasevich newinet->pmtudisc = inet->pmtudisc; 8808c720c7e8SEric Dumazet newinet->inet_id = asoc->next_tsn ^ jiffies; 8809914e1c8bSVlad Yasevich 8810914e1c8bSVlad Yasevich newinet->uc_ttl = inet->uc_ttl; 8811914e1c8bSVlad Yasevich newinet->mc_loop = 1; 8812914e1c8bSVlad Yasevich newinet->mc_ttl = 1; 8813914e1c8bSVlad Yasevich newinet->mc_index = 0; 8814914e1c8bSVlad Yasevich newinet->mc_list = NULL; 881501ce63c9SMarcelo Ricardo Leitner 881601ce63c9SMarcelo Ricardo Leitner if (newsk->sk_flags & SK_FLAGS_TIMESTAMP) 881701ce63c9SMarcelo Ricardo Leitner net_enable_timestamp(); 88183538a5c8SMarcelo Ricardo Leitner 88192277c7cdSRichard Haines /* Set newsk security attributes from orginal sk and connection 88202277c7cdSRichard Haines * security attribute from ep. 88212277c7cdSRichard Haines */ 88222277c7cdSRichard Haines security_sctp_sk_clone(ep, sk, newsk); 8823914e1c8bSVlad Yasevich } 8824914e1c8bSVlad Yasevich 88252d45a02dSMarcelo Ricardo Leitner static inline void sctp_copy_descendant(struct sock *sk_to, 88262d45a02dSMarcelo Ricardo Leitner const struct sock *sk_from) 88272d45a02dSMarcelo Ricardo Leitner { 88282d45a02dSMarcelo Ricardo Leitner int ancestor_size = sizeof(struct inet_sock) + 88292d45a02dSMarcelo Ricardo Leitner sizeof(struct sctp_sock) - 88302d45a02dSMarcelo Ricardo Leitner offsetof(struct sctp_sock, auto_asconf_list); 88312d45a02dSMarcelo Ricardo Leitner 88322d45a02dSMarcelo Ricardo Leitner if (sk_from->sk_family == PF_INET6) 88332d45a02dSMarcelo Ricardo Leitner ancestor_size += sizeof(struct ipv6_pinfo); 88342d45a02dSMarcelo Ricardo Leitner 88352d45a02dSMarcelo Ricardo Leitner __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); 88362d45a02dSMarcelo Ricardo Leitner } 88372d45a02dSMarcelo Ricardo Leitner 88381da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the assoc 88391da177e4SLinus Torvalds * and its messages to the newsk. 88401da177e4SLinus Torvalds */ 88411da177e4SLinus Torvalds static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, 88421da177e4SLinus Torvalds struct sctp_association *assoc, 8843b7ef2618SXin Long enum sctp_socket_type type) 88441da177e4SLinus Torvalds { 88451da177e4SLinus Torvalds struct sctp_sock *oldsp = sctp_sk(oldsk); 88461da177e4SLinus Torvalds struct sctp_sock *newsp = sctp_sk(newsk); 88471da177e4SLinus Torvalds struct sctp_bind_bucket *pp; /* hash list port iterator */ 88481da177e4SLinus Torvalds struct sctp_endpoint *newep = newsp->ep; 88491da177e4SLinus Torvalds struct sk_buff *skb, *tmp; 88501da177e4SLinus Torvalds struct sctp_ulpevent *event; 8851f26f7c48SVlad Yasevich struct sctp_bind_hashbucket *head; 88521da177e4SLinus Torvalds 88531da177e4SLinus Torvalds /* Migrate socket buffer sizes and all the socket level options to the 88541da177e4SLinus Torvalds * new socket. 88551da177e4SLinus Torvalds */ 88561da177e4SLinus Torvalds newsk->sk_sndbuf = oldsk->sk_sndbuf; 88571da177e4SLinus Torvalds newsk->sk_rcvbuf = oldsk->sk_rcvbuf; 88581da177e4SLinus Torvalds /* Brute force copy old sctp opt. */ 88592d45a02dSMarcelo Ricardo Leitner sctp_copy_descendant(newsk, oldsk); 88601da177e4SLinus Torvalds 88611da177e4SLinus Torvalds /* Restore the ep value that was overwritten with the above structure 88621da177e4SLinus Torvalds * copy. 88631da177e4SLinus Torvalds */ 88641da177e4SLinus Torvalds newsp->ep = newep; 88651da177e4SLinus Torvalds newsp->hmac = NULL; 88661da177e4SLinus Torvalds 88671da177e4SLinus Torvalds /* Hook this new socket in to the bind_hash list. */ 8868f1f43763SEric W. Biederman head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk), 8869f1f43763SEric W. Biederman inet_sk(oldsk)->inet_num)]; 8870489ce5f4SNicholas Mc Guire spin_lock_bh(&head->lock); 88711da177e4SLinus Torvalds pp = sctp_sk(oldsk)->bind_hash; 88721da177e4SLinus Torvalds sk_add_bind_node(newsk, &pp->owner); 88731da177e4SLinus Torvalds sctp_sk(newsk)->bind_hash = pp; 8874c720c7e8SEric Dumazet inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num; 8875489ce5f4SNicholas Mc Guire spin_unlock_bh(&head->lock); 88761da177e4SLinus Torvalds 88774243cac1SVladislav Yasevich /* Copy the bind_addr list from the original endpoint to the new 88784243cac1SVladislav Yasevich * endpoint so that we can handle restarts properly 88794243cac1SVladislav Yasevich */ 88808e71a11cSVlad Yasevich sctp_bind_addr_dup(&newsp->ep->base.bind_addr, 88818e71a11cSVlad Yasevich &oldsp->ep->base.bind_addr, GFP_KERNEL); 88824243cac1SVladislav Yasevich 88831da177e4SLinus Torvalds /* Move any messages in the old socket's receive queue that are for the 88841da177e4SLinus Torvalds * peeled off association to the new socket's receive queue. 88851da177e4SLinus Torvalds */ 88861da177e4SLinus Torvalds sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { 88871da177e4SLinus Torvalds event = sctp_skb2event(skb); 88881da177e4SLinus Torvalds if (event->asoc == assoc) { 88898728b834SDavid S. Miller __skb_unlink(skb, &oldsk->sk_receive_queue); 88901da177e4SLinus Torvalds __skb_queue_tail(&newsk->sk_receive_queue, skb); 8891ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 88921da177e4SLinus Torvalds } 88931da177e4SLinus Torvalds } 88941da177e4SLinus Torvalds 88951da177e4SLinus Torvalds /* Clean up any messages pending delivery due to partial 88961da177e4SLinus Torvalds * delivery. Three cases: 88971da177e4SLinus Torvalds * 1) No partial deliver; no work. 88981da177e4SLinus Torvalds * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby. 88991da177e4SLinus Torvalds * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue. 89001da177e4SLinus Torvalds */ 89011da177e4SLinus Torvalds skb_queue_head_init(&newsp->pd_lobby); 8902b6e1331fSVlad Yasevich atomic_set(&sctp_sk(newsk)->pd_mode, assoc->ulpq.pd_mode); 89031da177e4SLinus Torvalds 8904b6e1331fSVlad Yasevich if (atomic_read(&sctp_sk(oldsk)->pd_mode)) { 89051da177e4SLinus Torvalds struct sk_buff_head *queue; 89061da177e4SLinus Torvalds 89071da177e4SLinus Torvalds /* Decide which queue to move pd_lobby skbs to. */ 89081da177e4SLinus Torvalds if (assoc->ulpq.pd_mode) { 89091da177e4SLinus Torvalds queue = &newsp->pd_lobby; 89101da177e4SLinus Torvalds } else 89111da177e4SLinus Torvalds queue = &newsk->sk_receive_queue; 89121da177e4SLinus Torvalds 89131da177e4SLinus Torvalds /* Walk through the pd_lobby, looking for skbs that 89141da177e4SLinus Torvalds * need moved to the new socket. 89151da177e4SLinus Torvalds */ 89161da177e4SLinus Torvalds sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { 89171da177e4SLinus Torvalds event = sctp_skb2event(skb); 89181da177e4SLinus Torvalds if (event->asoc == assoc) { 89198728b834SDavid S. Miller __skb_unlink(skb, &oldsp->pd_lobby); 89201da177e4SLinus Torvalds __skb_queue_tail(queue, skb); 8921ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 89221da177e4SLinus Torvalds } 89231da177e4SLinus Torvalds } 89241da177e4SLinus Torvalds 89251da177e4SLinus Torvalds /* Clear up any skbs waiting for the partial 89261da177e4SLinus Torvalds * delivery to finish. 89271da177e4SLinus Torvalds */ 89281da177e4SLinus Torvalds if (assoc->ulpq.pd_mode) 8929b6e1331fSVlad Yasevich sctp_clear_pd(oldsk, NULL); 89301da177e4SLinus Torvalds 89311da177e4SLinus Torvalds } 89321da177e4SLinus Torvalds 893313228238SXin Long sctp_for_each_rx_skb(assoc, newsk, sctp_skb_set_owner_r_frag); 8934ea2bc483STsutomu Fujii 89351da177e4SLinus Torvalds /* Set the type of socket to indicate that it is peeled off from the 89361da177e4SLinus Torvalds * original UDP-style socket or created with the accept() call on a 89371da177e4SLinus Torvalds * TCP-style socket.. 89381da177e4SLinus Torvalds */ 89391da177e4SLinus Torvalds newsp->type = type; 89401da177e4SLinus Torvalds 894161c9fed4SVladislav Yasevich /* Mark the new socket "in-use" by the user so that any packets 894261c9fed4SVladislav Yasevich * that may arrive on the association after we've moved it are 894361c9fed4SVladislav Yasevich * queued to the backlog. This prevents a potential race between 894461c9fed4SVladislav Yasevich * backlog processing on the old socket and new-packet processing 894561c9fed4SVladislav Yasevich * on the new socket. 89465131a184SZach Brown * 89475131a184SZach Brown * The caller has just allocated newsk so we can guarantee that other 89485131a184SZach Brown * paths won't try to lock it and then oldsk. 894961c9fed4SVladislav Yasevich */ 89505131a184SZach Brown lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); 8951d04adf1bSXin Long sctp_for_each_tx_datachunk(assoc, sctp_clear_owner_w); 89521da177e4SLinus Torvalds sctp_assoc_migrate(assoc, newsk); 8953d04adf1bSXin Long sctp_for_each_tx_datachunk(assoc, sctp_set_owner_w); 89541da177e4SLinus Torvalds 89551da177e4SLinus Torvalds /* If the association on the newsk is already closed before accept() 89561da177e4SLinus Torvalds * is called, set RCV_SHUTDOWN flag. 89571da177e4SLinus Torvalds */ 8958d46e416cSXin Long if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) { 8959cbabf463SYafang Shao inet_sk_set_state(newsk, SCTP_SS_CLOSED); 89601da177e4SLinus Torvalds newsk->sk_shutdown |= RCV_SHUTDOWN; 8961d46e416cSXin Long } else { 8962cbabf463SYafang Shao inet_sk_set_state(newsk, SCTP_SS_ESTABLISHED); 8963d46e416cSXin Long } 8964d46e416cSXin Long 8965048ed4b6Swangweidong release_sock(newsk); 89661da177e4SLinus Torvalds } 89671da177e4SLinus Torvalds 89684d93df0aSNeil Horman 89691da177e4SLinus Torvalds /* This proto struct describes the ULP interface for SCTP. */ 89701da177e4SLinus Torvalds struct proto sctp_prot = { 89711da177e4SLinus Torvalds .name = "SCTP", 89721da177e4SLinus Torvalds .owner = THIS_MODULE, 89731da177e4SLinus Torvalds .close = sctp_close, 89741da177e4SLinus Torvalds .disconnect = sctp_disconnect, 89751da177e4SLinus Torvalds .accept = sctp_accept, 89761da177e4SLinus Torvalds .ioctl = sctp_ioctl, 89771da177e4SLinus Torvalds .init = sctp_init_sock, 89781da177e4SLinus Torvalds .destroy = sctp_destroy_sock, 89791da177e4SLinus Torvalds .shutdown = sctp_shutdown, 89801da177e4SLinus Torvalds .setsockopt = sctp_setsockopt, 89811da177e4SLinus Torvalds .getsockopt = sctp_getsockopt, 89821da177e4SLinus Torvalds .sendmsg = sctp_sendmsg, 89831da177e4SLinus Torvalds .recvmsg = sctp_recvmsg, 89841da177e4SLinus Torvalds .bind = sctp_bind, 89851da177e4SLinus Torvalds .backlog_rcv = sctp_backlog_rcv, 89861da177e4SLinus Torvalds .hash = sctp_hash, 89871da177e4SLinus Torvalds .unhash = sctp_unhash, 89881da177e4SLinus Torvalds .get_port = sctp_get_port, 89891da177e4SLinus Torvalds .obj_size = sizeof(struct sctp_sock), 8990ab9ee8e3SDavid Windsor .useroffset = offsetof(struct sctp_sock, subscribe), 8991ab9ee8e3SDavid Windsor .usersize = offsetof(struct sctp_sock, initmsg) - 8992ab9ee8e3SDavid Windsor offsetof(struct sctp_sock, subscribe) + 8993ab9ee8e3SDavid Windsor sizeof_field(struct sctp_sock, initmsg), 89944d93df0aSNeil Horman .sysctl_mem = sysctl_sctp_mem, 89954d93df0aSNeil Horman .sysctl_rmem = sysctl_sctp_rmem, 89964d93df0aSNeil Horman .sysctl_wmem = sysctl_sctp_wmem, 89974d93df0aSNeil Horman .memory_pressure = &sctp_memory_pressure, 89984d93df0aSNeil Horman .enter_memory_pressure = sctp_enter_memory_pressure, 89994d93df0aSNeil Horman .memory_allocated = &sctp_memory_allocated, 90005f31886fSPavel Emelyanov .sockets_allocated = &sctp_sockets_allocated, 90011da177e4SLinus Torvalds }; 90021da177e4SLinus Torvalds 9003dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 90048295b6d9SEric Dumazet 9005602dd62dSEric Dumazet #include <net/transp_v6.h> 9006602dd62dSEric Dumazet static void sctp_v6_destroy_sock(struct sock *sk) 9007602dd62dSEric Dumazet { 9008602dd62dSEric Dumazet sctp_destroy_sock(sk); 9009602dd62dSEric Dumazet inet6_destroy_sock(sk); 9010602dd62dSEric Dumazet } 9011602dd62dSEric Dumazet 90121da177e4SLinus Torvalds struct proto sctpv6_prot = { 90131da177e4SLinus Torvalds .name = "SCTPv6", 90141da177e4SLinus Torvalds .owner = THIS_MODULE, 90151da177e4SLinus Torvalds .close = sctp_close, 90161da177e4SLinus Torvalds .disconnect = sctp_disconnect, 90171da177e4SLinus Torvalds .accept = sctp_accept, 90181da177e4SLinus Torvalds .ioctl = sctp_ioctl, 90191da177e4SLinus Torvalds .init = sctp_init_sock, 9020602dd62dSEric Dumazet .destroy = sctp_v6_destroy_sock, 90211da177e4SLinus Torvalds .shutdown = sctp_shutdown, 90221da177e4SLinus Torvalds .setsockopt = sctp_setsockopt, 90231da177e4SLinus Torvalds .getsockopt = sctp_getsockopt, 90241da177e4SLinus Torvalds .sendmsg = sctp_sendmsg, 90251da177e4SLinus Torvalds .recvmsg = sctp_recvmsg, 90261da177e4SLinus Torvalds .bind = sctp_bind, 90271da177e4SLinus Torvalds .backlog_rcv = sctp_backlog_rcv, 90281da177e4SLinus Torvalds .hash = sctp_hash, 90291da177e4SLinus Torvalds .unhash = sctp_unhash, 90301da177e4SLinus Torvalds .get_port = sctp_get_port, 90311da177e4SLinus Torvalds .obj_size = sizeof(struct sctp6_sock), 9032ab9ee8e3SDavid Windsor .useroffset = offsetof(struct sctp6_sock, sctp.subscribe), 9033ab9ee8e3SDavid Windsor .usersize = offsetof(struct sctp6_sock, sctp.initmsg) - 9034ab9ee8e3SDavid Windsor offsetof(struct sctp6_sock, sctp.subscribe) + 9035ab9ee8e3SDavid Windsor sizeof_field(struct sctp6_sock, sctp.initmsg), 90364d93df0aSNeil Horman .sysctl_mem = sysctl_sctp_mem, 90374d93df0aSNeil Horman .sysctl_rmem = sysctl_sctp_rmem, 90384d93df0aSNeil Horman .sysctl_wmem = sysctl_sctp_wmem, 90394d93df0aSNeil Horman .memory_pressure = &sctp_memory_pressure, 90404d93df0aSNeil Horman .enter_memory_pressure = sctp_enter_memory_pressure, 90414d93df0aSNeil Horman .memory_allocated = &sctp_memory_allocated, 90425f31886fSPavel Emelyanov .sockets_allocated = &sctp_sockets_allocated, 90431da177e4SLinus Torvalds }; 9044dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */ 9045