147505b8bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 260c778b2SVlad Yasevich /* SCTP kernel implementation 31da177e4SLinus Torvalds * (C) Copyright IBM Corp. 2001, 2004 41da177e4SLinus Torvalds * Copyright (c) 1999-2000 Cisco, Inc. 51da177e4SLinus Torvalds * Copyright (c) 1999-2001 Motorola, Inc. 61da177e4SLinus Torvalds * Copyright (c) 2001-2003 Intel Corp. 71da177e4SLinus Torvalds * Copyright (c) 2001-2002 Nokia, Inc. 81da177e4SLinus Torvalds * Copyright (c) 2001 La Monte H.P. Yarroll 91da177e4SLinus Torvalds * 1060c778b2SVlad Yasevich * This file is part of the SCTP kernel implementation 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * These functions interface with the sockets layer to implement the 131da177e4SLinus Torvalds * SCTP Extensions for the Sockets API. 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * Note that the descriptions from the specification are USER level 161da177e4SLinus Torvalds * functions--this file is the functions which populate the struct proto 171da177e4SLinus Torvalds * for SCTP which is the BOTTOM of the sockets interface. 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * Please send any bug reports or fixes you make to the 201da177e4SLinus Torvalds * email address(es): 2191705c61SDaniel Borkmann * lksctp developers <linux-sctp@vger.kernel.org> 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * Written or modified by: 241da177e4SLinus Torvalds * La Monte H.P. Yarroll <piggy@acm.org> 251da177e4SLinus Torvalds * Narasimha Budihal <narsi@refcode.org> 261da177e4SLinus Torvalds * Karl Knutson <karl@athena.chicago.il.us> 271da177e4SLinus Torvalds * Jon Grimm <jgrimm@us.ibm.com> 281da177e4SLinus Torvalds * Xingang Guo <xingang.guo@intel.com> 291da177e4SLinus Torvalds * Daisy Chang <daisyc@us.ibm.com> 301da177e4SLinus Torvalds * Sridhar Samudrala <samudrala@us.ibm.com> 311da177e4SLinus Torvalds * Inaky Perez-Gonzalez <inaky.gonzalez@intel.com> 321da177e4SLinus Torvalds * Ardelle Fan <ardelle.fan@intel.com> 331da177e4SLinus Torvalds * Ryan Layer <rmlayer@us.ibm.com> 341da177e4SLinus Torvalds * Anup Pemmaiah <pemmaiah@cc.usu.edu> 351da177e4SLinus Torvalds * Kevin Gao <kevin.gao@intel.com> 361da177e4SLinus Torvalds */ 371da177e4SLinus Torvalds 38145ce502SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 39145ce502SJoe Perches 405821c769SHerbert Xu #include <crypto/hash.h> 411da177e4SLinus Torvalds #include <linux/types.h> 421da177e4SLinus Torvalds #include <linux/kernel.h> 431da177e4SLinus Torvalds #include <linux/wait.h> 441da177e4SLinus Torvalds #include <linux/time.h> 453f07c014SIngo Molnar #include <linux/sched/signal.h> 461da177e4SLinus Torvalds #include <linux/ip.h> 474fc268d2SRandy Dunlap #include <linux/capability.h> 481da177e4SLinus Torvalds #include <linux/fcntl.h> 491da177e4SLinus Torvalds #include <linux/poll.h> 501da177e4SLinus Torvalds #include <linux/init.h> 515a0e3ad6STejun Heo #include <linux/slab.h> 5256b31d1cSAl Viro #include <linux/file.h> 53ffd59393SDaniel Borkmann #include <linux/compat.h> 540eb71a9dSNeilBrown #include <linux/rhashtable.h> 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds #include <net/ip.h> 571da177e4SLinus Torvalds #include <net/icmp.h> 581da177e4SLinus Torvalds #include <net/route.h> 591da177e4SLinus Torvalds #include <net/ipv6.h> 601da177e4SLinus Torvalds #include <net/inet_common.h> 618465a5fcSNeil Horman #include <net/busy_poll.h> 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds #include <linux/socket.h> /* for sa_family_t */ 64bc3b2d7fSPaul Gortmaker #include <linux/export.h> 651da177e4SLinus Torvalds #include <net/sock.h> 661da177e4SLinus Torvalds #include <net/sctp/sctp.h> 671da177e4SLinus Torvalds #include <net/sctp/sm.h> 6813aa8770SMarcelo Ricardo Leitner #include <net/sctp/stream_sched.h> 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds /* Forward declarations for internal helper functions. */ 71cd305c74SXin Long static bool sctp_writeable(struct sock *sk); 721da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb); 73cea0cc80SXin Long static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 74a0ff6600SXin Long size_t msg_len); 751da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p); 761da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); 771da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo); 781da177e4SLinus Torvalds static void sctp_wait_for_close(struct sock *sk, long timeo); 790a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk); 801da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, 811da177e4SLinus Torvalds union sctp_addr *addr, int len); 821da177e4SLinus Torvalds static int sctp_bindx_add(struct sock *, struct sockaddr *, int); 831da177e4SLinus Torvalds static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); 841da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); 851da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int); 861da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc, 871da177e4SLinus Torvalds struct sctp_chunk *chunk); 881da177e4SLinus Torvalds static int sctp_do_bind(struct sock *, union sctp_addr *, int); 891da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk); 9089664c62SXin Long static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, 91b7ef2618SXin Long struct sctp_association *assoc, 92b7ef2618SXin Long enum sctp_socket_type type); 931da177e4SLinus Torvalds 9406044751SEric Dumazet static unsigned long sctp_memory_pressure; 958d987e5cSEric Dumazet static atomic_long_t sctp_memory_allocated; 961748376bSEric Dumazet struct percpu_counter sctp_sockets_allocated; 974d93df0aSNeil Horman 985c52ba17SPavel Emelyanov static void sctp_enter_memory_pressure(struct sock *sk) 994d93df0aSNeil Horman { 1004d93df0aSNeil Horman sctp_memory_pressure = 1; 1014d93df0aSNeil Horman } 1024d93df0aSNeil Horman 1034d93df0aSNeil Horman 1041da177e4SLinus Torvalds /* Get the sndbuf space available at the time on the association. */ 1051da177e4SLinus Torvalds static inline int sctp_wspace(struct sctp_association *asoc) 1061da177e4SLinus Torvalds { 107cd305c74SXin Long struct sock *sk = asoc->base.sk; 1081da177e4SLinus Torvalds 109cd305c74SXin Long return asoc->ep->sndbuf_policy ? sk->sk_sndbuf - asoc->sndbuf_used 110cd305c74SXin Long : sk_stream_wspace(sk); 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds /* Increment the used sndbuf space count of the corresponding association by 1141da177e4SLinus Torvalds * the size of the outgoing data chunk. 1151da177e4SLinus Torvalds * Also, set the skb destructor for sndbuf accounting later. 1161da177e4SLinus Torvalds * 1171da177e4SLinus Torvalds * Since it is always 1-1 between chunk and skb, and also a new skb is always 1181da177e4SLinus Torvalds * allocated for chunk bundling in sctp_packet_transmit(), we can use the 1191da177e4SLinus Torvalds * destructor in the data chunk skb for the purpose of the sndbuf space 1201da177e4SLinus Torvalds * tracking. 1211da177e4SLinus Torvalds */ 1221da177e4SLinus Torvalds static inline void sctp_set_owner_w(struct sctp_chunk *chunk) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds struct sctp_association *asoc = chunk->asoc; 1251da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds /* The sndbuf space is tracked per association. */ 1281da177e4SLinus Torvalds sctp_association_hold(asoc); 1291da177e4SLinus Torvalds 1301b1e0bc9SXin Long if (chunk->shkey) 1311b1e0bc9SXin Long sctp_auth_shkey_hold(chunk->shkey); 1321b1e0bc9SXin Long 1334eb701dfSNeil Horman skb_set_owner_w(chunk->skb, sk); 1344eb701dfSNeil Horman 1351da177e4SLinus Torvalds chunk->skb->destructor = sctp_wfree; 1361da177e4SLinus Torvalds /* Save the chunk pointer in skb for sctp_wfree to use later. */ 137f869c912SDaniel Borkmann skb_shinfo(chunk->skb)->destructor_arg = chunk; 1381da177e4SLinus Torvalds 13914afee4bSReshetova, Elena refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); 140605c0ac1SXin Long asoc->sndbuf_used += chunk->skb->truesize + sizeof(struct sctp_chunk); 141605c0ac1SXin Long sk->sk_wmem_queued += chunk->skb->truesize + sizeof(struct sctp_chunk); 1423ab224beSHideo Aoki sk_mem_charge(sk, chunk->skb->truesize); 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 145d04adf1bSXin Long static void sctp_clear_owner_w(struct sctp_chunk *chunk) 146d04adf1bSXin Long { 147d04adf1bSXin Long skb_orphan(chunk->skb); 148d04adf1bSXin Long } 149d04adf1bSXin Long 1505c3e82feSQiujun Huang #define traverse_and_process() \ 1515c3e82feSQiujun Huang do { \ 1525c3e82feSQiujun Huang msg = chunk->msg; \ 1535c3e82feSQiujun Huang if (msg == prev_msg) \ 1545c3e82feSQiujun Huang continue; \ 1555c3e82feSQiujun Huang list_for_each_entry(c, &msg->chunks, frag_list) { \ 1565c3e82feSQiujun Huang if ((clear && asoc->base.sk == c->skb->sk) || \ 1575c3e82feSQiujun Huang (!clear && asoc->base.sk != c->skb->sk)) \ 1585c3e82feSQiujun Huang cb(c); \ 1595c3e82feSQiujun Huang } \ 1605c3e82feSQiujun Huang prev_msg = msg; \ 1615c3e82feSQiujun Huang } while (0) 1625c3e82feSQiujun Huang 163d04adf1bSXin Long static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, 1645c3e82feSQiujun Huang bool clear, 165d04adf1bSXin Long void (*cb)(struct sctp_chunk *)) 166d04adf1bSXin Long 167d04adf1bSXin Long { 1685c3e82feSQiujun Huang struct sctp_datamsg *msg, *prev_msg = NULL; 169d04adf1bSXin Long struct sctp_outq *q = &asoc->outqueue; 1705c3e82feSQiujun Huang struct sctp_chunk *chunk, *c; 171d04adf1bSXin Long struct sctp_transport *t; 172d04adf1bSXin Long 173d04adf1bSXin Long list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) 174d04adf1bSXin Long list_for_each_entry(chunk, &t->transmitted, transmitted_list) 1755c3e82feSQiujun Huang traverse_and_process(); 176d04adf1bSXin Long 177a8dd3979SXin Long list_for_each_entry(chunk, &q->retransmit, transmitted_list) 1785c3e82feSQiujun Huang traverse_and_process(); 179d04adf1bSXin Long 180a8dd3979SXin Long list_for_each_entry(chunk, &q->sacked, transmitted_list) 1815c3e82feSQiujun Huang traverse_and_process(); 182d04adf1bSXin Long 183a8dd3979SXin Long list_for_each_entry(chunk, &q->abandoned, transmitted_list) 1845c3e82feSQiujun Huang traverse_and_process(); 185d04adf1bSXin Long 186d04adf1bSXin Long list_for_each_entry(chunk, &q->out_chunk_list, list) 1875c3e82feSQiujun Huang traverse_and_process(); 188d04adf1bSXin Long } 189d04adf1bSXin Long 19013228238SXin Long static void sctp_for_each_rx_skb(struct sctp_association *asoc, struct sock *sk, 19113228238SXin Long void (*cb)(struct sk_buff *, struct sock *)) 19213228238SXin Long 19313228238SXin Long { 19413228238SXin Long struct sk_buff *skb, *tmp; 19513228238SXin Long 19613228238SXin Long sctp_skb_for_each(skb, &asoc->ulpq.lobby, tmp) 19713228238SXin Long cb(skb, sk); 19813228238SXin Long 19913228238SXin Long sctp_skb_for_each(skb, &asoc->ulpq.reasm, tmp) 20013228238SXin Long cb(skb, sk); 20113228238SXin Long 20213228238SXin Long sctp_skb_for_each(skb, &asoc->ulpq.reasm_uo, tmp) 20313228238SXin Long cb(skb, sk); 20413228238SXin Long } 20513228238SXin Long 2061da177e4SLinus Torvalds /* Verify that this is a valid address. */ 2071da177e4SLinus Torvalds static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, 2081da177e4SLinus Torvalds int len) 2091da177e4SLinus Torvalds { 2101da177e4SLinus Torvalds struct sctp_af *af; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* Verify basic sockaddr. */ 2131da177e4SLinus Torvalds af = sctp_sockaddr_af(sctp_sk(sk), addr, len); 2141da177e4SLinus Torvalds if (!af) 2151da177e4SLinus Torvalds return -EINVAL; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds /* Is this a valid SCTP address? */ 2185636bef7SVlad Yasevich if (!af->addr_valid(addr, sctp_sk(sk), NULL)) 2191da177e4SLinus Torvalds return -EINVAL; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) 2221da177e4SLinus Torvalds return -EINVAL; 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds return 0; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds /* Look up the association by its id. If this is not a UDP-style 2281da177e4SLinus Torvalds * socket, the ID field is always ignored. 2291da177e4SLinus Torvalds */ 2301da177e4SLinus Torvalds struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) 2311da177e4SLinus Torvalds { 2321da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds /* If this is not a UDP-style socket, assoc id should be ignored. */ 2351da177e4SLinus Torvalds if (!sctp_style(sk, UDP)) { 2361da177e4SLinus Torvalds /* Return NULL if the socket state is not ESTABLISHED. It 2371da177e4SLinus Torvalds * could be a TCP-style listening socket or a socket which 2381da177e4SLinus Torvalds * hasn't yet called connect() to establish an association. 2391da177e4SLinus Torvalds */ 240e5b13f34SMarcelo Ricardo Leitner if (!sctp_sstate(sk, ESTABLISHED) && !sctp_sstate(sk, CLOSING)) 2411da177e4SLinus Torvalds return NULL; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds /* Get the first and the only association from the list. */ 2441da177e4SLinus Torvalds if (!list_empty(&sctp_sk(sk)->ep->asocs)) 2451da177e4SLinus Torvalds asoc = list_entry(sctp_sk(sk)->ep->asocs.next, 2461da177e4SLinus Torvalds struct sctp_association, asocs); 2471da177e4SLinus Torvalds return asoc; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* Otherwise this is a UDP-style socket. */ 25180df2704SXin Long if (id <= SCTP_ALL_ASSOC) 2521da177e4SLinus Torvalds return NULL; 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds spin_lock_bh(&sctp_assocs_id_lock); 2551da177e4SLinus Torvalds asoc = (struct sctp_association *)idr_find(&sctp_assocs_id, (int)id); 256b336decaSMarcelo Ricardo Leitner if (asoc && (asoc->base.sk != sk || asoc->base.dead)) 257b336decaSMarcelo Ricardo Leitner asoc = NULL; 2581da177e4SLinus Torvalds spin_unlock_bh(&sctp_assocs_id_lock); 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds return asoc; 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds /* Look up the transport from an address and an assoc id. If both address and 2641da177e4SLinus Torvalds * id are specified, the associations matching the address and the id should be 2651da177e4SLinus Torvalds * the same. 2661da177e4SLinus Torvalds */ 2671da177e4SLinus Torvalds static struct sctp_transport *sctp_addr_id2transport(struct sock *sk, 2681da177e4SLinus Torvalds struct sockaddr_storage *addr, 2691da177e4SLinus Torvalds sctp_assoc_t id) 2701da177e4SLinus Torvalds { 2711da177e4SLinus Torvalds struct sctp_association *addr_asoc = NULL, *id_asoc = NULL; 2726f29a130SXin Long struct sctp_af *af = sctp_get_af_specific(addr->ss_family); 2731da177e4SLinus Torvalds union sctp_addr *laddr = (union sctp_addr *)addr; 2746f29a130SXin Long struct sctp_transport *transport; 2756f29a130SXin Long 276912964eaSXin Long if (!af || sctp_verify_addr(sk, laddr, af->sockaddr_len)) 2776f29a130SXin Long return NULL; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep, 280cd4ff034SAl Viro laddr, 2811da177e4SLinus Torvalds &transport); 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds if (!addr_asoc) 2841da177e4SLinus Torvalds return NULL; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds id_asoc = sctp_id2assoc(sk, id); 2871da177e4SLinus Torvalds if (id_asoc && (id_asoc != addr_asoc)) 2881da177e4SLinus Torvalds return NULL; 2891da177e4SLinus Torvalds 290299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), 2911da177e4SLinus Torvalds (union sctp_addr *)addr); 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds return transport; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds /* API 3.1.2 bind() - UDP Style Syntax 2971da177e4SLinus Torvalds * The syntax of bind() is, 2981da177e4SLinus Torvalds * 2991da177e4SLinus Torvalds * ret = bind(int sd, struct sockaddr *addr, int addrlen); 3001da177e4SLinus Torvalds * 3011da177e4SLinus Torvalds * sd - the socket descriptor returned by socket(). 3021da177e4SLinus Torvalds * addr - the address structure (struct sockaddr_in or struct 3031da177e4SLinus Torvalds * sockaddr_in6 [RFC 2553]), 3041da177e4SLinus Torvalds * addr_len - the size of the address structure. 3051da177e4SLinus Torvalds */ 306dda91928SDaniel Borkmann static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds int retval = 0; 3091da177e4SLinus Torvalds 310048ed4b6Swangweidong lock_sock(sk); 3111da177e4SLinus Torvalds 312bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addr:%p, addr_len:%d\n", __func__, sk, 313bb33381dSDaniel Borkmann addr, addr_len); 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds /* Disallow binding twice. */ 3161da177e4SLinus Torvalds if (!sctp_sk(sk)->ep->base.bind_addr.port) 3173f7a87d2SFrank Filz retval = sctp_do_bind(sk, (union sctp_addr *)addr, 3181da177e4SLinus Torvalds addr_len); 3191da177e4SLinus Torvalds else 3201da177e4SLinus Torvalds retval = -EINVAL; 3211da177e4SLinus Torvalds 322048ed4b6Swangweidong release_sock(sk); 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds return retval; 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 3278e2ef6abSMao Wenan static int sctp_get_port_local(struct sock *, union sctp_addr *); 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds /* Verify this is a valid sockaddr. */ 3301da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, 3311da177e4SLinus Torvalds union sctp_addr *addr, int len) 3321da177e4SLinus Torvalds { 3331da177e4SLinus Torvalds struct sctp_af *af; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds /* Check minimum size. */ 3361da177e4SLinus Torvalds if (len < sizeof (struct sockaddr)) 3371da177e4SLinus Torvalds return NULL; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds if (!opt->pf->af_supported(addr->sa.sa_family, opt)) 3401da177e4SLinus Torvalds return NULL; 341c5006b8aSXin Long 34281e98370SEric Dumazet if (addr->sa.sa_family == AF_INET6) { 34381e98370SEric Dumazet if (len < SIN6_LEN_RFC2133) 34481e98370SEric Dumazet return NULL; 345c5006b8aSXin Long /* V4 mapped address are really of AF_INET family */ 34681e98370SEric Dumazet if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) && 347c5006b8aSXin Long !opt->pf->af_supported(AF_INET, opt)) 348c5006b8aSXin Long return NULL; 34981e98370SEric Dumazet } 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds /* If we get this far, af is valid. */ 3521da177e4SLinus Torvalds af = sctp_get_af_specific(addr->sa.sa_family); 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds if (len < af->sockaddr_len) 3551da177e4SLinus Torvalds return NULL; 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds return af; 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds /* Bind a local address either to an endpoint or to an association. */ 361dda91928SDaniel Borkmann static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) 3621da177e4SLinus Torvalds { 3633594698aSEric W. Biederman struct net *net = sock_net(sk); 3641da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 3651da177e4SLinus Torvalds struct sctp_endpoint *ep = sp->ep; 3661da177e4SLinus Torvalds struct sctp_bind_addr *bp = &ep->base.bind_addr; 3671da177e4SLinus Torvalds struct sctp_af *af; 3681da177e4SLinus Torvalds unsigned short snum; 3691da177e4SLinus Torvalds int ret = 0; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /* Common sockaddr verification. */ 3721da177e4SLinus Torvalds af = sctp_sockaddr_af(sp, addr, len); 3733f7a87d2SFrank Filz if (!af) { 374bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, newaddr:%p, len:%d EINVAL\n", 375bb33381dSDaniel Borkmann __func__, sk, addr, len); 3761da177e4SLinus Torvalds return -EINVAL; 3773f7a87d2SFrank Filz } 3783f7a87d2SFrank Filz 3793f7a87d2SFrank Filz snum = ntohs(addr->v4.sin_port); 3803f7a87d2SFrank Filz 381bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, new addr:%pISc, port:%d, new port:%d, len:%d\n", 382bb33381dSDaniel Borkmann __func__, sk, &addr->sa, bp->port, snum, len); 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds /* PF specific bind() address verification. */ 3851da177e4SLinus Torvalds if (!sp->pf->bind_verify(sp, addr)) 3861da177e4SLinus Torvalds return -EADDRNOTAVAIL; 3871da177e4SLinus Torvalds 3888b358056SVlad Yasevich /* We must either be unbound, or bind to the same port. 3898b358056SVlad Yasevich * It's OK to allow 0 ports if we are already bound. 3908b358056SVlad Yasevich * We'll just inhert an already bound port in this case 3918b358056SVlad Yasevich */ 3928b358056SVlad Yasevich if (bp->port) { 3938b358056SVlad Yasevich if (!snum) 3948b358056SVlad Yasevich snum = bp->port; 3958b358056SVlad Yasevich else if (snum != bp->port) { 396bb33381dSDaniel Borkmann pr_debug("%s: new port %d doesn't match existing port " 397bb33381dSDaniel Borkmann "%d\n", __func__, snum, bp->port); 3981da177e4SLinus Torvalds return -EINVAL; 3991da177e4SLinus Torvalds } 4008b358056SVlad Yasevich } 4011da177e4SLinus Torvalds 40282f31ebfSMaciej Żenczykowski if (snum && inet_port_requires_bind_service(net, snum) && 4033594698aSEric W. Biederman !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 4041da177e4SLinus Torvalds return -EACCES; 4051da177e4SLinus Torvalds 4064e54064eSVlad Yasevich /* See if the address matches any of the addresses we may have 4074e54064eSVlad Yasevich * already bound before checking against other endpoints. 4084e54064eSVlad Yasevich */ 4094e54064eSVlad Yasevich if (sctp_bind_addr_match(bp, addr, sp)) 4104e54064eSVlad Yasevich return -EINVAL; 4114e54064eSVlad Yasevich 4121da177e4SLinus Torvalds /* Make sure we are allowed to bind here. 4131da177e4SLinus Torvalds * The function sctp_get_port_local() does duplicate address 4141da177e4SLinus Torvalds * detection. 4151da177e4SLinus Torvalds */ 4162772b495SVlad Yasevich addr->v4.sin_port = htons(snum); 417e0e4b8deSMao Wenan if (sctp_get_port_local(sk, addr)) 4181da177e4SLinus Torvalds return -EADDRINUSE; 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds /* Refresh ephemeral port. */ 4211da177e4SLinus Torvalds if (!bp->port) 422c720c7e8SEric Dumazet bp->port = inet_sk(sk)->inet_num; 4231da177e4SLinus Torvalds 424559cf710SVlad Yasevich /* Add the address to the bind address list. 425559cf710SVlad Yasevich * Use GFP_ATOMIC since BHs will be disabled. 426559cf710SVlad Yasevich */ 427133800d1SMarcelo Ricardo Leitner ret = sctp_add_bind_addr(bp, addr, af->sockaddr_len, 428133800d1SMarcelo Ricardo Leitner SCTP_ADDR_SRC, GFP_ATOMIC); 4291da177e4SLinus Torvalds 43029b99f54SMao Wenan if (ret) { 43129b99f54SMao Wenan sctp_put_port(sk); 43229b99f54SMao Wenan return ret; 43329b99f54SMao Wenan } 4341da177e4SLinus Torvalds /* Copy back into socket for getsockname() use. */ 435c720c7e8SEric Dumazet inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num); 436299ee123SJason Gunthorpe sp->pf->to_sk_saddr(addr, sk); 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds return ret; 4391da177e4SLinus Torvalds } 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks 4421da177e4SLinus Torvalds * 4431da177e4SLinus Torvalds * R1) One and only one ASCONF Chunk MAY be in transit and unacknowledged 4441da177e4SLinus Torvalds * at any one time. If a sender, after sending an ASCONF chunk, decides 4451da177e4SLinus Torvalds * it needs to transfer another ASCONF Chunk, it MUST wait until the 4461da177e4SLinus Torvalds * ASCONF-ACK Chunk returns from the previous ASCONF Chunk before sending a 4471da177e4SLinus Torvalds * subsequent ASCONF. Note this restriction binds each side, so at any 4481da177e4SLinus Torvalds * time two ASCONF may be in-transit on any given association (one sent 4491da177e4SLinus Torvalds * from each endpoint). 4501da177e4SLinus Torvalds */ 4511da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc, 4521da177e4SLinus Torvalds struct sctp_chunk *chunk) 4531da177e4SLinus Torvalds { 4541da177e4SLinus Torvalds int retval = 0; 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds /* If there is an outstanding ASCONF chunk, queue it for later 4571da177e4SLinus Torvalds * transmission. 4581da177e4SLinus Torvalds */ 4591da177e4SLinus Torvalds if (asoc->addip_last_asconf) { 46079af02c2SDavid S. Miller list_add_tail(&chunk->list, &asoc->addip_chunk_list); 4611da177e4SLinus Torvalds goto out; 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds /* Hold the chunk until an ASCONF_ACK is received. */ 4651da177e4SLinus Torvalds sctp_chunk_hold(chunk); 4664e7696d9SXin Long retval = sctp_primitive_ASCONF(asoc->base.net, asoc, chunk); 4671da177e4SLinus Torvalds if (retval) 4681da177e4SLinus Torvalds sctp_chunk_free(chunk); 4691da177e4SLinus Torvalds else 4701da177e4SLinus Torvalds asoc->addip_last_asconf = chunk; 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds out: 4731da177e4SLinus Torvalds return retval; 4741da177e4SLinus Torvalds } 4751da177e4SLinus Torvalds 4761da177e4SLinus Torvalds /* Add a list of addresses as bind addresses to local endpoint or 4771da177e4SLinus Torvalds * association. 4781da177e4SLinus Torvalds * 4791da177e4SLinus Torvalds * Basically run through each address specified in the addrs/addrcnt 4801da177e4SLinus Torvalds * array/length pair, determine if it is IPv6 or IPv4 and call 4811da177e4SLinus Torvalds * sctp_do_bind() on it. 4821da177e4SLinus Torvalds * 4831da177e4SLinus Torvalds * If any of them fails, then the operation will be reversed and the 4841da177e4SLinus Torvalds * ones that were added will be removed. 4851da177e4SLinus Torvalds * 4861da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 4871da177e4SLinus Torvalds */ 48804675210Ssebastian@breakpoint.cc static int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt) 4891da177e4SLinus Torvalds { 4901da177e4SLinus Torvalds int cnt; 4911da177e4SLinus Torvalds int retval = 0; 4921da177e4SLinus Torvalds void *addr_buf; 4931da177e4SLinus Torvalds struct sockaddr *sa_addr; 4941da177e4SLinus Torvalds struct sctp_af *af; 4951da177e4SLinus Torvalds 496bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", __func__, sk, 497bb33381dSDaniel Borkmann addrs, addrcnt); 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds addr_buf = addrs; 5001da177e4SLinus Torvalds for (cnt = 0; cnt < addrcnt; cnt++) { 5011da177e4SLinus Torvalds /* The list may contain either IPv4 or IPv6 address; 5021da177e4SLinus Torvalds * determine the address length for walking thru the list. 5031da177e4SLinus Torvalds */ 504ea110733SJoe Perches sa_addr = addr_buf; 5051da177e4SLinus Torvalds af = sctp_get_af_specific(sa_addr->sa_family); 5061da177e4SLinus Torvalds if (!af) { 5071da177e4SLinus Torvalds retval = -EINVAL; 5081da177e4SLinus Torvalds goto err_bindx_add; 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds retval = sctp_do_bind(sk, (union sctp_addr *)sa_addr, 5121da177e4SLinus Torvalds af->sockaddr_len); 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds err_bindx_add: 5171da177e4SLinus Torvalds if (retval < 0) { 5181da177e4SLinus Torvalds /* Failed. Cleanup the ones that have been added */ 5191da177e4SLinus Torvalds if (cnt > 0) 5201da177e4SLinus Torvalds sctp_bindx_rem(sk, addrs, cnt); 5211da177e4SLinus Torvalds return retval; 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds } 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds return retval; 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds /* Send an ASCONF chunk with Add IP address parameters to all the peers of the 5291da177e4SLinus Torvalds * associations that are part of the endpoint indicating that a list of local 5301da177e4SLinus Torvalds * addresses are added to the endpoint. 5311da177e4SLinus Torvalds * 5321da177e4SLinus Torvalds * If any of the addresses is already in the bind address list of the 5331da177e4SLinus Torvalds * association, we do not send the chunk for that association. But it will not 5341da177e4SLinus Torvalds * affect other associations. 5351da177e4SLinus Torvalds * 5361da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 5371da177e4SLinus Torvalds */ 5381da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock *sk, 5391da177e4SLinus Torvalds struct sockaddr *addrs, 5401da177e4SLinus Torvalds int addrcnt) 5411da177e4SLinus Torvalds { 5421da177e4SLinus Torvalds struct sctp_sock *sp; 5431da177e4SLinus Torvalds struct sctp_endpoint *ep; 5441da177e4SLinus Torvalds struct sctp_association *asoc; 5451da177e4SLinus Torvalds struct sctp_bind_addr *bp; 5461da177e4SLinus Torvalds struct sctp_chunk *chunk; 5471da177e4SLinus Torvalds struct sctp_sockaddr_entry *laddr; 5481da177e4SLinus Torvalds union sctp_addr *addr; 549dc022a98SSridhar Samudrala union sctp_addr saveaddr; 5501da177e4SLinus Torvalds void *addr_buf; 5511da177e4SLinus Torvalds struct sctp_af *af; 5521da177e4SLinus Torvalds struct list_head *p; 5531da177e4SLinus Torvalds int i; 5541da177e4SLinus Torvalds int retval = 0; 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds sp = sctp_sk(sk); 5571da177e4SLinus Torvalds ep = sp->ep; 5581da177e4SLinus Torvalds 5594e27428fSXin Long if (!ep->asconf_enable) 5604e27428fSXin Long return retval; 5614e27428fSXin Long 562bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 5630dc47877SHarvey Harrison __func__, sk, addrs, addrcnt); 5641da177e4SLinus Torvalds 5659dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &ep->asocs, asocs) { 5661da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 5671da177e4SLinus Torvalds continue; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_ADD_IP) 5701da177e4SLinus Torvalds continue; 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 5731da177e4SLinus Torvalds continue; 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds /* Check if any address in the packed array of addresses is 5761da177e4SLinus Torvalds * in the bind address list of the association. If so, 5771da177e4SLinus Torvalds * do not send the asconf chunk to its peer, but continue with 5781da177e4SLinus Torvalds * other associations. 5791da177e4SLinus Torvalds */ 5801da177e4SLinus Torvalds addr_buf = addrs; 5811da177e4SLinus Torvalds for (i = 0; i < addrcnt; i++) { 582ea110733SJoe Perches addr = addr_buf; 5831da177e4SLinus Torvalds af = sctp_get_af_specific(addr->v4.sin_family); 5841da177e4SLinus Torvalds if (!af) { 5851da177e4SLinus Torvalds retval = -EINVAL; 5861da177e4SLinus Torvalds goto out; 5871da177e4SLinus Torvalds } 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds if (sctp_assoc_lookup_laddr(asoc, addr)) 5901da177e4SLinus Torvalds break; 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 5931da177e4SLinus Torvalds } 5941da177e4SLinus Torvalds if (i < addrcnt) 5951da177e4SLinus Torvalds continue; 5961da177e4SLinus Torvalds 597559cf710SVlad Yasevich /* Use the first valid address in bind addr list of 598559cf710SVlad Yasevich * association as Address Parameter of ASCONF CHUNK. 5991da177e4SLinus Torvalds */ 6001da177e4SLinus Torvalds bp = &asoc->base.bind_addr; 6011da177e4SLinus Torvalds p = bp->address_list.next; 6021da177e4SLinus Torvalds laddr = list_entry(p, struct sctp_sockaddr_entry, list); 6035ae955cfSAl Viro chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs, 6041da177e4SLinus Torvalds addrcnt, SCTP_PARAM_ADD_IP); 6051da177e4SLinus Torvalds if (!chunk) { 6061da177e4SLinus Torvalds retval = -ENOMEM; 6071da177e4SLinus Torvalds goto out; 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds 610dc022a98SSridhar Samudrala /* Add the new addresses to the bind address list with 611dc022a98SSridhar Samudrala * use_as_src set to 0. 6121da177e4SLinus Torvalds */ 613dc022a98SSridhar Samudrala addr_buf = addrs; 614dc022a98SSridhar Samudrala for (i = 0; i < addrcnt; i++) { 615ea110733SJoe Perches addr = addr_buf; 616dc022a98SSridhar Samudrala af = sctp_get_af_specific(addr->v4.sin_family); 617dc022a98SSridhar Samudrala memcpy(&saveaddr, addr, af->sockaddr_len); 618f57d96b2SVlad Yasevich retval = sctp_add_bind_addr(bp, &saveaddr, 619133800d1SMarcelo Ricardo Leitner sizeof(saveaddr), 620f57d96b2SVlad Yasevich SCTP_ADDR_NEW, GFP_ATOMIC); 621dc022a98SSridhar Samudrala addr_buf += af->sockaddr_len; 622dc022a98SSridhar Samudrala } 6238a07eb0aSMichio Honda if (asoc->src_out_of_asoc_ok) { 6248a07eb0aSMichio Honda struct sctp_transport *trans; 6258a07eb0aSMichio Honda 6268a07eb0aSMichio Honda list_for_each_entry(trans, 6278a07eb0aSMichio Honda &asoc->peer.transport_addr_list, transports) { 6288a07eb0aSMichio Honda trans->cwnd = min(4*asoc->pathmtu, max_t(__u32, 6298a07eb0aSMichio Honda 2*asoc->pathmtu, 4380)); 6308a07eb0aSMichio Honda trans->ssthresh = asoc->peer.i.a_rwnd; 6318a07eb0aSMichio Honda trans->rto = asoc->rto_initial; 632196d6759SMichele Baldessari sctp_max_rto(asoc, trans); 6338a07eb0aSMichio Honda trans->rtt = trans->srtt = trans->rttvar = 0; 6346e91b578SMarcelo Ricardo Leitner /* Clear the source and route cache */ 6358a07eb0aSMichio Honda sctp_transport_route(trans, NULL, 6368a07eb0aSMichio Honda sctp_sk(asoc->base.sk)); 6378a07eb0aSMichio Honda } 6388a07eb0aSMichio Honda } 6398a07eb0aSMichio Honda retval = sctp_send_asconf(asoc, chunk); 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds out: 6431da177e4SLinus Torvalds return retval; 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds /* Remove a list of addresses from bind addresses list. Do not remove the 6471da177e4SLinus Torvalds * last address. 6481da177e4SLinus Torvalds * 6491da177e4SLinus Torvalds * Basically run through each address specified in the addrs/addrcnt 6501da177e4SLinus Torvalds * array/length pair, determine if it is IPv6 or IPv4 and call 6511da177e4SLinus Torvalds * sctp_del_bind() on it. 6521da177e4SLinus Torvalds * 6531da177e4SLinus Torvalds * If any of them fails, then the operation will be reversed and the 6541da177e4SLinus Torvalds * ones that were removed will be added back. 6551da177e4SLinus Torvalds * 6561da177e4SLinus Torvalds * At least one address has to be left; if only one address is 6571da177e4SLinus Torvalds * available, the operation will return -EBUSY. 6581da177e4SLinus Torvalds * 6591da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 6601da177e4SLinus Torvalds */ 66104675210Ssebastian@breakpoint.cc static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) 6621da177e4SLinus Torvalds { 6631da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 6641da177e4SLinus Torvalds struct sctp_endpoint *ep = sp->ep; 6651da177e4SLinus Torvalds int cnt; 6661da177e4SLinus Torvalds struct sctp_bind_addr *bp = &ep->base.bind_addr; 6671da177e4SLinus Torvalds int retval = 0; 6681da177e4SLinus Torvalds void *addr_buf; 669c9a08505SAl Viro union sctp_addr *sa_addr; 6701da177e4SLinus Torvalds struct sctp_af *af; 6711da177e4SLinus Torvalds 672bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 673bb33381dSDaniel Borkmann __func__, sk, addrs, addrcnt); 6741da177e4SLinus Torvalds 6751da177e4SLinus Torvalds addr_buf = addrs; 6761da177e4SLinus Torvalds for (cnt = 0; cnt < addrcnt; cnt++) { 6771da177e4SLinus Torvalds /* If the bind address list is empty or if there is only one 6781da177e4SLinus Torvalds * bind address, there is nothing more to be removed (we need 6791da177e4SLinus Torvalds * at least one address here). 6801da177e4SLinus Torvalds */ 6811da177e4SLinus Torvalds if (list_empty(&bp->address_list) || 6821da177e4SLinus Torvalds (sctp_list_single_entry(&bp->address_list))) { 6831da177e4SLinus Torvalds retval = -EBUSY; 6841da177e4SLinus Torvalds goto err_bindx_rem; 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds 687ea110733SJoe Perches sa_addr = addr_buf; 688c9a08505SAl Viro af = sctp_get_af_specific(sa_addr->sa.sa_family); 6891da177e4SLinus Torvalds if (!af) { 6901da177e4SLinus Torvalds retval = -EINVAL; 6911da177e4SLinus Torvalds goto err_bindx_rem; 6921da177e4SLinus Torvalds } 6930304ff8aSPaolo Galtieri 6940304ff8aSPaolo Galtieri if (!af->addr_valid(sa_addr, sp, NULL)) { 6950304ff8aSPaolo Galtieri retval = -EADDRNOTAVAIL; 6960304ff8aSPaolo Galtieri goto err_bindx_rem; 6970304ff8aSPaolo Galtieri } 6980304ff8aSPaolo Galtieri 699ee9cbacaSVlad Yasevich if (sa_addr->v4.sin_port && 700ee9cbacaSVlad Yasevich sa_addr->v4.sin_port != htons(bp->port)) { 7011da177e4SLinus Torvalds retval = -EINVAL; 7021da177e4SLinus Torvalds goto err_bindx_rem; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds 705ee9cbacaSVlad Yasevich if (!sa_addr->v4.sin_port) 706ee9cbacaSVlad Yasevich sa_addr->v4.sin_port = htons(bp->port); 707ee9cbacaSVlad Yasevich 7081da177e4SLinus Torvalds /* FIXME - There is probably a need to check if sk->sk_saddr and 7091da177e4SLinus Torvalds * sk->sk_rcv_addr are currently set to one of the addresses to 7101da177e4SLinus Torvalds * be removed. This is something which needs to be looked into 7111da177e4SLinus Torvalds * when we are fixing the outstanding issues with multi-homing 7121da177e4SLinus Torvalds * socket routing and failover schemes. Refer to comments in 7131da177e4SLinus Torvalds * sctp_do_bind(). -daisy 7141da177e4SLinus Torvalds */ 7150ed90fb0SVlad Yasevich retval = sctp_del_bind_addr(bp, sa_addr); 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 7181da177e4SLinus Torvalds err_bindx_rem: 7191da177e4SLinus Torvalds if (retval < 0) { 7201da177e4SLinus Torvalds /* Failed. Add the ones that has been removed back */ 7211da177e4SLinus Torvalds if (cnt > 0) 7221da177e4SLinus Torvalds sctp_bindx_add(sk, addrs, cnt); 7231da177e4SLinus Torvalds return retval; 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds } 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds return retval; 7281da177e4SLinus Torvalds } 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds /* Send an ASCONF chunk with Delete IP address parameters to all the peers of 7311da177e4SLinus Torvalds * the associations that are part of the endpoint indicating that a list of 7321da177e4SLinus Torvalds * local addresses are removed from the endpoint. 7331da177e4SLinus Torvalds * 7341da177e4SLinus Torvalds * If any of the addresses is already in the bind address list of the 7351da177e4SLinus Torvalds * association, we do not send the chunk for that association. But it will not 7361da177e4SLinus Torvalds * affect other associations. 7371da177e4SLinus Torvalds * 7381da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 7391da177e4SLinus Torvalds */ 7401da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock *sk, 7411da177e4SLinus Torvalds struct sockaddr *addrs, 7421da177e4SLinus Torvalds int addrcnt) 7431da177e4SLinus Torvalds { 7441da177e4SLinus Torvalds struct sctp_sock *sp; 7451da177e4SLinus Torvalds struct sctp_endpoint *ep; 7461da177e4SLinus Torvalds struct sctp_association *asoc; 747dc022a98SSridhar Samudrala struct sctp_transport *transport; 7481da177e4SLinus Torvalds struct sctp_bind_addr *bp; 7491da177e4SLinus Torvalds struct sctp_chunk *chunk; 7501da177e4SLinus Torvalds union sctp_addr *laddr; 7511da177e4SLinus Torvalds void *addr_buf; 7521da177e4SLinus Torvalds struct sctp_af *af; 753dc022a98SSridhar Samudrala struct sctp_sockaddr_entry *saddr; 7541da177e4SLinus Torvalds int i; 7551da177e4SLinus Torvalds int retval = 0; 7568a07eb0aSMichio Honda int stored = 0; 7571da177e4SLinus Torvalds 7588a07eb0aSMichio Honda chunk = NULL; 7591da177e4SLinus Torvalds sp = sctp_sk(sk); 7601da177e4SLinus Torvalds ep = sp->ep; 7611da177e4SLinus Torvalds 7624e27428fSXin Long if (!ep->asconf_enable) 7634e27428fSXin Long return retval; 7644e27428fSXin Long 765bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 7660dc47877SHarvey Harrison __func__, sk, addrs, addrcnt); 7671da177e4SLinus Torvalds 7689dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &ep->asocs, asocs) { 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 7711da177e4SLinus Torvalds continue; 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_DEL_IP) 7741da177e4SLinus Torvalds continue; 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 7771da177e4SLinus Torvalds continue; 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds /* Check if any address in the packed array of addresses is 7801da177e4SLinus Torvalds * not present in the bind address list of the association. 7811da177e4SLinus Torvalds * If so, do not send the asconf chunk to its peer, but 7821da177e4SLinus Torvalds * continue with other associations. 7831da177e4SLinus Torvalds */ 7841da177e4SLinus Torvalds addr_buf = addrs; 7851da177e4SLinus Torvalds for (i = 0; i < addrcnt; i++) { 786ea110733SJoe Perches laddr = addr_buf; 7871da177e4SLinus Torvalds af = sctp_get_af_specific(laddr->v4.sin_family); 7881da177e4SLinus Torvalds if (!af) { 7891da177e4SLinus Torvalds retval = -EINVAL; 7901da177e4SLinus Torvalds goto out; 7911da177e4SLinus Torvalds } 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds if (!sctp_assoc_lookup_laddr(asoc, laddr)) 7941da177e4SLinus Torvalds break; 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 7971da177e4SLinus Torvalds } 7981da177e4SLinus Torvalds if (i < addrcnt) 7991da177e4SLinus Torvalds continue; 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds /* Find one address in the association's bind address list 8021da177e4SLinus Torvalds * that is not in the packed array of addresses. This is to 8031da177e4SLinus Torvalds * make sure that we do not delete all the addresses in the 8041da177e4SLinus Torvalds * association. 8051da177e4SLinus Torvalds */ 8061da177e4SLinus Torvalds bp = &asoc->base.bind_addr; 8071da177e4SLinus Torvalds laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, 8081da177e4SLinus Torvalds addrcnt, sp); 8098a07eb0aSMichio Honda if ((laddr == NULL) && (addrcnt == 1)) { 8108a07eb0aSMichio Honda if (asoc->asconf_addr_del_pending) 8111da177e4SLinus Torvalds continue; 8128a07eb0aSMichio Honda asoc->asconf_addr_del_pending = 8138a07eb0aSMichio Honda kzalloc(sizeof(union sctp_addr), GFP_ATOMIC); 8146d65e5eeSMichio Honda if (asoc->asconf_addr_del_pending == NULL) { 8156d65e5eeSMichio Honda retval = -ENOMEM; 8166d65e5eeSMichio Honda goto out; 8176d65e5eeSMichio Honda } 8188a07eb0aSMichio Honda asoc->asconf_addr_del_pending->sa.sa_family = 8198a07eb0aSMichio Honda addrs->sa_family; 8208a07eb0aSMichio Honda asoc->asconf_addr_del_pending->v4.sin_port = 8218a07eb0aSMichio Honda htons(bp->port); 8228a07eb0aSMichio Honda if (addrs->sa_family == AF_INET) { 8238a07eb0aSMichio Honda struct sockaddr_in *sin; 8248a07eb0aSMichio Honda 8258a07eb0aSMichio Honda sin = (struct sockaddr_in *)addrs; 8268a07eb0aSMichio Honda asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr; 8278a07eb0aSMichio Honda } else if (addrs->sa_family == AF_INET6) { 8288a07eb0aSMichio Honda struct sockaddr_in6 *sin6; 8298a07eb0aSMichio Honda 8308a07eb0aSMichio Honda sin6 = (struct sockaddr_in6 *)addrs; 8314e3fd7a0SAlexey Dobriyan asoc->asconf_addr_del_pending->v6.sin6_addr = sin6->sin6_addr; 8328a07eb0aSMichio Honda } 833bb33381dSDaniel Borkmann 834bb33381dSDaniel Borkmann pr_debug("%s: keep the last address asoc:%p %pISc at %p\n", 835bb33381dSDaniel Borkmann __func__, asoc, &asoc->asconf_addr_del_pending->sa, 8368a07eb0aSMichio Honda asoc->asconf_addr_del_pending); 837bb33381dSDaniel Borkmann 8388a07eb0aSMichio Honda asoc->src_out_of_asoc_ok = 1; 8398a07eb0aSMichio Honda stored = 1; 8408a07eb0aSMichio Honda goto skip_mkasconf; 8418a07eb0aSMichio Honda } 8421da177e4SLinus Torvalds 84388362ad8SDaniel Borkmann if (laddr == NULL) 84488362ad8SDaniel Borkmann return -EINVAL; 84588362ad8SDaniel Borkmann 846559cf710SVlad Yasevich /* We do not need RCU protection throughout this loop 847559cf710SVlad Yasevich * because this is done under a socket lock from the 848559cf710SVlad Yasevich * setsockopt call. 849559cf710SVlad Yasevich */ 8501da177e4SLinus Torvalds chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt, 8511da177e4SLinus Torvalds SCTP_PARAM_DEL_IP); 8521da177e4SLinus Torvalds if (!chunk) { 8531da177e4SLinus Torvalds retval = -ENOMEM; 8541da177e4SLinus Torvalds goto out; 8551da177e4SLinus Torvalds } 8561da177e4SLinus Torvalds 8578a07eb0aSMichio Honda skip_mkasconf: 858dc022a98SSridhar Samudrala /* Reset use_as_src flag for the addresses in the bind address 859dc022a98SSridhar Samudrala * list that are to be deleted. 8601da177e4SLinus Torvalds */ 861dc022a98SSridhar Samudrala addr_buf = addrs; 862dc022a98SSridhar Samudrala for (i = 0; i < addrcnt; i++) { 863ea110733SJoe Perches laddr = addr_buf; 864dc022a98SSridhar Samudrala af = sctp_get_af_specific(laddr->v4.sin_family); 865559cf710SVlad Yasevich list_for_each_entry(saddr, &bp->address_list, list) { 8665f242a13SAl Viro if (sctp_cmp_addr_exact(&saddr->a, laddr)) 867f57d96b2SVlad Yasevich saddr->state = SCTP_ADDR_DEL; 868dc022a98SSridhar Samudrala } 869dc022a98SSridhar Samudrala addr_buf += af->sockaddr_len; 870dc022a98SSridhar Samudrala } 871dc022a98SSridhar Samudrala 872dc022a98SSridhar Samudrala /* Update the route and saddr entries for all the transports 873dc022a98SSridhar Samudrala * as some of the addresses in the bind address list are 874dc022a98SSridhar Samudrala * about to be deleted and cannot be used as source addresses. 875dc022a98SSridhar Samudrala */ 8769dbc15f0SRobert P. J. Day list_for_each_entry(transport, &asoc->peer.transport_addr_list, 8779dbc15f0SRobert P. J. Day transports) { 878dc022a98SSridhar Samudrala sctp_transport_route(transport, NULL, 879dc022a98SSridhar Samudrala sctp_sk(asoc->base.sk)); 880dc022a98SSridhar Samudrala } 881dc022a98SSridhar Samudrala 8828a07eb0aSMichio Honda if (stored) 8838a07eb0aSMichio Honda /* We don't need to transmit ASCONF */ 8848a07eb0aSMichio Honda continue; 885dc022a98SSridhar Samudrala retval = sctp_send_asconf(asoc, chunk); 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds out: 8881da177e4SLinus Torvalds return retval; 8891da177e4SLinus Torvalds } 8901da177e4SLinus Torvalds 8919f7d653bSMichio Honda /* set addr events to assocs in the endpoint. ep and addr_wq must be locked */ 8929f7d653bSMichio Honda int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw) 8939f7d653bSMichio Honda { 8949f7d653bSMichio Honda struct sock *sk = sctp_opt2sk(sp); 8959f7d653bSMichio Honda union sctp_addr *addr; 8969f7d653bSMichio Honda struct sctp_af *af; 8979f7d653bSMichio Honda 8989f7d653bSMichio Honda /* It is safe to write port space in caller. */ 8999f7d653bSMichio Honda addr = &addrw->a; 9009f7d653bSMichio Honda addr->v4.sin_port = htons(sp->ep->base.bind_addr.port); 9019f7d653bSMichio Honda af = sctp_get_af_specific(addr->sa.sa_family); 9029f7d653bSMichio Honda if (!af) 9039f7d653bSMichio Honda return -EINVAL; 9049f7d653bSMichio Honda if (sctp_verify_addr(sk, addr, af->sockaddr_len)) 9059f7d653bSMichio Honda return -EINVAL; 9069f7d653bSMichio Honda 9079f7d653bSMichio Honda if (addrw->state == SCTP_ADDR_NEW) 9089f7d653bSMichio Honda return sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1); 9099f7d653bSMichio Honda else 9109f7d653bSMichio Honda return sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1); 9119f7d653bSMichio Honda } 9129f7d653bSMichio Honda 9131da177e4SLinus Torvalds /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt() 9141da177e4SLinus Torvalds * 9151da177e4SLinus Torvalds * API 8.1 9161da177e4SLinus Torvalds * int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, 9171da177e4SLinus Torvalds * int flags); 9181da177e4SLinus Torvalds * 9191da177e4SLinus Torvalds * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. 9201da177e4SLinus Torvalds * If the sd is an IPv6 socket, the addresses passed can either be IPv4 9211da177e4SLinus Torvalds * or IPv6 addresses. 9221da177e4SLinus Torvalds * 9231da177e4SLinus Torvalds * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see 9241da177e4SLinus Torvalds * Section 3.1.2 for this usage. 9251da177e4SLinus Torvalds * 9261da177e4SLinus Torvalds * addrs is a pointer to an array of one or more socket addresses. Each 9271da177e4SLinus Torvalds * address is contained in its appropriate structure (i.e. struct 9281da177e4SLinus Torvalds * sockaddr_in or struct sockaddr_in6) the family of the address type 92923c435f7SVille Nuorvala * must be used to distinguish the address length (note that this 9301da177e4SLinus Torvalds * representation is termed a "packed array" of addresses). The caller 9311da177e4SLinus Torvalds * specifies the number of addresses in the array with addrcnt. 9321da177e4SLinus Torvalds * 9331da177e4SLinus Torvalds * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns 9341da177e4SLinus Torvalds * -1, and sets errno to the appropriate error code. 9351da177e4SLinus Torvalds * 9361da177e4SLinus Torvalds * For SCTP, the port given in each socket address must be the same, or 9371da177e4SLinus Torvalds * sctp_bindx() will fail, setting errno to EINVAL. 9381da177e4SLinus Torvalds * 9391da177e4SLinus Torvalds * The flags parameter is formed from the bitwise OR of zero or more of 9401da177e4SLinus Torvalds * the following currently defined flags: 9411da177e4SLinus Torvalds * 9421da177e4SLinus Torvalds * SCTP_BINDX_ADD_ADDR 9431da177e4SLinus Torvalds * 9441da177e4SLinus Torvalds * SCTP_BINDX_REM_ADDR 9451da177e4SLinus Torvalds * 9461da177e4SLinus Torvalds * SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the 9471da177e4SLinus Torvalds * association, and SCTP_BINDX_REM_ADDR directs SCTP to remove the given 9481da177e4SLinus Torvalds * addresses from the association. The two flags are mutually exclusive; 9491da177e4SLinus Torvalds * if both are given, sctp_bindx() will fail with EINVAL. A caller may 9501da177e4SLinus Torvalds * not remove all addresses from an association; sctp_bindx() will 9511da177e4SLinus Torvalds * reject such an attempt with EINVAL. 9521da177e4SLinus Torvalds * 9531da177e4SLinus Torvalds * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate 9541da177e4SLinus Torvalds * additional addresses with an endpoint after calling bind(). Or use 9551da177e4SLinus Torvalds * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening 9561da177e4SLinus Torvalds * socket is associated with so that no new association accepted will be 9571da177e4SLinus Torvalds * associated with those addresses. If the endpoint supports dynamic 9581da177e4SLinus Torvalds * address a SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR may cause a 9591da177e4SLinus Torvalds * endpoint to send the appropriate message to the peer to change the 9601da177e4SLinus Torvalds * peers address lists. 9611da177e4SLinus Torvalds * 9621da177e4SLinus Torvalds * Adding and removing addresses from a connected association is 9631da177e4SLinus Torvalds * optional functionality. Implementations that do not support this 9641da177e4SLinus Torvalds * functionality should return EOPNOTSUPP. 9651da177e4SLinus Torvalds * 9661da177e4SLinus Torvalds * Basically do nothing but copying the addresses from user to kernel 9671da177e4SLinus Torvalds * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk. 9683f7a87d2SFrank Filz * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() 9693f7a87d2SFrank Filz * from userspace. 9701da177e4SLinus Torvalds * 9711da177e4SLinus Torvalds * On exit there is no need to do sockfd_put(), sys_setsockopt() does 9721da177e4SLinus Torvalds * it. 9731da177e4SLinus Torvalds * 9741da177e4SLinus Torvalds * sk The sk of the socket 97505bfd366SChristoph Hellwig * addrs The pointer to the addresses 9761da177e4SLinus Torvalds * addrssize Size of the addrs buffer 9771da177e4SLinus Torvalds * op Operation to perform (add or remove, see the flags of 9781da177e4SLinus Torvalds * sctp_bindx) 9791da177e4SLinus Torvalds * 9801da177e4SLinus Torvalds * Returns 0 if ok, <0 errno code on error. 9811da177e4SLinus Torvalds */ 9828c7517f5SChristoph Hellwig static int sctp_setsockopt_bindx(struct sock *sk, struct sockaddr *addrs, 9838c7517f5SChristoph Hellwig int addrs_size, int op) 9841da177e4SLinus Torvalds { 9851da177e4SLinus Torvalds int err; 9861da177e4SLinus Torvalds int addrcnt = 0; 9871da177e4SLinus Torvalds int walk_size = 0; 9881da177e4SLinus Torvalds struct sockaddr *sa_addr; 98905bfd366SChristoph Hellwig void *addr_buf = addrs; 9901da177e4SLinus Torvalds struct sctp_af *af; 9911da177e4SLinus Torvalds 992bb33381dSDaniel Borkmann pr_debug("%s: sk:%p addrs:%p addrs_size:%d opt:%d\n", 9938c7517f5SChristoph Hellwig __func__, sk, addr_buf, addrs_size, op); 9941da177e4SLinus Torvalds 9951da177e4SLinus Torvalds if (unlikely(addrs_size <= 0)) 9961da177e4SLinus Torvalds return -EINVAL; 9971da177e4SLinus Torvalds 9981da177e4SLinus Torvalds /* Walk through the addrs buffer and count the number of addresses. */ 9991da177e4SLinus Torvalds while (walk_size < addrs_size) { 100005bfd366SChristoph Hellwig if (walk_size + sizeof(sa_family_t) > addrs_size) 1001d7e0d19aSDan Rosenberg return -EINVAL; 1002d7e0d19aSDan Rosenberg 1003ea110733SJoe Perches sa_addr = addr_buf; 10041da177e4SLinus Torvalds af = sctp_get_af_specific(sa_addr->sa_family); 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds /* If the address family is not supported or if this address 10071da177e4SLinus Torvalds * causes the address buffer to overflow return EINVAL. 10081da177e4SLinus Torvalds */ 100905bfd366SChristoph Hellwig if (!af || (walk_size + af->sockaddr_len) > addrs_size) 10101da177e4SLinus Torvalds return -EINVAL; 10111da177e4SLinus Torvalds addrcnt++; 10121da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 10131da177e4SLinus Torvalds walk_size += af->sockaddr_len; 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds /* Do the work. */ 10171da177e4SLinus Torvalds switch (op) { 10181da177e4SLinus Torvalds case SCTP_BINDX_ADD_ADDR: 10192277c7cdSRichard Haines /* Allow security module to validate bindx addresses. */ 10202277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_BINDX_ADD, 102105bfd366SChristoph Hellwig addrs, addrs_size); 10222277c7cdSRichard Haines if (err) 102305bfd366SChristoph Hellwig return err; 102405bfd366SChristoph Hellwig err = sctp_bindx_add(sk, addrs, addrcnt); 10251da177e4SLinus Torvalds if (err) 102605bfd366SChristoph Hellwig return err; 102705bfd366SChristoph Hellwig return sctp_send_asconf_add_ip(sk, addrs, addrcnt); 10281da177e4SLinus Torvalds case SCTP_BINDX_REM_ADDR: 102905bfd366SChristoph Hellwig err = sctp_bindx_rem(sk, addrs, addrcnt); 10301da177e4SLinus Torvalds if (err) 103105bfd366SChristoph Hellwig return err; 103205bfd366SChristoph Hellwig return sctp_send_asconf_del_ip(sk, addrs, addrcnt); 10331da177e4SLinus Torvalds 10341da177e4SLinus Torvalds default: 103505bfd366SChristoph Hellwig return -EINVAL; 103605bfd366SChristoph Hellwig } 10373ff50b79SStephen Hemminger } 10381da177e4SLinus Torvalds 1039c0425a42SChristoph Hellwig static int sctp_bind_add(struct sock *sk, struct sockaddr *addrs, 1040c0425a42SChristoph Hellwig int addrlen) 1041c0425a42SChristoph Hellwig { 1042c0425a42SChristoph Hellwig int err; 1043c0425a42SChristoph Hellwig 1044c0425a42SChristoph Hellwig lock_sock(sk); 10458c7517f5SChristoph Hellwig err = sctp_setsockopt_bindx(sk, addrs, addrlen, SCTP_BINDX_ADD_ADDR); 1046c0425a42SChristoph Hellwig release_sock(sk); 1047c0425a42SChristoph Hellwig return err; 1048c0425a42SChristoph Hellwig } 1049c0425a42SChristoph Hellwig 1050f26f9951SXin Long static int sctp_connect_new_asoc(struct sctp_endpoint *ep, 1051f26f9951SXin Long const union sctp_addr *daddr, 1052f26f9951SXin Long const struct sctp_initmsg *init, 1053f26f9951SXin Long struct sctp_transport **tp) 1054f26f9951SXin Long { 1055f26f9951SXin Long struct sctp_association *asoc; 1056f26f9951SXin Long struct sock *sk = ep->base.sk; 1057f26f9951SXin Long struct net *net = sock_net(sk); 1058f26f9951SXin Long enum sctp_scope scope; 1059f26f9951SXin Long int err; 1060f26f9951SXin Long 1061f26f9951SXin Long if (sctp_endpoint_is_peeled_off(ep, daddr)) 1062f26f9951SXin Long return -EADDRNOTAVAIL; 1063f26f9951SXin Long 1064f26f9951SXin Long if (!ep->base.bind_addr.port) { 1065f26f9951SXin Long if (sctp_autobind(sk)) 1066f26f9951SXin Long return -EAGAIN; 1067f26f9951SXin Long } else { 106882f31ebfSMaciej Żenczykowski if (inet_port_requires_bind_service(net, ep->base.bind_addr.port) && 1069f26f9951SXin Long !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 1070f26f9951SXin Long return -EACCES; 1071f26f9951SXin Long } 1072f26f9951SXin Long 1073f26f9951SXin Long scope = sctp_scope(daddr); 1074f26f9951SXin Long asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); 1075f26f9951SXin Long if (!asoc) 1076f26f9951SXin Long return -ENOMEM; 1077f26f9951SXin Long 1078f26f9951SXin Long err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL); 1079f26f9951SXin Long if (err < 0) 1080f26f9951SXin Long goto free; 1081f26f9951SXin Long 1082f26f9951SXin Long *tp = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN); 1083f26f9951SXin Long if (!*tp) { 1084f26f9951SXin Long err = -ENOMEM; 1085f26f9951SXin Long goto free; 1086f26f9951SXin Long } 1087f26f9951SXin Long 1088f26f9951SXin Long if (!init) 1089f26f9951SXin Long return 0; 1090f26f9951SXin Long 1091f26f9951SXin Long if (init->sinit_num_ostreams) { 1092f26f9951SXin Long __u16 outcnt = init->sinit_num_ostreams; 1093f26f9951SXin Long 1094f26f9951SXin Long asoc->c.sinit_num_ostreams = outcnt; 1095f26f9951SXin Long /* outcnt has been changed, need to re-init stream */ 1096f26f9951SXin Long err = sctp_stream_init(&asoc->stream, outcnt, 0, GFP_KERNEL); 1097f26f9951SXin Long if (err) 1098f26f9951SXin Long goto free; 1099f26f9951SXin Long } 1100f26f9951SXin Long 1101f26f9951SXin Long if (init->sinit_max_instreams) 1102f26f9951SXin Long asoc->c.sinit_max_instreams = init->sinit_max_instreams; 1103f26f9951SXin Long 1104f26f9951SXin Long if (init->sinit_max_attempts) 1105f26f9951SXin Long asoc->max_init_attempts = init->sinit_max_attempts; 1106f26f9951SXin Long 1107f26f9951SXin Long if (init->sinit_max_init_timeo) 1108f26f9951SXin Long asoc->max_init_timeo = 1109f26f9951SXin Long msecs_to_jiffies(init->sinit_max_init_timeo); 1110f26f9951SXin Long 1111f26f9951SXin Long return 0; 1112f26f9951SXin Long free: 1113f26f9951SXin Long sctp_association_free(asoc); 1114f26f9951SXin Long return err; 1115f26f9951SXin Long } 1116f26f9951SXin Long 1117a64e59c7SXin Long static int sctp_connect_add_peer(struct sctp_association *asoc, 1118a64e59c7SXin Long union sctp_addr *daddr, int addr_len) 1119a64e59c7SXin Long { 1120a64e59c7SXin Long struct sctp_endpoint *ep = asoc->ep; 1121a64e59c7SXin Long struct sctp_association *old; 1122a64e59c7SXin Long struct sctp_transport *t; 1123a64e59c7SXin Long int err; 1124a64e59c7SXin Long 1125a64e59c7SXin Long err = sctp_verify_addr(ep->base.sk, daddr, addr_len); 1126a64e59c7SXin Long if (err) 1127a64e59c7SXin Long return err; 1128a64e59c7SXin Long 1129a64e59c7SXin Long old = sctp_endpoint_lookup_assoc(ep, daddr, &t); 1130a64e59c7SXin Long if (old && old != asoc) 1131a64e59c7SXin Long return old->state >= SCTP_STATE_ESTABLISHED ? -EISCONN 1132a64e59c7SXin Long : -EALREADY; 1133a64e59c7SXin Long 1134a64e59c7SXin Long if (sctp_endpoint_is_peeled_off(ep, daddr)) 1135a64e59c7SXin Long return -EADDRNOTAVAIL; 1136a64e59c7SXin Long 1137a64e59c7SXin Long t = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN); 1138a64e59c7SXin Long if (!t) 1139a64e59c7SXin Long return -ENOMEM; 1140a64e59c7SXin Long 1141a64e59c7SXin Long return 0; 1142a64e59c7SXin Long } 1143a64e59c7SXin Long 11443f7a87d2SFrank Filz /* __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, int addrs_size) 11453f7a87d2SFrank Filz * 11463f7a87d2SFrank Filz * Common routine for handling connect() and sctp_connectx(). 11473f7a87d2SFrank Filz * Connect will come in with just a single address. 11483f7a87d2SFrank Filz */ 1149dd8378b3SXin Long static int __sctp_connect(struct sock *sk, struct sockaddr *kaddrs, 1150dd8378b3SXin Long int addrs_size, int flags, sctp_assoc_t *assoc_id) 11513f7a87d2SFrank Filz { 1152dd8378b3SXin Long struct sctp_sock *sp = sctp_sk(sk); 1153dd8378b3SXin Long struct sctp_endpoint *ep = sp->ep; 11543f7a87d2SFrank Filz struct sctp_transport *transport; 1155a64e59c7SXin Long struct sctp_association *asoc; 1156dd8378b3SXin Long void *addr_buf = kaddrs; 1157dd8378b3SXin Long union sctp_addr *daddr; 1158299ee123SJason Gunthorpe struct sctp_af *af; 1159dd8378b3SXin Long int walk_size, err; 1160dd8378b3SXin Long long timeo; 1161299ee123SJason Gunthorpe 1162dd8378b3SXin Long if (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING) || 1163dd8378b3SXin Long (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) 1164dd8378b3SXin Long return -EISCONN; 1165d7e0d19aSDan Rosenberg 1166dd8378b3SXin Long daddr = addr_buf; 1167dd8378b3SXin Long af = sctp_get_af_specific(daddr->sa.sa_family); 1168dd8378b3SXin Long if (!af || af->sockaddr_len > addrs_size) 1169dd8378b3SXin Long return -EINVAL; 11703f7a87d2SFrank Filz 1171dd8378b3SXin Long err = sctp_verify_addr(sk, daddr, af->sockaddr_len); 11723f7a87d2SFrank Filz if (err) 1173dd8378b3SXin Long return err; 11743f7a87d2SFrank Filz 1175dd8378b3SXin Long asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport); 1176dd8378b3SXin Long if (asoc) 1177dd8378b3SXin Long return asoc->state >= SCTP_STATE_ESTABLISHED ? -EISCONN 1178dd8378b3SXin Long : -EALREADY; 11793f7a87d2SFrank Filz 1180f26f9951SXin Long err = sctp_connect_new_asoc(ep, daddr, NULL, &transport); 1181f26f9951SXin Long if (err) 1182f26f9951SXin Long return err; 1183f26f9951SXin Long asoc = transport->asoc; 1184409b95afSVlad Yasevich 1185dd8378b3SXin Long addr_buf += af->sockaddr_len; 1186dd8378b3SXin Long walk_size = af->sockaddr_len; 1187dd8378b3SXin Long while (walk_size < addrs_size) { 1188dd8378b3SXin Long err = -EINVAL; 1189dd8378b3SXin Long if (walk_size + sizeof(sa_family_t) > addrs_size) 1190dd8378b3SXin Long goto out_free; 1191dd8378b3SXin Long 1192dd8378b3SXin Long daddr = addr_buf; 1193dd8378b3SXin Long af = sctp_get_af_specific(daddr->sa.sa_family); 1194dd8378b3SXin Long if (!af || af->sockaddr_len + walk_size > addrs_size) 1195dd8378b3SXin Long goto out_free; 1196dd8378b3SXin Long 1197dd8378b3SXin Long if (asoc->peer.port != ntohs(daddr->v4.sin_port)) 1198dd8378b3SXin Long goto out_free; 1199dd8378b3SXin Long 1200a64e59c7SXin Long err = sctp_connect_add_peer(asoc, daddr, af->sockaddr_len); 1201dd8378b3SXin Long if (err) 1202dd8378b3SXin Long goto out_free; 1203dd8378b3SXin Long 12043f7a87d2SFrank Filz addr_buf += af->sockaddr_len; 12053f7a87d2SFrank Filz walk_size += af->sockaddr_len; 12063f7a87d2SFrank Filz } 12073f7a87d2SFrank Filz 1208c6ba68a2SVlad Yasevich /* In case the user of sctp_connectx() wants an association 1209c6ba68a2SVlad Yasevich * id back, assign one now. 1210c6ba68a2SVlad Yasevich */ 1211c6ba68a2SVlad Yasevich if (assoc_id) { 1212c6ba68a2SVlad Yasevich err = sctp_assoc_set_id(asoc, GFP_KERNEL); 1213c6ba68a2SVlad Yasevich if (err < 0) 1214c6ba68a2SVlad Yasevich goto out_free; 1215c6ba68a2SVlad Yasevich } 1216c6ba68a2SVlad Yasevich 1217f26f9951SXin Long err = sctp_primitive_ASSOCIATE(sock_net(sk), asoc, NULL); 1218dd8378b3SXin Long if (err < 0) 12193f7a87d2SFrank Filz goto out_free; 12203f7a87d2SFrank Filz 12213f7a87d2SFrank Filz /* Initialize sk's dport and daddr for getpeername() */ 1222c720c7e8SEric Dumazet inet_sk(sk)->inet_dport = htons(asoc->peer.port); 1223dd8378b3SXin Long sp->pf->to_sk_daddr(daddr, sk); 12248de8c873SSridhar Samudrala sk->sk_err = 0; 12253f7a87d2SFrank Filz 12267233bc84SMarcelo Ricardo Leitner if (assoc_id) 122788a0a948SVlad Yasevich *assoc_id = asoc->assoc_id; 12282277c7cdSRichard Haines 1229dd8378b3SXin Long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); 1230dd8378b3SXin Long return sctp_wait_for_connect(asoc, &timeo); 12313f7a87d2SFrank Filz 12323f7a87d2SFrank Filz out_free: 1233bb33381dSDaniel Borkmann pr_debug("%s: took out_free path with asoc:%p kaddrs:%p err:%d\n", 1234bb33381dSDaniel Borkmann __func__, asoc, kaddrs, err); 12353f7a87d2SFrank Filz sctp_association_free(asoc); 12363f7a87d2SFrank Filz return err; 12373f7a87d2SFrank Filz } 12383f7a87d2SFrank Filz 12393f7a87d2SFrank Filz /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt() 12403f7a87d2SFrank Filz * 12413f7a87d2SFrank Filz * API 8.9 124288a0a948SVlad Yasevich * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt, 124388a0a948SVlad Yasevich * sctp_assoc_t *asoc); 12443f7a87d2SFrank Filz * 12453f7a87d2SFrank Filz * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. 12463f7a87d2SFrank Filz * If the sd is an IPv6 socket, the addresses passed can either be IPv4 12473f7a87d2SFrank Filz * or IPv6 addresses. 12483f7a87d2SFrank Filz * 12493f7a87d2SFrank Filz * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see 12503f7a87d2SFrank Filz * Section 3.1.2 for this usage. 12513f7a87d2SFrank Filz * 12523f7a87d2SFrank Filz * addrs is a pointer to an array of one or more socket addresses. Each 12533f7a87d2SFrank Filz * address is contained in its appropriate structure (i.e. struct 12543f7a87d2SFrank Filz * sockaddr_in or struct sockaddr_in6) the family of the address type 12553f7a87d2SFrank Filz * must be used to distengish the address length (note that this 12563f7a87d2SFrank Filz * representation is termed a "packed array" of addresses). The caller 12573f7a87d2SFrank Filz * specifies the number of addresses in the array with addrcnt. 12583f7a87d2SFrank Filz * 125988a0a948SVlad Yasevich * On success, sctp_connectx() returns 0. It also sets the assoc_id to 126088a0a948SVlad Yasevich * the association id of the new association. On failure, sctp_connectx() 126188a0a948SVlad Yasevich * returns -1, and sets errno to the appropriate error code. The assoc_id 126288a0a948SVlad Yasevich * is not touched by the kernel. 12633f7a87d2SFrank Filz * 12643f7a87d2SFrank Filz * For SCTP, the port given in each socket address must be the same, or 12653f7a87d2SFrank Filz * sctp_connectx() will fail, setting errno to EINVAL. 12663f7a87d2SFrank Filz * 12673f7a87d2SFrank Filz * An application can use sctp_connectx to initiate an association with 12683f7a87d2SFrank Filz * an endpoint that is multi-homed. Much like sctp_bindx() this call 12693f7a87d2SFrank Filz * allows a caller to specify multiple addresses at which a peer can be 12703f7a87d2SFrank Filz * reached. The way the SCTP stack uses the list of addresses to set up 127125985edcSLucas De Marchi * the association is implementation dependent. This function only 12723f7a87d2SFrank Filz * specifies that the stack will try to make use of all the addresses in 12733f7a87d2SFrank Filz * the list when needed. 12743f7a87d2SFrank Filz * 12753f7a87d2SFrank Filz * Note that the list of addresses passed in is only used for setting up 12763f7a87d2SFrank Filz * the association. It does not necessarily equal the set of addresses 12773f7a87d2SFrank Filz * the peer uses for the resulting association. If the caller wants to 12783f7a87d2SFrank Filz * find out the set of peer addresses, it must use sctp_getpaddrs() to 12793f7a87d2SFrank Filz * retrieve them after the association has been set up. 12803f7a87d2SFrank Filz * 12813f7a87d2SFrank Filz * Basically do nothing but copying the addresses from user to kernel 12823f7a87d2SFrank Filz * land and invoking either sctp_connectx(). This is used for tunneling 12833f7a87d2SFrank Filz * the sctp_connectx() request through sctp_setsockopt() from userspace. 12843f7a87d2SFrank Filz * 12853f7a87d2SFrank Filz * On exit there is no need to do sockfd_put(), sys_setsockopt() does 12863f7a87d2SFrank Filz * it. 12873f7a87d2SFrank Filz * 12883f7a87d2SFrank Filz * sk The sk of the socket 1289ce5b2f89SChristoph Hellwig * addrs The pointer to the addresses 12903f7a87d2SFrank Filz * addrssize Size of the addrs buffer 12913f7a87d2SFrank Filz * 129288a0a948SVlad Yasevich * Returns >=0 if ok, <0 errno code on error. 12933f7a87d2SFrank Filz */ 1294ce5b2f89SChristoph Hellwig static int __sctp_setsockopt_connectx(struct sock *sk, struct sockaddr *kaddrs, 1295ce5b2f89SChristoph Hellwig int addrs_size, sctp_assoc_t *assoc_id) 12963f7a87d2SFrank Filz { 1297644fbdeaSXin Long int err = 0, flags = 0; 12983f7a87d2SFrank Filz 1299bb33381dSDaniel Borkmann pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n", 1300ce5b2f89SChristoph Hellwig __func__, sk, kaddrs, addrs_size); 13013f7a87d2SFrank Filz 1302f40f1177SXin Long /* make sure the 1st addr's sa_family is accessible later */ 1303f40f1177SXin Long if (unlikely(addrs_size < sizeof(sa_family_t))) 13043f7a87d2SFrank Filz return -EINVAL; 13053f7a87d2SFrank Filz 13062277c7cdSRichard Haines /* Allow security module to validate connectx addresses. */ 13072277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX, 13082277c7cdSRichard Haines (struct sockaddr *)kaddrs, 13092277c7cdSRichard Haines addrs_size); 13102277c7cdSRichard Haines if (err) 1311ce5b2f89SChristoph Hellwig return err; 13122277c7cdSRichard Haines 1313644fbdeaSXin Long /* in-kernel sockets don't generally have a file allocated to them 1314644fbdeaSXin Long * if all they do is call sock_create_kern(). 1315644fbdeaSXin Long */ 1316644fbdeaSXin Long if (sk->sk_socket->file) 1317644fbdeaSXin Long flags = sk->sk_socket->file->f_flags; 1318644fbdeaSXin Long 1319ce5b2f89SChristoph Hellwig return __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id); 13203f7a87d2SFrank Filz } 13213f7a87d2SFrank Filz 132288a0a948SVlad Yasevich /* 132388a0a948SVlad Yasevich * This is an older interface. It's kept for backward compatibility 132488a0a948SVlad Yasevich * to the option that doesn't provide association id. 132588a0a948SVlad Yasevich */ 1326dda91928SDaniel Borkmann static int sctp_setsockopt_connectx_old(struct sock *sk, 1327ce5b2f89SChristoph Hellwig struct sockaddr *kaddrs, 132888a0a948SVlad Yasevich int addrs_size) 132988a0a948SVlad Yasevich { 1330ce5b2f89SChristoph Hellwig return __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, NULL); 133188a0a948SVlad Yasevich } 133288a0a948SVlad Yasevich 133388a0a948SVlad Yasevich /* 133488a0a948SVlad Yasevich * New interface for the API. The since the API is done with a socket 133588a0a948SVlad Yasevich * option, to make it simple we feed back the association id is as a return 133688a0a948SVlad Yasevich * indication to the call. Error is always negative and association id is 133788a0a948SVlad Yasevich * always positive. 133888a0a948SVlad Yasevich */ 1339dda91928SDaniel Borkmann static int sctp_setsockopt_connectx(struct sock *sk, 1340ce5b2f89SChristoph Hellwig struct sockaddr *kaddrs, 134188a0a948SVlad Yasevich int addrs_size) 134288a0a948SVlad Yasevich { 134388a0a948SVlad Yasevich sctp_assoc_t assoc_id = 0; 134488a0a948SVlad Yasevich int err = 0; 134588a0a948SVlad Yasevich 1346ce5b2f89SChristoph Hellwig err = __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, &assoc_id); 134788a0a948SVlad Yasevich 134888a0a948SVlad Yasevich if (err) 134988a0a948SVlad Yasevich return err; 135088a0a948SVlad Yasevich else 135188a0a948SVlad Yasevich return assoc_id; 135288a0a948SVlad Yasevich } 135388a0a948SVlad Yasevich 1354c6ba68a2SVlad Yasevich /* 1355f9c67811SVlad Yasevich * New (hopefully final) interface for the API. 1356f9c67811SVlad Yasevich * We use the sctp_getaddrs_old structure so that use-space library 1357ffd59393SDaniel Borkmann * can avoid any unnecessary allocations. The only different part 1358f9c67811SVlad Yasevich * is that we store the actual length of the address buffer into the 1359f9c67811SVlad Yasevich * addrs_num structure member. That way we can re-use the existing 1360f9c67811SVlad Yasevich * code. 1361c6ba68a2SVlad Yasevich */ 1362ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT 1363ffd59393SDaniel Borkmann struct compat_sctp_getaddrs_old { 1364ffd59393SDaniel Borkmann sctp_assoc_t assoc_id; 1365ffd59393SDaniel Borkmann s32 addr_num; 1366ffd59393SDaniel Borkmann compat_uptr_t addrs; /* struct sockaddr * */ 1367ffd59393SDaniel Borkmann }; 1368ffd59393SDaniel Borkmann #endif 1369ffd59393SDaniel Borkmann 1370dda91928SDaniel Borkmann static int sctp_getsockopt_connectx3(struct sock *sk, int len, 1371c6ba68a2SVlad Yasevich char __user *optval, 1372c6ba68a2SVlad Yasevich int __user *optlen) 1373c6ba68a2SVlad Yasevich { 1374f9c67811SVlad Yasevich struct sctp_getaddrs_old param; 1375c6ba68a2SVlad Yasevich sctp_assoc_t assoc_id = 0; 1376ce5b2f89SChristoph Hellwig struct sockaddr *kaddrs; 1377c6ba68a2SVlad Yasevich int err = 0; 1378c6ba68a2SVlad Yasevich 1379ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT 138096c0e0a9SAndy Lutomirski if (in_compat_syscall()) { 1381ffd59393SDaniel Borkmann struct compat_sctp_getaddrs_old param32; 1382c6ba68a2SVlad Yasevich 1383ffd59393SDaniel Borkmann if (len < sizeof(param32)) 1384ffd59393SDaniel Borkmann return -EINVAL; 1385ffd59393SDaniel Borkmann if (copy_from_user(¶m32, optval, sizeof(param32))) 1386f9c67811SVlad Yasevich return -EFAULT; 1387f9c67811SVlad Yasevich 1388ffd59393SDaniel Borkmann param.assoc_id = param32.assoc_id; 1389ffd59393SDaniel Borkmann param.addr_num = param32.addr_num; 1390ffd59393SDaniel Borkmann param.addrs = compat_ptr(param32.addrs); 1391ffd59393SDaniel Borkmann } else 1392ffd59393SDaniel Borkmann #endif 1393ffd59393SDaniel Borkmann { 1394ffd59393SDaniel Borkmann if (len < sizeof(param)) 1395ffd59393SDaniel Borkmann return -EINVAL; 1396ffd59393SDaniel Borkmann if (copy_from_user(¶m, optval, sizeof(param))) 1397ffd59393SDaniel Borkmann return -EFAULT; 1398ffd59393SDaniel Borkmann } 1399c6ba68a2SVlad Yasevich 1400ce5b2f89SChristoph Hellwig kaddrs = memdup_user(param.addrs, param.addr_num); 1401ce5b2f89SChristoph Hellwig if (IS_ERR(kaddrs)) 1402ce5b2f89SChristoph Hellwig return PTR_ERR(kaddrs); 1403ce5b2f89SChristoph Hellwig 1404ce5b2f89SChristoph Hellwig err = __sctp_setsockopt_connectx(sk, kaddrs, param.addr_num, &assoc_id); 1405ce5b2f89SChristoph Hellwig kfree(kaddrs); 1406c6ba68a2SVlad Yasevich if (err == 0 || err == -EINPROGRESS) { 1407c6ba68a2SVlad Yasevich if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) 1408c6ba68a2SVlad Yasevich return -EFAULT; 1409c6ba68a2SVlad Yasevich if (put_user(sizeof(assoc_id), optlen)) 1410c6ba68a2SVlad Yasevich return -EFAULT; 1411c6ba68a2SVlad Yasevich } 1412c6ba68a2SVlad Yasevich 1413c6ba68a2SVlad Yasevich return err; 1414c6ba68a2SVlad Yasevich } 1415c6ba68a2SVlad Yasevich 14161da177e4SLinus Torvalds /* API 3.1.4 close() - UDP Style Syntax 14171da177e4SLinus Torvalds * Applications use close() to perform graceful shutdown (as described in 14181da177e4SLinus Torvalds * Section 10.1 of [SCTP]) on ALL the associations currently represented 14191da177e4SLinus Torvalds * by a UDP-style socket. 14201da177e4SLinus Torvalds * 14211da177e4SLinus Torvalds * The syntax is 14221da177e4SLinus Torvalds * 14231da177e4SLinus Torvalds * ret = close(int sd); 14241da177e4SLinus Torvalds * 14251da177e4SLinus Torvalds * sd - the socket descriptor of the associations to be closed. 14261da177e4SLinus Torvalds * 14271da177e4SLinus Torvalds * To gracefully shutdown a specific association represented by the 14281da177e4SLinus Torvalds * UDP-style socket, an application should use the sendmsg() call, 14291da177e4SLinus Torvalds * passing no user data, but including the appropriate flag in the 14301da177e4SLinus Torvalds * ancillary data (see Section xxxx). 14311da177e4SLinus Torvalds * 14321da177e4SLinus Torvalds * If sd in the close() call is a branched-off socket representing only 14331da177e4SLinus Torvalds * one association, the shutdown is performed on that association only. 14341da177e4SLinus Torvalds * 14351da177e4SLinus Torvalds * 4.1.6 close() - TCP Style Syntax 14361da177e4SLinus Torvalds * 14371da177e4SLinus Torvalds * Applications use close() to gracefully close down an association. 14381da177e4SLinus Torvalds * 14391da177e4SLinus Torvalds * The syntax is: 14401da177e4SLinus Torvalds * 14411da177e4SLinus Torvalds * int close(int sd); 14421da177e4SLinus Torvalds * 14431da177e4SLinus Torvalds * sd - the socket descriptor of the association to be closed. 14441da177e4SLinus Torvalds * 14451da177e4SLinus Torvalds * After an application calls close() on a socket descriptor, no further 14461da177e4SLinus Torvalds * socket operations will succeed on that descriptor. 14471da177e4SLinus Torvalds * 14481da177e4SLinus Torvalds * API 7.1.4 SO_LINGER 14491da177e4SLinus Torvalds * 14501da177e4SLinus Torvalds * An application using the TCP-style socket can use this option to 14511da177e4SLinus Torvalds * perform the SCTP ABORT primitive. The linger option structure is: 14521da177e4SLinus Torvalds * 14531da177e4SLinus Torvalds * struct linger { 14541da177e4SLinus Torvalds * int l_onoff; // option on/off 14551da177e4SLinus Torvalds * int l_linger; // linger time 14561da177e4SLinus Torvalds * }; 14571da177e4SLinus Torvalds * 14581da177e4SLinus Torvalds * To enable the option, set l_onoff to 1. If the l_linger value is set 14591da177e4SLinus Torvalds * to 0, calling close() is the same as the ABORT primitive. If the 14601da177e4SLinus Torvalds * value is set to a negative value, the setsockopt() call will return 14611da177e4SLinus Torvalds * an error. If the value is set to a positive value linger_time, the 14621da177e4SLinus Torvalds * close() can be blocked for at most linger_time ms. If the graceful 14631da177e4SLinus Torvalds * shutdown phase does not finish during this period, close() will 14641da177e4SLinus Torvalds * return but the graceful shutdown phase continues in the system. 14651da177e4SLinus Torvalds */ 1466dda91928SDaniel Borkmann static void sctp_close(struct sock *sk, long timeout) 14671da177e4SLinus Torvalds { 146855e26eb9SEric W. Biederman struct net *net = sock_net(sk); 14691da177e4SLinus Torvalds struct sctp_endpoint *ep; 14701da177e4SLinus Torvalds struct sctp_association *asoc; 14711da177e4SLinus Torvalds struct list_head *pos, *temp; 1472cd4fcc70SThomas Graf unsigned int data_was_unread; 14731da177e4SLinus Torvalds 1474bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout); 14751da177e4SLinus Torvalds 14766dfe4b97SXin Long lock_sock_nested(sk, SINGLE_DEPTH_NESTING); 14771da177e4SLinus Torvalds sk->sk_shutdown = SHUTDOWN_MASK; 1478cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_CLOSING); 14791da177e4SLinus Torvalds 14801da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 14811da177e4SLinus Torvalds 1482cd4fcc70SThomas Graf /* Clean up any skbs sitting on the receive queue. */ 1483cd4fcc70SThomas Graf data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue); 1484cd4fcc70SThomas Graf data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); 1485cd4fcc70SThomas Graf 148661c9fed4SVladislav Yasevich /* Walk all associations on an endpoint. */ 14871da177e4SLinus Torvalds list_for_each_safe(pos, temp, &ep->asocs) { 14881da177e4SLinus Torvalds asoc = list_entry(pos, struct sctp_association, asocs); 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds if (sctp_style(sk, TCP)) { 14911da177e4SLinus Torvalds /* A closed association can still be in the list if 14921da177e4SLinus Torvalds * it belongs to a TCP-style listening socket that is 14931da177e4SLinus Torvalds * not yet accepted. If so, free it. If not, send an 14941da177e4SLinus Torvalds * ABORT or SHUTDOWN based on the linger options. 14951da177e4SLinus Torvalds */ 14961da177e4SLinus Torvalds if (sctp_state(asoc, CLOSED)) { 14971da177e4SLinus Torvalds sctp_association_free(asoc); 1498b89498a1SVladislav Yasevich continue; 1499b89498a1SVladislav Yasevich } 1500b89498a1SVladislav Yasevich } 15011da177e4SLinus Torvalds 1502cd4fcc70SThomas Graf if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) || 1503cd4fcc70SThomas Graf !skb_queue_empty(&asoc->ulpq.reasm) || 150413228238SXin Long !skb_queue_empty(&asoc->ulpq.reasm_uo) || 1505cd4fcc70SThomas Graf (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { 1506b9ac8672SSridhar Samudrala struct sctp_chunk *chunk; 1507b9ac8672SSridhar Samudrala 1508b9ac8672SSridhar Samudrala chunk = sctp_make_abort_user(asoc, NULL, 0); 150955e26eb9SEric W. Biederman sctp_primitive_ABORT(net, asoc, chunk); 1510b9ac8672SSridhar Samudrala } else 151155e26eb9SEric W. Biederman sctp_primitive_SHUTDOWN(net, asoc, NULL); 15121da177e4SLinus Torvalds } 15131da177e4SLinus Torvalds 15141da177e4SLinus Torvalds /* On a TCP-style socket, block for at most linger_time if set. */ 15151da177e4SLinus Torvalds if (sctp_style(sk, TCP) && timeout) 15161da177e4SLinus Torvalds sctp_wait_for_close(sk, timeout); 15171da177e4SLinus Torvalds 15181da177e4SLinus Torvalds /* This will run the backlog queue. */ 1519048ed4b6Swangweidong release_sock(sk); 15201da177e4SLinus Torvalds 15211da177e4SLinus Torvalds /* Supposedly, no process has access to the socket, but 15221da177e4SLinus Torvalds * the net layers still may. 15232d45a02dSMarcelo Ricardo Leitner * Also, sctp_destroy_sock() needs to be called with addr_wq_lock 15242d45a02dSMarcelo Ricardo Leitner * held and that should be grabbed before socket lock. 15251da177e4SLinus Torvalds */ 15262d45a02dSMarcelo Ricardo Leitner spin_lock_bh(&net->sctp.addr_wq_lock); 15276dfe4b97SXin Long bh_lock_sock_nested(sk); 15281da177e4SLinus Torvalds 15291da177e4SLinus Torvalds /* Hold the sock, since sk_common_release() will put sock_put() 15301da177e4SLinus Torvalds * and we have just a little more cleanup. 15311da177e4SLinus Torvalds */ 15321da177e4SLinus Torvalds sock_hold(sk); 15331da177e4SLinus Torvalds sk_common_release(sk); 15341da177e4SLinus Torvalds 15355bc1d1b4Swangweidong bh_unlock_sock(sk); 15362d45a02dSMarcelo Ricardo Leitner spin_unlock_bh(&net->sctp.addr_wq_lock); 15371da177e4SLinus Torvalds 15381da177e4SLinus Torvalds sock_put(sk); 15391da177e4SLinus Torvalds 15401da177e4SLinus Torvalds SCTP_DBG_OBJCNT_DEC(sock); 15411da177e4SLinus Torvalds } 15421da177e4SLinus Torvalds 15431da177e4SLinus Torvalds /* Handle EPIPE error. */ 15441da177e4SLinus Torvalds static int sctp_error(struct sock *sk, int flags, int err) 15451da177e4SLinus Torvalds { 15461da177e4SLinus Torvalds if (err == -EPIPE) 15471da177e4SLinus Torvalds err = sock_error(sk) ? : -EPIPE; 15481da177e4SLinus Torvalds if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) 15491da177e4SLinus Torvalds send_sig(SIGPIPE, current, 0); 15501da177e4SLinus Torvalds return err; 15511da177e4SLinus Torvalds } 15521da177e4SLinus Torvalds 15531da177e4SLinus Torvalds /* API 3.1.3 sendmsg() - UDP Style Syntax 15541da177e4SLinus Torvalds * 15551da177e4SLinus Torvalds * An application uses sendmsg() and recvmsg() calls to transmit data to 15561da177e4SLinus Torvalds * and receive data from its peer. 15571da177e4SLinus Torvalds * 15581da177e4SLinus Torvalds * ssize_t sendmsg(int socket, const struct msghdr *message, 15591da177e4SLinus Torvalds * int flags); 15601da177e4SLinus Torvalds * 15611da177e4SLinus Torvalds * socket - the socket descriptor of the endpoint. 15621da177e4SLinus Torvalds * message - pointer to the msghdr structure which contains a single 15631da177e4SLinus Torvalds * user message and possibly some ancillary data. 15641da177e4SLinus Torvalds * 15651da177e4SLinus Torvalds * See Section 5 for complete description of the data 15661da177e4SLinus Torvalds * structures. 15671da177e4SLinus Torvalds * 15681da177e4SLinus Torvalds * flags - flags sent or received with the user message, see Section 15691da177e4SLinus Torvalds * 5 for complete description of the flags. 15701da177e4SLinus Torvalds * 15711da177e4SLinus Torvalds * Note: This function could use a rewrite especially when explicit 15721da177e4SLinus Torvalds * connect support comes in. 15731da177e4SLinus Torvalds */ 15741da177e4SLinus Torvalds /* BUG: We do not implement the equivalent of sk_stream_wait_memory(). */ 15751da177e4SLinus Torvalds 1576a05437acSXin Long static int sctp_msghdr_parse(const struct msghdr *msg, 1577a05437acSXin Long struct sctp_cmsgs *cmsgs); 15781da177e4SLinus Torvalds 1579204f817fSXin Long static int sctp_sendmsg_parse(struct sock *sk, struct sctp_cmsgs *cmsgs, 1580204f817fSXin Long struct sctp_sndrcvinfo *srinfo, 1581204f817fSXin Long const struct msghdr *msg, size_t msg_len) 1582204f817fSXin Long { 1583204f817fSXin Long __u16 sflags; 1584204f817fSXin Long int err; 1585204f817fSXin Long 1586204f817fSXin Long if (sctp_sstate(sk, LISTENING) && sctp_style(sk, TCP)) 1587204f817fSXin Long return -EPIPE; 1588204f817fSXin Long 1589204f817fSXin Long if (msg_len > sk->sk_sndbuf) 1590204f817fSXin Long return -EMSGSIZE; 1591204f817fSXin Long 1592204f817fSXin Long memset(cmsgs, 0, sizeof(*cmsgs)); 1593204f817fSXin Long err = sctp_msghdr_parse(msg, cmsgs); 1594204f817fSXin Long if (err) { 1595204f817fSXin Long pr_debug("%s: msghdr parse err:%x\n", __func__, err); 1596204f817fSXin Long return err; 1597204f817fSXin Long } 1598204f817fSXin Long 1599204f817fSXin Long memset(srinfo, 0, sizeof(*srinfo)); 1600204f817fSXin Long if (cmsgs->srinfo) { 1601204f817fSXin Long srinfo->sinfo_stream = cmsgs->srinfo->sinfo_stream; 1602204f817fSXin Long srinfo->sinfo_flags = cmsgs->srinfo->sinfo_flags; 1603204f817fSXin Long srinfo->sinfo_ppid = cmsgs->srinfo->sinfo_ppid; 1604204f817fSXin Long srinfo->sinfo_context = cmsgs->srinfo->sinfo_context; 1605204f817fSXin Long srinfo->sinfo_assoc_id = cmsgs->srinfo->sinfo_assoc_id; 1606204f817fSXin Long srinfo->sinfo_timetolive = cmsgs->srinfo->sinfo_timetolive; 1607204f817fSXin Long } 1608204f817fSXin Long 1609204f817fSXin Long if (cmsgs->sinfo) { 1610204f817fSXin Long srinfo->sinfo_stream = cmsgs->sinfo->snd_sid; 1611204f817fSXin Long srinfo->sinfo_flags = cmsgs->sinfo->snd_flags; 1612204f817fSXin Long srinfo->sinfo_ppid = cmsgs->sinfo->snd_ppid; 1613204f817fSXin Long srinfo->sinfo_context = cmsgs->sinfo->snd_context; 1614204f817fSXin Long srinfo->sinfo_assoc_id = cmsgs->sinfo->snd_assoc_id; 1615204f817fSXin Long } 1616204f817fSXin Long 1617ed63afb8SXin Long if (cmsgs->prinfo) { 1618ed63afb8SXin Long srinfo->sinfo_timetolive = cmsgs->prinfo->pr_value; 1619ed63afb8SXin Long SCTP_PR_SET_POLICY(srinfo->sinfo_flags, 1620ed63afb8SXin Long cmsgs->prinfo->pr_policy); 1621ed63afb8SXin Long } 1622ed63afb8SXin Long 1623204f817fSXin Long sflags = srinfo->sinfo_flags; 1624204f817fSXin Long if (!sflags && msg_len) 1625204f817fSXin Long return 0; 1626204f817fSXin Long 1627204f817fSXin Long if (sctp_style(sk, TCP) && (sflags & (SCTP_EOF | SCTP_ABORT))) 1628204f817fSXin Long return -EINVAL; 1629204f817fSXin Long 1630204f817fSXin Long if (((sflags & SCTP_EOF) && msg_len > 0) || 1631204f817fSXin Long (!(sflags & (SCTP_EOF | SCTP_ABORT)) && msg_len == 0)) 1632204f817fSXin Long return -EINVAL; 1633204f817fSXin Long 1634204f817fSXin Long if ((sflags & SCTP_ADDR_OVER) && !msg->msg_name) 1635204f817fSXin Long return -EINVAL; 1636204f817fSXin Long 1637204f817fSXin Long return 0; 1638204f817fSXin Long } 1639204f817fSXin Long 16402bfd80f9SXin Long static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags, 16412bfd80f9SXin Long struct sctp_cmsgs *cmsgs, 16422bfd80f9SXin Long union sctp_addr *daddr, 16432bfd80f9SXin Long struct sctp_transport **tp) 16442bfd80f9SXin Long { 16452bfd80f9SXin Long struct sctp_endpoint *ep = sctp_sk(sk)->ep; 16462bfd80f9SXin Long struct sctp_association *asoc; 16472c0dbaa0SXin Long struct cmsghdr *cmsg; 16484be4139fSXin Long __be32 flowinfo = 0; 16499eda2d2dSLinus Torvalds struct sctp_af *af; 1650d98985ddSWei Yongjun int err; 16512bfd80f9SXin Long 16522bfd80f9SXin Long *tp = NULL; 16532bfd80f9SXin Long 16542bfd80f9SXin Long if (sflags & (SCTP_EOF | SCTP_ABORT)) 16552bfd80f9SXin Long return -EINVAL; 16562bfd80f9SXin Long 16572bfd80f9SXin Long if (sctp_style(sk, TCP) && (sctp_sstate(sk, ESTABLISHED) || 16582bfd80f9SXin Long sctp_sstate(sk, CLOSING))) 16592bfd80f9SXin Long return -EADDRNOTAVAIL; 16602bfd80f9SXin Long 16612277c7cdSRichard Haines /* Label connection socket for first association 1-to-many 16622277c7cdSRichard Haines * style for client sequence socket()->sendmsg(). This 16632277c7cdSRichard Haines * needs to be done before sctp_assoc_add_peer() as that will 16642277c7cdSRichard Haines * set up the initial packet that needs to account for any 16652277c7cdSRichard Haines * security ip options (CIPSO/CALIPSO) added to the packet. 16662277c7cdSRichard Haines */ 16679eda2d2dSLinus Torvalds af = sctp_get_af_specific(daddr->sa.sa_family); 16689eda2d2dSLinus Torvalds if (!af) 16699eda2d2dSLinus Torvalds return -EINVAL; 16702277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_SENDMSG_CONNECT, 16719eda2d2dSLinus Torvalds (struct sockaddr *)daddr, 16722277c7cdSRichard Haines af->sockaddr_len); 16732277c7cdSRichard Haines if (err < 0) 16749eda2d2dSLinus Torvalds return err; 16752277c7cdSRichard Haines 1676f26f9951SXin Long err = sctp_connect_new_asoc(ep, daddr, cmsgs->init, tp); 16772bfd80f9SXin Long if (err) 1678f26f9951SXin Long return err; 1679f26f9951SXin Long asoc = (*tp)->asoc; 16802bfd80f9SXin Long 16812c0dbaa0SXin Long if (!cmsgs->addrs_msg) 16822c0dbaa0SXin Long return 0; 16832c0dbaa0SXin Long 16844be4139fSXin Long if (daddr->sa.sa_family == AF_INET6) 16854be4139fSXin Long flowinfo = daddr->v6.sin6_flowinfo; 16864be4139fSXin Long 16872c0dbaa0SXin Long /* sendv addr list parse */ 16882c0dbaa0SXin Long for_each_cmsghdr(cmsg, cmsgs->addrs_msg) { 16892c0dbaa0SXin Long union sctp_addr _daddr; 16902c0dbaa0SXin Long int dlen; 16912c0dbaa0SXin Long 16922c0dbaa0SXin Long if (cmsg->cmsg_level != IPPROTO_SCTP || 16932c0dbaa0SXin Long (cmsg->cmsg_type != SCTP_DSTADDRV4 && 16942c0dbaa0SXin Long cmsg->cmsg_type != SCTP_DSTADDRV6)) 16952c0dbaa0SXin Long continue; 16962c0dbaa0SXin Long 16972c0dbaa0SXin Long daddr = &_daddr; 16982c0dbaa0SXin Long memset(daddr, 0, sizeof(*daddr)); 16992c0dbaa0SXin Long dlen = cmsg->cmsg_len - sizeof(struct cmsghdr); 17002c0dbaa0SXin Long if (cmsg->cmsg_type == SCTP_DSTADDRV4) { 1701d98985ddSWei Yongjun if (dlen < sizeof(struct in_addr)) { 1702d98985ddSWei Yongjun err = -EINVAL; 17032c0dbaa0SXin Long goto free; 1704d98985ddSWei Yongjun } 17052c0dbaa0SXin Long 17062c0dbaa0SXin Long dlen = sizeof(struct in_addr); 17072c0dbaa0SXin Long daddr->v4.sin_family = AF_INET; 17082c0dbaa0SXin Long daddr->v4.sin_port = htons(asoc->peer.port); 17092c0dbaa0SXin Long memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen); 17102c0dbaa0SXin Long } else { 1711d98985ddSWei Yongjun if (dlen < sizeof(struct in6_addr)) { 1712d98985ddSWei Yongjun err = -EINVAL; 17132c0dbaa0SXin Long goto free; 1714d98985ddSWei Yongjun } 17152c0dbaa0SXin Long 17162c0dbaa0SXin Long dlen = sizeof(struct in6_addr); 17174be4139fSXin Long daddr->v6.sin6_flowinfo = flowinfo; 17182c0dbaa0SXin Long daddr->v6.sin6_family = AF_INET6; 17192c0dbaa0SXin Long daddr->v6.sin6_port = htons(asoc->peer.port); 17202c0dbaa0SXin Long memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen); 17212c0dbaa0SXin Long } 1722a64e59c7SXin Long 1723a64e59c7SXin Long err = sctp_connect_add_peer(asoc, daddr, sizeof(*daddr)); 17242c0dbaa0SXin Long if (err) 17252c0dbaa0SXin Long goto free; 17262c0dbaa0SXin Long } 17272c0dbaa0SXin Long 17282bfd80f9SXin Long return 0; 17292bfd80f9SXin Long 17302bfd80f9SXin Long free: 17312bfd80f9SXin Long sctp_association_free(asoc); 17322bfd80f9SXin Long return err; 17332bfd80f9SXin Long } 17342bfd80f9SXin Long 1735c2666de1SXin Long static int sctp_sendmsg_check_sflags(struct sctp_association *asoc, 1736c2666de1SXin Long __u16 sflags, struct msghdr *msg, 1737c2666de1SXin Long size_t msg_len) 1738c2666de1SXin Long { 1739c2666de1SXin Long struct sock *sk = asoc->base.sk; 1740c2666de1SXin Long struct net *net = sock_net(sk); 1741c2666de1SXin Long 1742c2666de1SXin Long if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) 1743c2666de1SXin Long return -EPIPE; 1744c2666de1SXin Long 174549102805SXin Long if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP) && 174649102805SXin Long !sctp_state(asoc, ESTABLISHED)) 174749102805SXin Long return 0; 174849102805SXin Long 1749c2666de1SXin Long if (sflags & SCTP_EOF) { 1750c2666de1SXin Long pr_debug("%s: shutting down association:%p\n", __func__, asoc); 1751c2666de1SXin Long sctp_primitive_SHUTDOWN(net, asoc, NULL); 1752c2666de1SXin Long 1753c2666de1SXin Long return 0; 1754c2666de1SXin Long } 1755c2666de1SXin Long 1756c2666de1SXin Long if (sflags & SCTP_ABORT) { 1757c2666de1SXin Long struct sctp_chunk *chunk; 1758c2666de1SXin Long 1759c2666de1SXin Long chunk = sctp_make_abort_user(asoc, msg, msg_len); 1760c2666de1SXin Long if (!chunk) 1761c2666de1SXin Long return -ENOMEM; 1762c2666de1SXin Long 1763c2666de1SXin Long pr_debug("%s: aborting association:%p\n", __func__, asoc); 1764c2666de1SXin Long sctp_primitive_ABORT(net, asoc, chunk); 1765901efe12SXin Long iov_iter_revert(&msg->msg_iter, msg_len); 1766c2666de1SXin Long 1767c2666de1SXin Long return 0; 1768c2666de1SXin Long } 1769c2666de1SXin Long 1770c2666de1SXin Long return 1; 1771c2666de1SXin Long } 1772c2666de1SXin Long 1773f84af331SXin Long static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, 1774f84af331SXin Long struct msghdr *msg, size_t msg_len, 1775f84af331SXin Long struct sctp_transport *transport, 1776f84af331SXin Long struct sctp_sndrcvinfo *sinfo) 1777f84af331SXin Long { 1778f84af331SXin Long struct sock *sk = asoc->base.sk; 177963d01330SMarcelo Ricardo Leitner struct sctp_sock *sp = sctp_sk(sk); 1780f84af331SXin Long struct net *net = sock_net(sk); 1781f84af331SXin Long struct sctp_datamsg *datamsg; 1782f84af331SXin Long bool wait_connect = false; 1783f84af331SXin Long struct sctp_chunk *chunk; 1784f84af331SXin Long long timeo; 1785f84af331SXin Long int err; 1786f84af331SXin Long 1787f84af331SXin Long if (sinfo->sinfo_stream >= asoc->stream.outcnt) { 1788f84af331SXin Long err = -EINVAL; 1789f84af331SXin Long goto err; 1790f84af331SXin Long } 1791f84af331SXin Long 179205364ca0SKonstantin Khorenko if (unlikely(!SCTP_SO(&asoc->stream, sinfo->sinfo_stream)->ext)) { 1793f84af331SXin Long err = sctp_stream_init_ext(&asoc->stream, sinfo->sinfo_stream); 1794f84af331SXin Long if (err) 1795f84af331SXin Long goto err; 1796f84af331SXin Long } 1797f84af331SXin Long 179863d01330SMarcelo Ricardo Leitner if (sp->disable_fragments && msg_len > asoc->frag_point) { 1799f84af331SXin Long err = -EMSGSIZE; 1800f84af331SXin Long goto err; 1801f84af331SXin Long } 1802f84af331SXin Long 18032521680eSMarcelo Ricardo Leitner if (asoc->pmtu_pending) { 180463d01330SMarcelo Ricardo Leitner if (sp->param_flags & SPP_PMTUD_ENABLE) 18052521680eSMarcelo Ricardo Leitner sctp_assoc_sync_pmtu(asoc); 18062521680eSMarcelo Ricardo Leitner asoc->pmtu_pending = 0; 18072521680eSMarcelo Ricardo Leitner } 18080aee4c25SNeil Horman 1809cd305c74SXin Long if (sctp_wspace(asoc) < (int)msg_len) 18100aee4c25SNeil Horman sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc)); 18110aee4c25SNeil Horman 18121033990aSXin Long if (sk_under_memory_pressure(sk)) 18131033990aSXin Long sk_mem_reclaim(sk); 18141033990aSXin Long 18151033990aSXin Long if (sctp_wspace(asoc) <= 0 || !sk_wmem_schedule(sk, msg_len)) { 18160aee4c25SNeil Horman timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 18170aee4c25SNeil Horman err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); 18180aee4c25SNeil Horman if (err) 18190aee4c25SNeil Horman goto err; 18200aee4c25SNeil Horman } 18210aee4c25SNeil Horman 1822f84af331SXin Long if (sctp_state(asoc, CLOSED)) { 1823f84af331SXin Long err = sctp_primitive_ASSOCIATE(net, asoc, NULL); 1824f84af331SXin Long if (err) 1825f84af331SXin Long goto err; 1826f84af331SXin Long 1827e55f4b8bSXin Long if (asoc->ep->intl_enable) { 1828f84af331SXin Long timeo = sock_sndtimeo(sk, 0); 1829f84af331SXin Long err = sctp_wait_for_connect(asoc, &timeo); 1830c863850cSXin Long if (err) { 1831c863850cSXin Long err = -ESRCH; 1832f84af331SXin Long goto err; 1833c863850cSXin Long } 1834f84af331SXin Long } else { 1835f84af331SXin Long wait_connect = true; 1836f84af331SXin Long } 1837f84af331SXin Long 1838f84af331SXin Long pr_debug("%s: we associated primitively\n", __func__); 1839f84af331SXin Long } 1840f84af331SXin Long 1841f84af331SXin Long datamsg = sctp_datamsg_from_user(asoc, sinfo, &msg->msg_iter); 1842f84af331SXin Long if (IS_ERR(datamsg)) { 1843f84af331SXin Long err = PTR_ERR(datamsg); 1844f84af331SXin Long goto err; 1845f84af331SXin Long } 1846f84af331SXin Long 1847f84af331SXin Long asoc->force_delay = !!(msg->msg_flags & MSG_MORE); 1848f84af331SXin Long 1849f84af331SXin Long list_for_each_entry(chunk, &datamsg->chunks, frag_list) { 1850f84af331SXin Long sctp_chunk_hold(chunk); 1851f84af331SXin Long sctp_set_owner_w(chunk); 1852f84af331SXin Long chunk->transport = transport; 1853f84af331SXin Long } 1854f84af331SXin Long 1855f84af331SXin Long err = sctp_primitive_SEND(net, asoc, datamsg); 1856f84af331SXin Long if (err) { 1857f84af331SXin Long sctp_datamsg_free(datamsg); 1858f84af331SXin Long goto err; 1859f84af331SXin Long } 1860f84af331SXin Long 1861f84af331SXin Long pr_debug("%s: we sent primitively\n", __func__); 1862f84af331SXin Long 1863f84af331SXin Long sctp_datamsg_put(datamsg); 1864f84af331SXin Long 1865f84af331SXin Long if (unlikely(wait_connect)) { 1866f84af331SXin Long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 1867f84af331SXin Long sctp_wait_for_connect(asoc, &timeo); 1868f84af331SXin Long } 1869f84af331SXin Long 1870f84af331SXin Long err = msg_len; 1871f84af331SXin Long 1872f84af331SXin Long err: 1873f84af331SXin Long return err; 1874f84af331SXin Long } 1875f84af331SXin Long 1876becef9b1SXin Long static union sctp_addr *sctp_sendmsg_get_daddr(struct sock *sk, 1877becef9b1SXin Long const struct msghdr *msg, 1878becef9b1SXin Long struct sctp_cmsgs *cmsgs) 1879becef9b1SXin Long { 1880becef9b1SXin Long union sctp_addr *daddr = NULL; 1881becef9b1SXin Long int err; 1882becef9b1SXin Long 1883becef9b1SXin Long if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) { 1884becef9b1SXin Long int len = msg->msg_namelen; 1885becef9b1SXin Long 1886becef9b1SXin Long if (len > sizeof(*daddr)) 1887becef9b1SXin Long len = sizeof(*daddr); 1888becef9b1SXin Long 1889becef9b1SXin Long daddr = (union sctp_addr *)msg->msg_name; 1890becef9b1SXin Long 1891becef9b1SXin Long err = sctp_verify_addr(sk, daddr, len); 1892becef9b1SXin Long if (err) 1893becef9b1SXin Long return ERR_PTR(err); 1894becef9b1SXin Long } 1895becef9b1SXin Long 1896becef9b1SXin Long return daddr; 1897becef9b1SXin Long } 1898becef9b1SXin Long 1899d42cb06eSXin Long static void sctp_sendmsg_update_sinfo(struct sctp_association *asoc, 1900d42cb06eSXin Long struct sctp_sndrcvinfo *sinfo, 1901d42cb06eSXin Long struct sctp_cmsgs *cmsgs) 1902d42cb06eSXin Long { 1903d42cb06eSXin Long if (!cmsgs->srinfo && !cmsgs->sinfo) { 1904d42cb06eSXin Long sinfo->sinfo_stream = asoc->default_stream; 1905d42cb06eSXin Long sinfo->sinfo_ppid = asoc->default_ppid; 1906d42cb06eSXin Long sinfo->sinfo_context = asoc->default_context; 1907d42cb06eSXin Long sinfo->sinfo_assoc_id = sctp_assoc2id(asoc); 1908ed63afb8SXin Long 1909ed63afb8SXin Long if (!cmsgs->prinfo) 1910ed63afb8SXin Long sinfo->sinfo_flags = asoc->default_flags; 1911d42cb06eSXin Long } 1912d42cb06eSXin Long 1913ed63afb8SXin Long if (!cmsgs->srinfo && !cmsgs->prinfo) 1914d42cb06eSXin Long sinfo->sinfo_timetolive = asoc->default_timetolive; 19153ff547c0SXin Long 19163ff547c0SXin Long if (cmsgs->authinfo) { 19173ff547c0SXin Long /* Reuse sinfo_tsn to indicate that authinfo was set and 19183ff547c0SXin Long * sinfo_ssn to save the keyid on tx path. 19193ff547c0SXin Long */ 19203ff547c0SXin Long sinfo->sinfo_tsn = 1; 19213ff547c0SXin Long sinfo->sinfo_ssn = cmsgs->authinfo->auth_keynumber; 19223ff547c0SXin Long } 1923d42cb06eSXin Long } 1924d42cb06eSXin Long 19251b784140SYing Xue static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) 19261da177e4SLinus Torvalds { 1927204f817fSXin Long struct sctp_endpoint *ep = sctp_sk(sk)->ep; 19288e87c6ebSXin Long struct sctp_transport *transport = NULL; 1929204f817fSXin Long struct sctp_sndrcvinfo _sinfo, *sinfo; 1930ba59fb02SGreg Kroah-Hartman struct sctp_association *asoc, *tmp; 1931007b7e18SXin Long struct sctp_cmsgs cmsgs; 1932becef9b1SXin Long union sctp_addr *daddr; 1933007b7e18SXin Long bool new = false; 1934007b7e18SXin Long __u16 sflags; 193563b94938SGeir Ola Vaagland int err; 19361da177e4SLinus Torvalds 1937204f817fSXin Long /* Parse and get snd_info */ 1938204f817fSXin Long err = sctp_sendmsg_parse(sk, &cmsgs, &_sinfo, msg, msg_len); 1939204f817fSXin Long if (err) 1940007b7e18SXin Long goto out; 19411da177e4SLinus Torvalds 1942204f817fSXin Long sinfo = &_sinfo; 1943007b7e18SXin Long sflags = sinfo->sinfo_flags; 19441da177e4SLinus Torvalds 1945becef9b1SXin Long /* Get daddr from msg */ 1946becef9b1SXin Long daddr = sctp_sendmsg_get_daddr(sk, msg, &cmsgs); 1947becef9b1SXin Long if (IS_ERR(daddr)) { 1948becef9b1SXin Long err = PTR_ERR(daddr); 1949007b7e18SXin Long goto out; 19501da177e4SLinus Torvalds } 19511da177e4SLinus Torvalds 1952048ed4b6Swangweidong lock_sock(sk); 19531da177e4SLinus Torvalds 195449102805SXin Long /* SCTP_SENDALL process */ 195549102805SXin Long if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) { 1956ba59fb02SGreg Kroah-Hartman list_for_each_entry_safe(asoc, tmp, &ep->asocs, asocs) { 195749102805SXin Long err = sctp_sendmsg_check_sflags(asoc, sflags, msg, 195849102805SXin Long msg_len); 195949102805SXin Long if (err == 0) 196049102805SXin Long continue; 196149102805SXin Long if (err < 0) 196249102805SXin Long goto out_unlock; 196349102805SXin Long 196449102805SXin Long sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs); 196549102805SXin Long 196649102805SXin Long err = sctp_sendmsg_to_asoc(asoc, msg, msg_len, 196749102805SXin Long NULL, sinfo); 196849102805SXin Long if (err < 0) 196949102805SXin Long goto out_unlock; 197049102805SXin Long 197149102805SXin Long iov_iter_revert(&msg->msg_iter, err); 197249102805SXin Long } 197349102805SXin Long 197449102805SXin Long goto out_unlock; 197549102805SXin Long } 197649102805SXin Long 19770a3920d2SXin Long /* Get and check or create asoc */ 1978becef9b1SXin Long if (daddr) { 1979becef9b1SXin Long asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport); 19801da177e4SLinus Torvalds if (asoc) { 19810a3920d2SXin Long err = sctp_sendmsg_check_sflags(asoc, sflags, msg, 19820a3920d2SXin Long msg_len); 1983c2666de1SXin Long if (err <= 0) 19841da177e4SLinus Torvalds goto out_unlock; 19850a3920d2SXin Long } else { 1986007b7e18SXin Long err = sctp_sendmsg_new_asoc(sk, sflags, &cmsgs, daddr, 19872bfd80f9SXin Long &transport); 1988625637bfSXin Long if (err) 19892bfd80f9SXin Long goto out_unlock; 19901da177e4SLinus Torvalds 19912bfd80f9SXin Long asoc = transport->asoc; 1992007b7e18SXin Long new = true; 19931da177e4SLinus Torvalds } 19941da177e4SLinus Torvalds 1995007b7e18SXin Long if (!sctp_style(sk, TCP) && !(sflags & SCTP_ADDR_OVER)) 19968e87c6ebSXin Long transport = NULL; 19970a3920d2SXin Long } else { 19980a3920d2SXin Long asoc = sctp_id2assoc(sk, sinfo->sinfo_assoc_id); 19990a3920d2SXin Long if (!asoc) { 20000a3920d2SXin Long err = -EPIPE; 20010a3920d2SXin Long goto out_unlock; 20020a3920d2SXin Long } 20030a3920d2SXin Long 20040a3920d2SXin Long err = sctp_sendmsg_check_sflags(asoc, sflags, msg, msg_len); 20050a3920d2SXin Long if (err <= 0) 20060a3920d2SXin Long goto out_unlock; 20070a3920d2SXin Long } 20088e87c6ebSXin Long 2009d42cb06eSXin Long /* Update snd_info with the asoc */ 2010d42cb06eSXin Long sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs); 20111da177e4SLinus Torvalds 2012f84af331SXin Long /* Send msg to the asoc */ 20138e87c6ebSXin Long err = sctp_sendmsg_to_asoc(asoc, msg, msg_len, transport, sinfo); 2014007b7e18SXin Long if (err < 0 && err != -ESRCH && new) 20151da177e4SLinus Torvalds sctp_association_free(asoc); 20168e87c6ebSXin Long 20171da177e4SLinus Torvalds out_unlock: 2018048ed4b6Swangweidong release_sock(sk); 2019007b7e18SXin Long out: 2020f84af331SXin Long return sctp_error(sk, msg->msg_flags, err); 20211da177e4SLinus Torvalds } 20221da177e4SLinus Torvalds 20231da177e4SLinus Torvalds /* This is an extended version of skb_pull() that removes the data from the 20241da177e4SLinus Torvalds * start of a skb even when data is spread across the list of skb's in the 20251da177e4SLinus Torvalds * frag_list. len specifies the total amount of data that needs to be removed. 20261da177e4SLinus Torvalds * when 'len' bytes could be removed from the skb, it returns 0. 20271da177e4SLinus Torvalds * If 'len' exceeds the total skb length, it returns the no. of bytes that 20281da177e4SLinus Torvalds * could not be removed. 20291da177e4SLinus Torvalds */ 20301da177e4SLinus Torvalds static int sctp_skb_pull(struct sk_buff *skb, int len) 20311da177e4SLinus Torvalds { 20321da177e4SLinus Torvalds struct sk_buff *list; 20331da177e4SLinus Torvalds int skb_len = skb_headlen(skb); 20341da177e4SLinus Torvalds int rlen; 20351da177e4SLinus Torvalds 20361da177e4SLinus Torvalds if (len <= skb_len) { 20371da177e4SLinus Torvalds __skb_pull(skb, len); 20381da177e4SLinus Torvalds return 0; 20391da177e4SLinus Torvalds } 20401da177e4SLinus Torvalds len -= skb_len; 20411da177e4SLinus Torvalds __skb_pull(skb, skb_len); 20421da177e4SLinus Torvalds 20431b003be3SDavid S. Miller skb_walk_frags(skb, list) { 20441da177e4SLinus Torvalds rlen = sctp_skb_pull(list, len); 20451da177e4SLinus Torvalds skb->len -= (len-rlen); 20461da177e4SLinus Torvalds skb->data_len -= (len-rlen); 20471da177e4SLinus Torvalds 20481da177e4SLinus Torvalds if (!rlen) 20491da177e4SLinus Torvalds return 0; 20501da177e4SLinus Torvalds 20511da177e4SLinus Torvalds len = rlen; 20521da177e4SLinus Torvalds } 20531da177e4SLinus Torvalds 20541da177e4SLinus Torvalds return len; 20551da177e4SLinus Torvalds } 20561da177e4SLinus Torvalds 20571da177e4SLinus Torvalds /* API 3.1.3 recvmsg() - UDP Style Syntax 20581da177e4SLinus Torvalds * 20591da177e4SLinus Torvalds * ssize_t recvmsg(int socket, struct msghdr *message, 20601da177e4SLinus Torvalds * int flags); 20611da177e4SLinus Torvalds * 20621da177e4SLinus Torvalds * socket - the socket descriptor of the endpoint. 20631da177e4SLinus Torvalds * message - pointer to the msghdr structure which contains a single 20641da177e4SLinus Torvalds * user message and possibly some ancillary data. 20651da177e4SLinus Torvalds * 20661da177e4SLinus Torvalds * See Section 5 for complete description of the data 20671da177e4SLinus Torvalds * structures. 20681da177e4SLinus Torvalds * 20691da177e4SLinus Torvalds * flags - flags sent or received with the user message, see Section 20701da177e4SLinus Torvalds * 5 for complete description of the flags. 20711da177e4SLinus Torvalds */ 20721b784140SYing Xue static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 20731b784140SYing Xue int noblock, int flags, int *addr_len) 20741da177e4SLinus Torvalds { 20751da177e4SLinus Torvalds struct sctp_ulpevent *event = NULL; 20761da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 20771f45f78fSMarcelo Ricardo Leitner struct sk_buff *skb, *head_skb; 20781da177e4SLinus Torvalds int copied; 20791da177e4SLinus Torvalds int err = 0; 20801da177e4SLinus Torvalds int skb_len; 20811da177e4SLinus Torvalds 2082bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, msghdr:%p, len:%zd, noblock:%d, flags:0x%x, " 2083bb33381dSDaniel Borkmann "addr_len:%p)\n", __func__, sk, msg, len, noblock, flags, 2084bb33381dSDaniel Borkmann addr_len); 20851da177e4SLinus Torvalds 2086048ed4b6Swangweidong lock_sock(sk); 20871da177e4SLinus Torvalds 2088e5b13f34SMarcelo Ricardo Leitner if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED) && 2089e0878694SXin Long !sctp_sstate(sk, CLOSING) && !sctp_sstate(sk, CLOSED)) { 20901da177e4SLinus Torvalds err = -ENOTCONN; 20911da177e4SLinus Torvalds goto out; 20921da177e4SLinus Torvalds } 20931da177e4SLinus Torvalds 20941da177e4SLinus Torvalds skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); 20951da177e4SLinus Torvalds if (!skb) 20961da177e4SLinus Torvalds goto out; 20971da177e4SLinus Torvalds 20981da177e4SLinus Torvalds /* Get the total length of the skb including any skb's in the 20991da177e4SLinus Torvalds * frag_list. 21001da177e4SLinus Torvalds */ 21011da177e4SLinus Torvalds skb_len = skb->len; 21021da177e4SLinus Torvalds 21031da177e4SLinus Torvalds copied = skb_len; 21041da177e4SLinus Torvalds if (copied > len) 21051da177e4SLinus Torvalds copied = len; 21061da177e4SLinus Torvalds 210751f3d02bSDavid S. Miller err = skb_copy_datagram_msg(skb, 0, msg, copied); 21081da177e4SLinus Torvalds 21091da177e4SLinus Torvalds event = sctp_skb2event(skb); 21101da177e4SLinus Torvalds 21111da177e4SLinus Torvalds if (err) 21121da177e4SLinus Torvalds goto out_free; 21131da177e4SLinus Torvalds 21141f45f78fSMarcelo Ricardo Leitner if (event->chunk && event->chunk->head_skb) 21151f45f78fSMarcelo Ricardo Leitner head_skb = event->chunk->head_skb; 21161f45f78fSMarcelo Ricardo Leitner else 21171f45f78fSMarcelo Ricardo Leitner head_skb = skb; 21181f45f78fSMarcelo Ricardo Leitner sock_recv_ts_and_drops(msg, sk, head_skb); 21191da177e4SLinus Torvalds if (sctp_ulpevent_is_notification(event)) { 21201da177e4SLinus Torvalds msg->msg_flags |= MSG_NOTIFICATION; 21211da177e4SLinus Torvalds sp->pf->event_msgname(event, msg->msg_name, addr_len); 21221da177e4SLinus Torvalds } else { 21231f45f78fSMarcelo Ricardo Leitner sp->pf->skb_msgname(head_skb, msg->msg_name, addr_len); 21241da177e4SLinus Torvalds } 21251da177e4SLinus Torvalds 21262347c80fSGeir Ola Vaagland /* Check if we allow SCTP_NXTINFO. */ 21272347c80fSGeir Ola Vaagland if (sp->recvnxtinfo) 21282347c80fSGeir Ola Vaagland sctp_ulpevent_read_nxtinfo(event, msg, sk); 21290d3a421dSGeir Ola Vaagland /* Check if we allow SCTP_RCVINFO. */ 21300d3a421dSGeir Ola Vaagland if (sp->recvrcvinfo) 21310d3a421dSGeir Ola Vaagland sctp_ulpevent_read_rcvinfo(event, msg); 21321da177e4SLinus Torvalds /* Check if we allow SCTP_SNDRCVINFO. */ 21332cc0eeb6SXin Long if (sctp_ulpevent_type_enabled(sp->subscribe, SCTP_DATA_IO_EVENT)) 21341da177e4SLinus Torvalds sctp_ulpevent_read_sndrcvinfo(event, msg); 21350d3a421dSGeir Ola Vaagland 21361da177e4SLinus Torvalds err = copied; 21371da177e4SLinus Torvalds 21381da177e4SLinus Torvalds /* If skb's length exceeds the user's buffer, update the skb and 21391da177e4SLinus Torvalds * push it back to the receive_queue so that the next call to 21401da177e4SLinus Torvalds * recvmsg() will return the remaining data. Don't set MSG_EOR. 21411da177e4SLinus Torvalds */ 21421da177e4SLinus Torvalds if (skb_len > copied) { 21431da177e4SLinus Torvalds msg->msg_flags &= ~MSG_EOR; 21441da177e4SLinus Torvalds if (flags & MSG_PEEK) 21451da177e4SLinus Torvalds goto out_free; 21461da177e4SLinus Torvalds sctp_skb_pull(skb, copied); 21471da177e4SLinus Torvalds skb_queue_head(&sk->sk_receive_queue, skb); 21481da177e4SLinus Torvalds 2149362d5204SDaniel Borkmann /* When only partial message is copied to the user, increase 2150362d5204SDaniel Borkmann * rwnd by that amount. If all the data in the skb is read, 2151362d5204SDaniel Borkmann * rwnd is updated when the event is freed. 2152362d5204SDaniel Borkmann */ 2153362d5204SDaniel Borkmann if (!sctp_ulpevent_is_notification(event)) 2154362d5204SDaniel Borkmann sctp_assoc_rwnd_increase(event->asoc, copied); 21551da177e4SLinus Torvalds goto out; 21561da177e4SLinus Torvalds } else if ((event->msg_flags & MSG_NOTIFICATION) || 21571da177e4SLinus Torvalds (event->msg_flags & MSG_EOR)) 21581da177e4SLinus Torvalds msg->msg_flags |= MSG_EOR; 21591da177e4SLinus Torvalds else 21601da177e4SLinus Torvalds msg->msg_flags &= ~MSG_EOR; 21611da177e4SLinus Torvalds 21621da177e4SLinus Torvalds out_free: 21631da177e4SLinus Torvalds if (flags & MSG_PEEK) { 21641da177e4SLinus Torvalds /* Release the skb reference acquired after peeking the skb in 21651da177e4SLinus Torvalds * sctp_skb_recv_datagram(). 21661da177e4SLinus Torvalds */ 21671da177e4SLinus Torvalds kfree_skb(skb); 21681da177e4SLinus Torvalds } else { 21691da177e4SLinus Torvalds /* Free the event which includes releasing the reference to 21701da177e4SLinus Torvalds * the owner of the skb, freeing the skb and updating the 21711da177e4SLinus Torvalds * rwnd. 21721da177e4SLinus Torvalds */ 21731da177e4SLinus Torvalds sctp_ulpevent_free(event); 21741da177e4SLinus Torvalds } 21751da177e4SLinus Torvalds out: 2176048ed4b6Swangweidong release_sock(sk); 21771da177e4SLinus Torvalds return err; 21781da177e4SLinus Torvalds } 21791da177e4SLinus Torvalds 21801da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) 21811da177e4SLinus Torvalds * 21821da177e4SLinus Torvalds * This option is a on/off flag. If enabled no SCTP message 21831da177e4SLinus Torvalds * fragmentation will be performed. Instead if a message being sent 21841da177e4SLinus Torvalds * exceeds the current PMTU size, the message will NOT be sent and 21851da177e4SLinus Torvalds * instead a error will be indicated to the user. 21861da177e4SLinus Torvalds */ 218710835825SChristoph Hellwig static int sctp_setsockopt_disable_fragments(struct sock *sk, int *val, 2188b7058842SDavid S. Miller unsigned int optlen) 21891da177e4SLinus Torvalds { 21901da177e4SLinus Torvalds if (optlen < sizeof(int)) 21911da177e4SLinus Torvalds return -EINVAL; 219210835825SChristoph Hellwig sctp_sk(sk)->disable_fragments = (*val == 0) ? 0 : 1; 21931da177e4SLinus Torvalds return 0; 21941da177e4SLinus Torvalds } 21951da177e4SLinus Torvalds 2196a98d21a1SChristoph Hellwig static int sctp_setsockopt_events(struct sock *sk, __u8 *sn_type, 2197b7058842SDavid S. Miller unsigned int optlen) 21981da177e4SLinus Torvalds { 21992cc0eeb6SXin Long struct sctp_sock *sp = sctp_sk(sk); 2200a1e3a059SXin Long struct sctp_association *asoc; 22012cc0eeb6SXin Long int i; 220294912301SWei Yongjun 22037e8616d8SVlad Yasevich if (optlen > sizeof(struct sctp_event_subscribe)) 22041da177e4SLinus Torvalds return -EINVAL; 22052cc0eeb6SXin Long 22062cc0eeb6SXin Long for (i = 0; i < optlen; i++) 22072cc0eeb6SXin Long sctp_ulpevent_type_set(&sp->subscribe, SCTP_SN_TYPE_BASE + i, 22082cc0eeb6SXin Long sn_type[i]); 22092cc0eeb6SXin Long 2210a1e3a059SXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) 2211a1e3a059SXin Long asoc->subscribe = sctp_sk(sk)->subscribe; 2212a1e3a059SXin Long 2213bbbea41dSDaniel Borkmann /* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, 221494912301SWei Yongjun * if there is no data to be sent or retransmit, the stack will 221594912301SWei Yongjun * immediately send up this notification. 221694912301SWei Yongjun */ 22172cc0eeb6SXin Long if (sctp_ulpevent_type_enabled(sp->subscribe, SCTP_SENDER_DRY_EVENT)) { 22182cc0eeb6SXin Long struct sctp_ulpevent *event; 221994912301SWei Yongjun 2220a1e3a059SXin Long asoc = sctp_id2assoc(sk, 0); 222194912301SWei Yongjun if (asoc && sctp_outq_is_empty(&asoc->outqueue)) { 222294912301SWei Yongjun event = sctp_ulpevent_make_sender_dry_event(asoc, 22232e83acb9SMarcelo Ricardo Leitner GFP_USER | __GFP_NOWARN); 222494912301SWei Yongjun if (!event) 222594912301SWei Yongjun return -ENOMEM; 222694912301SWei Yongjun 22279162e0edSXin Long asoc->stream.si->enqueue_event(&asoc->ulpq, event); 222894912301SWei Yongjun } 222994912301SWei Yongjun } 223094912301SWei Yongjun 22311da177e4SLinus Torvalds return 0; 22321da177e4SLinus Torvalds } 22331da177e4SLinus Torvalds 22341da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) 22351da177e4SLinus Torvalds * 22361da177e4SLinus Torvalds * This socket option is applicable to the UDP-style socket only. When 22371da177e4SLinus Torvalds * set it will cause associations that are idle for more than the 22381da177e4SLinus Torvalds * specified number of seconds to automatically close. An association 22391da177e4SLinus Torvalds * being idle is defined an association that has NOT sent or received 22401da177e4SLinus Torvalds * user data. The special value of '0' indicates that no automatic 22411da177e4SLinus Torvalds * close of any associations should be performed. The option expects an 22421da177e4SLinus Torvalds * integer defining the number of seconds of idle time before an 22431da177e4SLinus Torvalds * association is closed. 22441da177e4SLinus Torvalds */ 22450b49a65cSChristoph Hellwig static int sctp_setsockopt_autoclose(struct sock *sk, u32 *optval, 2246b7058842SDavid S. Miller unsigned int optlen) 22471da177e4SLinus Torvalds { 22481da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 22499f70f46bSNeil Horman struct net *net = sock_net(sk); 22501da177e4SLinus Torvalds 22511da177e4SLinus Torvalds /* Applicable to UDP-style socket only */ 22521da177e4SLinus Torvalds if (sctp_style(sk, TCP)) 22531da177e4SLinus Torvalds return -EOPNOTSUPP; 22541da177e4SLinus Torvalds if (optlen != sizeof(int)) 22551da177e4SLinus Torvalds return -EINVAL; 22561da177e4SLinus Torvalds 22570b49a65cSChristoph Hellwig sp->autoclose = *optval; 22589f70f46bSNeil Horman if (sp->autoclose > net->sctp.max_autoclose) 22599f70f46bSNeil Horman sp->autoclose = net->sctp.max_autoclose; 22609f70f46bSNeil Horman 22611da177e4SLinus Torvalds return 0; 22621da177e4SLinus Torvalds } 22631da177e4SLinus Torvalds 22641da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) 22651da177e4SLinus Torvalds * 22661da177e4SLinus Torvalds * Applications can enable or disable heartbeats for any peer address of 22671da177e4SLinus Torvalds * an association, modify an address's heartbeat interval, force a 22681da177e4SLinus Torvalds * heartbeat to be sent immediately, and adjust the address's maximum 22691da177e4SLinus Torvalds * number of retransmissions sent before an address is considered 22701da177e4SLinus Torvalds * unreachable. The following structure is used to access and modify an 22711da177e4SLinus Torvalds * address's parameters: 22721da177e4SLinus Torvalds * 22731da177e4SLinus Torvalds * struct sctp_paddrparams { 22741da177e4SLinus Torvalds * sctp_assoc_t spp_assoc_id; 22751da177e4SLinus Torvalds * struct sockaddr_storage spp_address; 22761da177e4SLinus Torvalds * uint32_t spp_hbinterval; 22771da177e4SLinus Torvalds * uint16_t spp_pathmaxrxt; 227852ccb8e9SFrank Filz * uint32_t spp_pathmtu; 227952ccb8e9SFrank Filz * uint32_t spp_sackdelay; 228052ccb8e9SFrank Filz * uint32_t spp_flags; 22810b0dce7aSXin Long * uint32_t spp_ipv6_flowlabel; 22820b0dce7aSXin Long * uint8_t spp_dscp; 22831da177e4SLinus Torvalds * }; 22841da177e4SLinus Torvalds * 228552ccb8e9SFrank Filz * spp_assoc_id - (one-to-many style socket) This is filled in the 228652ccb8e9SFrank Filz * application, and identifies the association for 228752ccb8e9SFrank Filz * this query. 22881da177e4SLinus Torvalds * spp_address - This specifies which address is of interest. 22891da177e4SLinus Torvalds * spp_hbinterval - This contains the value of the heartbeat interval, 229052ccb8e9SFrank Filz * in milliseconds. If a value of zero 229152ccb8e9SFrank Filz * is present in this field then no changes are to 229252ccb8e9SFrank Filz * be made to this parameter. 22931da177e4SLinus Torvalds * spp_pathmaxrxt - This contains the maximum number of 22941da177e4SLinus Torvalds * retransmissions before this address shall be 229552ccb8e9SFrank Filz * considered unreachable. If a value of zero 229652ccb8e9SFrank Filz * is present in this field then no changes are to 229752ccb8e9SFrank Filz * be made to this parameter. 229852ccb8e9SFrank Filz * spp_pathmtu - When Path MTU discovery is disabled the value 229952ccb8e9SFrank Filz * specified here will be the "fixed" path mtu. 230052ccb8e9SFrank Filz * Note that if the spp_address field is empty 230152ccb8e9SFrank Filz * then all associations on this address will 230252ccb8e9SFrank Filz * have this fixed path mtu set upon them. 230352ccb8e9SFrank Filz * 230452ccb8e9SFrank Filz * spp_sackdelay - When delayed sack is enabled, this value specifies 230552ccb8e9SFrank Filz * the number of milliseconds that sacks will be delayed 230652ccb8e9SFrank Filz * for. This value will apply to all addresses of an 230752ccb8e9SFrank Filz * association if the spp_address field is empty. Note 230852ccb8e9SFrank Filz * also, that if delayed sack is enabled and this 230952ccb8e9SFrank Filz * value is set to 0, no change is made to the last 231052ccb8e9SFrank Filz * recorded delayed sack timer value. 231152ccb8e9SFrank Filz * 231252ccb8e9SFrank Filz * spp_flags - These flags are used to control various features 231352ccb8e9SFrank Filz * on an association. The flag field may contain 231452ccb8e9SFrank Filz * zero or more of the following options. 231552ccb8e9SFrank Filz * 231652ccb8e9SFrank Filz * SPP_HB_ENABLE - Enable heartbeats on the 231752ccb8e9SFrank Filz * specified address. Note that if the address 231852ccb8e9SFrank Filz * field is empty all addresses for the association 231952ccb8e9SFrank Filz * have heartbeats enabled upon them. 232052ccb8e9SFrank Filz * 232152ccb8e9SFrank Filz * SPP_HB_DISABLE - Disable heartbeats on the 232252ccb8e9SFrank Filz * speicifed address. Note that if the address 232352ccb8e9SFrank Filz * field is empty all addresses for the association 232452ccb8e9SFrank Filz * will have their heartbeats disabled. Note also 232552ccb8e9SFrank Filz * that SPP_HB_ENABLE and SPP_HB_DISABLE are 232652ccb8e9SFrank Filz * mutually exclusive, only one of these two should 232752ccb8e9SFrank Filz * be specified. Enabling both fields will have 232852ccb8e9SFrank Filz * undetermined results. 232952ccb8e9SFrank Filz * 233052ccb8e9SFrank Filz * SPP_HB_DEMAND - Request a user initiated heartbeat 233152ccb8e9SFrank Filz * to be made immediately. 233252ccb8e9SFrank Filz * 2333bdf3092aSVlad Yasevich * SPP_HB_TIME_IS_ZERO - Specify's that the time for 2334bdf3092aSVlad Yasevich * heartbeat delayis to be set to the value of 0 2335bdf3092aSVlad Yasevich * milliseconds. 2336bdf3092aSVlad Yasevich * 233752ccb8e9SFrank Filz * SPP_PMTUD_ENABLE - This field will enable PMTU 233852ccb8e9SFrank Filz * discovery upon the specified address. Note that 233952ccb8e9SFrank Filz * if the address feild is empty then all addresses 234052ccb8e9SFrank Filz * on the association are effected. 234152ccb8e9SFrank Filz * 234252ccb8e9SFrank Filz * SPP_PMTUD_DISABLE - This field will disable PMTU 234352ccb8e9SFrank Filz * discovery upon the specified address. Note that 234452ccb8e9SFrank Filz * if the address feild is empty then all addresses 234552ccb8e9SFrank Filz * on the association are effected. Not also that 234652ccb8e9SFrank Filz * SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually 234752ccb8e9SFrank Filz * exclusive. Enabling both will have undetermined 234852ccb8e9SFrank Filz * results. 234952ccb8e9SFrank Filz * 235052ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE - Setting this flag turns 235152ccb8e9SFrank Filz * on delayed sack. The time specified in spp_sackdelay 235252ccb8e9SFrank Filz * is used to specify the sack delay for this address. Note 235352ccb8e9SFrank Filz * that if spp_address is empty then all addresses will 235452ccb8e9SFrank Filz * enable delayed sack and take on the sack delay 235552ccb8e9SFrank Filz * value specified in spp_sackdelay. 235652ccb8e9SFrank Filz * SPP_SACKDELAY_DISABLE - Setting this flag turns 235752ccb8e9SFrank Filz * off delayed sack. If the spp_address field is blank then 235852ccb8e9SFrank Filz * delayed sack is disabled for the entire association. Note 235952ccb8e9SFrank Filz * also that this field is mutually exclusive to 236052ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE, setting both will have undefined 236152ccb8e9SFrank Filz * results. 23620b0dce7aSXin Long * 23630b0dce7aSXin Long * SPP_IPV6_FLOWLABEL: Setting this flag enables the 23640b0dce7aSXin Long * setting of the IPV6 flow label value. The value is 23650b0dce7aSXin Long * contained in the spp_ipv6_flowlabel field. 23660b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 23670b0dce7aSXin Long * the spp_ipv6_flowlabel field has a valid value returned. 23680b0dce7aSXin Long * If a specific destination address is set (in the 23690b0dce7aSXin Long * spp_address field), then the value returned is that of 23700b0dce7aSXin Long * the address. If just an association is specified (and 23710b0dce7aSXin Long * no address), then the association's default flow label 23720b0dce7aSXin Long * is returned. If neither an association nor a destination 23730b0dce7aSXin Long * is specified, then the socket's default flow label is 23740b0dce7aSXin Long * returned. For non-IPv6 sockets, this flag will be left 23750b0dce7aSXin Long * cleared. 23760b0dce7aSXin Long * 23770b0dce7aSXin Long * SPP_DSCP: Setting this flag enables the setting of the 23780b0dce7aSXin Long * Differentiated Services Code Point (DSCP) value 23790b0dce7aSXin Long * associated with either the association or a specific 23800b0dce7aSXin Long * address. The value is obtained in the spp_dscp field. 23810b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 23820b0dce7aSXin Long * the spp_dscp field has a valid value returned. If a 23830b0dce7aSXin Long * specific destination address is set when called (in the 23840b0dce7aSXin Long * spp_address field), then that specific destination 23850b0dce7aSXin Long * address's DSCP value is returned. If just an association 23860b0dce7aSXin Long * is specified, then the association's default DSCP is 23870b0dce7aSXin Long * returned. If neither an association nor a destination is 23880b0dce7aSXin Long * specified, then the socket's default DSCP is returned. 23890b0dce7aSXin Long * 23900b0dce7aSXin Long * spp_ipv6_flowlabel 23910b0dce7aSXin Long * - This field is used in conjunction with the 23920b0dce7aSXin Long * SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label. 23930b0dce7aSXin Long * The 20 least significant bits are used for the flow 23940b0dce7aSXin Long * label. This setting has precedence over any IPv6-layer 23950b0dce7aSXin Long * setting. 23960b0dce7aSXin Long * 23970b0dce7aSXin Long * spp_dscp - This field is used in conjunction with the SPP_DSCP flag 23980b0dce7aSXin Long * and contains the DSCP. The 6 most significant bits are 23990b0dce7aSXin Long * used for the DSCP. This setting has precedence over any 24000b0dce7aSXin Long * IPv4- or IPv6- layer setting. 24011da177e4SLinus Torvalds */ 240216164366SAdrian Bunk static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, 240352ccb8e9SFrank Filz struct sctp_transport *trans, 240452ccb8e9SFrank Filz struct sctp_association *asoc, 240552ccb8e9SFrank Filz struct sctp_sock *sp, 240652ccb8e9SFrank Filz int hb_change, 240752ccb8e9SFrank Filz int pmtud_change, 240852ccb8e9SFrank Filz int sackdelay_change) 240952ccb8e9SFrank Filz { 241052ccb8e9SFrank Filz int error; 241152ccb8e9SFrank Filz 241252ccb8e9SFrank Filz if (params->spp_flags & SPP_HB_DEMAND && trans) { 24134e7696d9SXin Long error = sctp_primitive_REQUESTHEARTBEAT(trans->asoc->base.net, 24144e7696d9SXin Long trans->asoc, trans); 241552ccb8e9SFrank Filz if (error) 241652ccb8e9SFrank Filz return error; 241752ccb8e9SFrank Filz } 241852ccb8e9SFrank Filz 2419bdf3092aSVlad Yasevich /* Note that unless the spp_flag is set to SPP_HB_ENABLE the value of 2420bdf3092aSVlad Yasevich * this field is ignored. Note also that a value of zero indicates 2421bdf3092aSVlad Yasevich * the current setting should be left unchanged. 2422bdf3092aSVlad Yasevich */ 2423bdf3092aSVlad Yasevich if (params->spp_flags & SPP_HB_ENABLE) { 2424bdf3092aSVlad Yasevich 2425bdf3092aSVlad Yasevich /* Re-zero the interval if the SPP_HB_TIME_IS_ZERO is 2426bdf3092aSVlad Yasevich * set. This lets us use 0 value when this flag 2427bdf3092aSVlad Yasevich * is set. 2428bdf3092aSVlad Yasevich */ 2429bdf3092aSVlad Yasevich if (params->spp_flags & SPP_HB_TIME_IS_ZERO) 2430bdf3092aSVlad Yasevich params->spp_hbinterval = 0; 2431bdf3092aSVlad Yasevich 2432bdf3092aSVlad Yasevich if (params->spp_hbinterval || 2433bdf3092aSVlad Yasevich (params->spp_flags & SPP_HB_TIME_IS_ZERO)) { 243452ccb8e9SFrank Filz if (trans) { 2435bdf3092aSVlad Yasevich trans->hbinterval = 2436bdf3092aSVlad Yasevich msecs_to_jiffies(params->spp_hbinterval); 243752ccb8e9SFrank Filz } else if (asoc) { 2438bdf3092aSVlad Yasevich asoc->hbinterval = 2439bdf3092aSVlad Yasevich msecs_to_jiffies(params->spp_hbinterval); 244052ccb8e9SFrank Filz } else { 244152ccb8e9SFrank Filz sp->hbinterval = params->spp_hbinterval; 244252ccb8e9SFrank Filz } 244352ccb8e9SFrank Filz } 2444bdf3092aSVlad Yasevich } 244552ccb8e9SFrank Filz 244652ccb8e9SFrank Filz if (hb_change) { 244752ccb8e9SFrank Filz if (trans) { 244852ccb8e9SFrank Filz trans->param_flags = 244952ccb8e9SFrank Filz (trans->param_flags & ~SPP_HB) | hb_change; 245052ccb8e9SFrank Filz } else if (asoc) { 245152ccb8e9SFrank Filz asoc->param_flags = 245252ccb8e9SFrank Filz (asoc->param_flags & ~SPP_HB) | hb_change; 245352ccb8e9SFrank Filz } else { 245452ccb8e9SFrank Filz sp->param_flags = 245552ccb8e9SFrank Filz (sp->param_flags & ~SPP_HB) | hb_change; 245652ccb8e9SFrank Filz } 245752ccb8e9SFrank Filz } 245852ccb8e9SFrank Filz 2459bdf3092aSVlad Yasevich /* When Path MTU discovery is disabled the value specified here will 2460bdf3092aSVlad Yasevich * be the "fixed" path mtu (i.e. the value of the spp_flags field must 2461bdf3092aSVlad Yasevich * include the flag SPP_PMTUD_DISABLE for this field to have any 2462bdf3092aSVlad Yasevich * effect). 2463bdf3092aSVlad Yasevich */ 2464bdf3092aSVlad Yasevich if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { 246552ccb8e9SFrank Filz if (trans) { 246652ccb8e9SFrank Filz trans->pathmtu = params->spp_pathmtu; 24673ebfdf08SXin Long sctp_assoc_sync_pmtu(asoc); 246852ccb8e9SFrank Filz } else if (asoc) { 2469c4b2893dSMarcelo Ricardo Leitner sctp_assoc_set_pmtu(asoc, params->spp_pathmtu); 247052ccb8e9SFrank Filz } else { 247152ccb8e9SFrank Filz sp->pathmtu = params->spp_pathmtu; 247252ccb8e9SFrank Filz } 247352ccb8e9SFrank Filz } 247452ccb8e9SFrank Filz 247552ccb8e9SFrank Filz if (pmtud_change) { 247652ccb8e9SFrank Filz if (trans) { 247752ccb8e9SFrank Filz int update = (trans->param_flags & SPP_PMTUD_DISABLE) && 247852ccb8e9SFrank Filz (params->spp_flags & SPP_PMTUD_ENABLE); 247952ccb8e9SFrank Filz trans->param_flags = 248052ccb8e9SFrank Filz (trans->param_flags & ~SPP_PMTUD) | pmtud_change; 248152ccb8e9SFrank Filz if (update) { 24829914ae3cSVlad Yasevich sctp_transport_pmtu(trans, sctp_opt2sk(sp)); 24833ebfdf08SXin Long sctp_assoc_sync_pmtu(asoc); 248452ccb8e9SFrank Filz } 248552ccb8e9SFrank Filz } else if (asoc) { 248652ccb8e9SFrank Filz asoc->param_flags = 248752ccb8e9SFrank Filz (asoc->param_flags & ~SPP_PMTUD) | pmtud_change; 248852ccb8e9SFrank Filz } else { 248952ccb8e9SFrank Filz sp->param_flags = 249052ccb8e9SFrank Filz (sp->param_flags & ~SPP_PMTUD) | pmtud_change; 249152ccb8e9SFrank Filz } 249252ccb8e9SFrank Filz } 249352ccb8e9SFrank Filz 2494bdf3092aSVlad Yasevich /* Note that unless the spp_flag is set to SPP_SACKDELAY_ENABLE the 2495bdf3092aSVlad Yasevich * value of this field is ignored. Note also that a value of zero 2496bdf3092aSVlad Yasevich * indicates the current setting should be left unchanged. 2497bdf3092aSVlad Yasevich */ 2498bdf3092aSVlad Yasevich if ((params->spp_flags & SPP_SACKDELAY_ENABLE) && params->spp_sackdelay) { 249952ccb8e9SFrank Filz if (trans) { 250052ccb8e9SFrank Filz trans->sackdelay = 250152ccb8e9SFrank Filz msecs_to_jiffies(params->spp_sackdelay); 250252ccb8e9SFrank Filz } else if (asoc) { 250352ccb8e9SFrank Filz asoc->sackdelay = 250452ccb8e9SFrank Filz msecs_to_jiffies(params->spp_sackdelay); 250552ccb8e9SFrank Filz } else { 250652ccb8e9SFrank Filz sp->sackdelay = params->spp_sackdelay; 250752ccb8e9SFrank Filz } 250852ccb8e9SFrank Filz } 250952ccb8e9SFrank Filz 251052ccb8e9SFrank Filz if (sackdelay_change) { 251152ccb8e9SFrank Filz if (trans) { 251252ccb8e9SFrank Filz trans->param_flags = 251352ccb8e9SFrank Filz (trans->param_flags & ~SPP_SACKDELAY) | 251452ccb8e9SFrank Filz sackdelay_change; 251552ccb8e9SFrank Filz } else if (asoc) { 251652ccb8e9SFrank Filz asoc->param_flags = 251752ccb8e9SFrank Filz (asoc->param_flags & ~SPP_SACKDELAY) | 251852ccb8e9SFrank Filz sackdelay_change; 251952ccb8e9SFrank Filz } else { 252052ccb8e9SFrank Filz sp->param_flags = 252152ccb8e9SFrank Filz (sp->param_flags & ~SPP_SACKDELAY) | 252252ccb8e9SFrank Filz sackdelay_change; 252352ccb8e9SFrank Filz } 252452ccb8e9SFrank Filz } 252552ccb8e9SFrank Filz 252637051f73SAndrei Pelinescu-Onciul /* Note that a value of zero indicates the current setting should be 252737051f73SAndrei Pelinescu-Onciul left unchanged. 2528bdf3092aSVlad Yasevich */ 252937051f73SAndrei Pelinescu-Onciul if (params->spp_pathmaxrxt) { 253052ccb8e9SFrank Filz if (trans) { 253152ccb8e9SFrank Filz trans->pathmaxrxt = params->spp_pathmaxrxt; 253252ccb8e9SFrank Filz } else if (asoc) { 253352ccb8e9SFrank Filz asoc->pathmaxrxt = params->spp_pathmaxrxt; 253452ccb8e9SFrank Filz } else { 253552ccb8e9SFrank Filz sp->pathmaxrxt = params->spp_pathmaxrxt; 253652ccb8e9SFrank Filz } 253752ccb8e9SFrank Filz } 253852ccb8e9SFrank Filz 25390b0dce7aSXin Long if (params->spp_flags & SPP_IPV6_FLOWLABEL) { 2540741880e1SXin Long if (trans) { 2541741880e1SXin Long if (trans->ipaddr.sa.sa_family == AF_INET6) { 25420b0dce7aSXin Long trans->flowlabel = params->spp_ipv6_flowlabel & 25430b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 25440b0dce7aSXin Long trans->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 2545741880e1SXin Long } 25460b0dce7aSXin Long } else if (asoc) { 2547af8a2b8bSXin Long struct sctp_transport *t; 2548af8a2b8bSXin Long 2549af8a2b8bSXin Long list_for_each_entry(t, &asoc->peer.transport_addr_list, 25500b0dce7aSXin Long transports) { 2551af8a2b8bSXin Long if (t->ipaddr.sa.sa_family != AF_INET6) 25520b0dce7aSXin Long continue; 2553af8a2b8bSXin Long t->flowlabel = params->spp_ipv6_flowlabel & 25540b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 2555af8a2b8bSXin Long t->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 25560b0dce7aSXin Long } 25570b0dce7aSXin Long asoc->flowlabel = params->spp_ipv6_flowlabel & 25580b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 25590b0dce7aSXin Long asoc->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 25600b0dce7aSXin Long } else if (sctp_opt2sk(sp)->sk_family == AF_INET6) { 25610b0dce7aSXin Long sp->flowlabel = params->spp_ipv6_flowlabel & 25620b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 25630b0dce7aSXin Long sp->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 25640b0dce7aSXin Long } 25650b0dce7aSXin Long } 25660b0dce7aSXin Long 25670b0dce7aSXin Long if (params->spp_flags & SPP_DSCP) { 25680b0dce7aSXin Long if (trans) { 25690b0dce7aSXin Long trans->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK; 25700b0dce7aSXin Long trans->dscp |= SCTP_DSCP_SET_MASK; 25710b0dce7aSXin Long } else if (asoc) { 2572af8a2b8bSXin Long struct sctp_transport *t; 2573af8a2b8bSXin Long 2574af8a2b8bSXin Long list_for_each_entry(t, &asoc->peer.transport_addr_list, 25750b0dce7aSXin Long transports) { 2576af8a2b8bSXin Long t->dscp = params->spp_dscp & 25770b0dce7aSXin Long SCTP_DSCP_VAL_MASK; 2578af8a2b8bSXin Long t->dscp |= SCTP_DSCP_SET_MASK; 25790b0dce7aSXin Long } 25800b0dce7aSXin Long asoc->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK; 25810b0dce7aSXin Long asoc->dscp |= SCTP_DSCP_SET_MASK; 25820b0dce7aSXin Long } else { 25830b0dce7aSXin Long sp->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK; 25840b0dce7aSXin Long sp->dscp |= SCTP_DSCP_SET_MASK; 25850b0dce7aSXin Long } 25860b0dce7aSXin Long } 25870b0dce7aSXin Long 258852ccb8e9SFrank Filz return 0; 258952ccb8e9SFrank Filz } 259052ccb8e9SFrank Filz 25911da177e4SLinus Torvalds static int sctp_setsockopt_peer_addr_params(struct sock *sk, 25929b7b0d1aSChristoph Hellwig struct sctp_paddrparams *params, 2593b7058842SDavid S. Miller unsigned int optlen) 25941da177e4SLinus Torvalds { 259552ccb8e9SFrank Filz struct sctp_transport *trans = NULL; 259652ccb8e9SFrank Filz struct sctp_association *asoc = NULL; 259752ccb8e9SFrank Filz struct sctp_sock *sp = sctp_sk(sk); 25981da177e4SLinus Torvalds int error; 259952ccb8e9SFrank Filz int hb_change, pmtud_change, sackdelay_change; 26001da177e4SLinus Torvalds 26019b7b0d1aSChristoph Hellwig if (optlen == ALIGN(offsetof(struct sctp_paddrparams, 26020b0dce7aSXin Long spp_ipv6_flowlabel), 4)) { 26039b7b0d1aSChristoph Hellwig if (params->spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL)) 26040b0dce7aSXin Long return -EINVAL; 26059b7b0d1aSChristoph Hellwig } else if (optlen != sizeof(*params)) { 26060b0dce7aSXin Long return -EINVAL; 26070b0dce7aSXin Long } 26081da177e4SLinus Torvalds 260952ccb8e9SFrank Filz /* Validate flags and value parameters. */ 26109b7b0d1aSChristoph Hellwig hb_change = params->spp_flags & SPP_HB; 26119b7b0d1aSChristoph Hellwig pmtud_change = params->spp_flags & SPP_PMTUD; 26129b7b0d1aSChristoph Hellwig sackdelay_change = params->spp_flags & SPP_SACKDELAY; 26131da177e4SLinus Torvalds 261452ccb8e9SFrank Filz if (hb_change == SPP_HB || 261552ccb8e9SFrank Filz pmtud_change == SPP_PMTUD || 261652ccb8e9SFrank Filz sackdelay_change == SPP_SACKDELAY || 26179b7b0d1aSChristoph Hellwig params->spp_sackdelay > 500 || 26189b7b0d1aSChristoph Hellwig (params->spp_pathmtu && 26199b7b0d1aSChristoph Hellwig params->spp_pathmtu < SCTP_DEFAULT_MINSEGMENT)) 26201da177e4SLinus Torvalds return -EINVAL; 26211da177e4SLinus Torvalds 262252ccb8e9SFrank Filz /* If an address other than INADDR_ANY is specified, and 262352ccb8e9SFrank Filz * no transport is found, then the request is invalid. 262452ccb8e9SFrank Filz */ 26259b7b0d1aSChristoph Hellwig if (!sctp_is_any(sk, (union sctp_addr *)¶ms->spp_address)) { 26269b7b0d1aSChristoph Hellwig trans = sctp_addr_id2transport(sk, ¶ms->spp_address, 26279b7b0d1aSChristoph Hellwig params->spp_assoc_id); 26281da177e4SLinus Torvalds if (!trans) 26291da177e4SLinus Torvalds return -EINVAL; 26301da177e4SLinus Torvalds } 26311da177e4SLinus Torvalds 2632b99e5e02SXin Long /* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the 2633b99e5e02SXin Long * socket is a one to many style socket, and an association 2634b99e5e02SXin Long * was not found, then the id was invalid. 26351da177e4SLinus Torvalds */ 26369b7b0d1aSChristoph Hellwig asoc = sctp_id2assoc(sk, params->spp_assoc_id); 26379b7b0d1aSChristoph Hellwig if (!asoc && params->spp_assoc_id != SCTP_FUTURE_ASSOC && 2638b99e5e02SXin Long sctp_style(sk, UDP)) 263952ccb8e9SFrank Filz return -EINVAL; 264052ccb8e9SFrank Filz 264152ccb8e9SFrank Filz /* Heartbeat demand can only be sent on a transport or 264252ccb8e9SFrank Filz * association, but not a socket. 264352ccb8e9SFrank Filz */ 26449b7b0d1aSChristoph Hellwig if (params->spp_flags & SPP_HB_DEMAND && !trans && !asoc) 264552ccb8e9SFrank Filz return -EINVAL; 264652ccb8e9SFrank Filz 264752ccb8e9SFrank Filz /* Process parameters. */ 26489b7b0d1aSChristoph Hellwig error = sctp_apply_peer_addr_params(params, trans, asoc, sp, 264952ccb8e9SFrank Filz hb_change, pmtud_change, 265052ccb8e9SFrank Filz sackdelay_change); 265152ccb8e9SFrank Filz 265252ccb8e9SFrank Filz if (error) 265352ccb8e9SFrank Filz return error; 265452ccb8e9SFrank Filz 265552ccb8e9SFrank Filz /* If changes are for association, also apply parameters to each 265652ccb8e9SFrank Filz * transport. 265752ccb8e9SFrank Filz */ 265852ccb8e9SFrank Filz if (!trans && asoc) { 26599dbc15f0SRobert P. J. Day list_for_each_entry(trans, &asoc->peer.transport_addr_list, 26609dbc15f0SRobert P. J. Day transports) { 26619b7b0d1aSChristoph Hellwig sctp_apply_peer_addr_params(params, trans, asoc, sp, 266252ccb8e9SFrank Filz hb_change, pmtud_change, 266352ccb8e9SFrank Filz sackdelay_change); 266452ccb8e9SFrank Filz } 266552ccb8e9SFrank Filz } 26661da177e4SLinus Torvalds 26671da177e4SLinus Torvalds return 0; 26681da177e4SLinus Torvalds } 26691da177e4SLinus Torvalds 26700ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags) 26710ea5e4dfSwangweidong { 26720ea5e4dfSwangweidong return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; 26730ea5e4dfSwangweidong } 26740ea5e4dfSwangweidong 26750ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags) 26760ea5e4dfSwangweidong { 26770ea5e4dfSwangweidong return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; 26780ea5e4dfSwangweidong } 26790ea5e4dfSwangweidong 26809c5829e1SXin Long static void sctp_apply_asoc_delayed_ack(struct sctp_sack_info *params, 26819c5829e1SXin Long struct sctp_association *asoc) 26829c5829e1SXin Long { 26839c5829e1SXin Long struct sctp_transport *trans; 26849c5829e1SXin Long 26859c5829e1SXin Long if (params->sack_delay) { 26869c5829e1SXin Long asoc->sackdelay = msecs_to_jiffies(params->sack_delay); 26879c5829e1SXin Long asoc->param_flags = 26889c5829e1SXin Long sctp_spp_sackdelay_enable(asoc->param_flags); 26899c5829e1SXin Long } 26909c5829e1SXin Long if (params->sack_freq == 1) { 26919c5829e1SXin Long asoc->param_flags = 26929c5829e1SXin Long sctp_spp_sackdelay_disable(asoc->param_flags); 26939c5829e1SXin Long } else if (params->sack_freq > 1) { 26949c5829e1SXin Long asoc->sackfreq = params->sack_freq; 26959c5829e1SXin Long asoc->param_flags = 26969c5829e1SXin Long sctp_spp_sackdelay_enable(asoc->param_flags); 26979c5829e1SXin Long } 26989c5829e1SXin Long 26999c5829e1SXin Long list_for_each_entry(trans, &asoc->peer.transport_addr_list, 27009c5829e1SXin Long transports) { 27019c5829e1SXin Long if (params->sack_delay) { 27029c5829e1SXin Long trans->sackdelay = msecs_to_jiffies(params->sack_delay); 27039c5829e1SXin Long trans->param_flags = 27049c5829e1SXin Long sctp_spp_sackdelay_enable(trans->param_flags); 27059c5829e1SXin Long } 27069c5829e1SXin Long if (params->sack_freq == 1) { 27079c5829e1SXin Long trans->param_flags = 27089c5829e1SXin Long sctp_spp_sackdelay_disable(trans->param_flags); 27099c5829e1SXin Long } else if (params->sack_freq > 1) { 27109c5829e1SXin Long trans->sackfreq = params->sack_freq; 27119c5829e1SXin Long trans->param_flags = 27129c5829e1SXin Long sctp_spp_sackdelay_enable(trans->param_flags); 27139c5829e1SXin Long } 27149c5829e1SXin Long } 27159c5829e1SXin Long } 27169c5829e1SXin Long 2717d364d927SWei Yongjun /* 2718d364d927SWei Yongjun * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 27197708610bSFrank Filz * 2720d364d927SWei Yongjun * This option will effect the way delayed acks are performed. This 2721d364d927SWei Yongjun * option allows you to get or set the delayed ack time, in 2722d364d927SWei Yongjun * milliseconds. It also allows changing the delayed ack frequency. 2723d364d927SWei Yongjun * Changing the frequency to 1 disables the delayed sack algorithm. If 2724d364d927SWei Yongjun * the assoc_id is 0, then this sets or gets the endpoints default 2725d364d927SWei Yongjun * values. If the assoc_id field is non-zero, then the set or get 2726d364d927SWei Yongjun * effects the specified association for the one to many model (the 2727d364d927SWei Yongjun * assoc_id field is ignored by the one to one model). Note that if 2728d364d927SWei Yongjun * sack_delay or sack_freq are 0 when setting this option, then the 2729d364d927SWei Yongjun * current values will remain unchanged. 27307708610bSFrank Filz * 2731d364d927SWei Yongjun * struct sctp_sack_info { 2732d364d927SWei Yongjun * sctp_assoc_t sack_assoc_id; 2733d364d927SWei Yongjun * uint32_t sack_delay; 2734d364d927SWei Yongjun * uint32_t sack_freq; 27357708610bSFrank Filz * }; 27367708610bSFrank Filz * 2737d364d927SWei Yongjun * sack_assoc_id - This parameter, indicates which association the user 2738d364d927SWei Yongjun * is performing an action upon. Note that if this field's value is 2739d364d927SWei Yongjun * zero then the endpoints default value is changed (effecting future 27407708610bSFrank Filz * associations only). 27417708610bSFrank Filz * 2742d364d927SWei Yongjun * sack_delay - This parameter contains the number of milliseconds that 2743d364d927SWei Yongjun * the user is requesting the delayed ACK timer be set to. Note that 2744d364d927SWei Yongjun * this value is defined in the standard to be between 200 and 500 2745d364d927SWei Yongjun * milliseconds. 27467708610bSFrank Filz * 2747d364d927SWei Yongjun * sack_freq - This parameter contains the number of packets that must 2748d364d927SWei Yongjun * be received before a sack is sent without waiting for the delay 2749d364d927SWei Yongjun * timer to expire. The default value for this is 2, setting this 2750d364d927SWei Yongjun * value to 1 will disable the delayed sack algorithm. 27517708610bSFrank Filz */ 27527708610bSFrank Filz 2753d364d927SWei Yongjun static int sctp_setsockopt_delayed_ack(struct sock *sk, 2754ebb25defSChristoph Hellwig struct sctp_sack_info *params, 2755ebb25defSChristoph Hellwig unsigned int optlen) 27567708610bSFrank Filz { 27577708610bSFrank Filz struct sctp_sock *sp = sctp_sk(sk); 27589c5829e1SXin Long struct sctp_association *asoc; 27597708610bSFrank Filz 2760d364d927SWei Yongjun if (optlen == sizeof(struct sctp_sack_info)) { 2761ebb25defSChristoph Hellwig if (params->sack_delay == 0 && params->sack_freq == 0) 2762d364d927SWei Yongjun return 0; 2763d364d927SWei Yongjun } else if (optlen == sizeof(struct sctp_assoc_value)) { 276494f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 2765f916ec96SNeil Horman "%s (pid %d) " 276694f65193SNeil Horman "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 2767f916ec96SNeil Horman "Use struct sctp_sack_info instead\n", 2768f916ec96SNeil Horman current->comm, task_pid_nr(current)); 2769d364d927SWei Yongjun 2770ebb25defSChristoph Hellwig if (params->sack_delay == 0) 2771ebb25defSChristoph Hellwig params->sack_freq = 1; 2772d364d927SWei Yongjun else 2773ebb25defSChristoph Hellwig params->sack_freq = 0; 2774d364d927SWei Yongjun } else 27757708610bSFrank Filz return -EINVAL; 27767708610bSFrank Filz 2777d364d927SWei Yongjun /* Validate value parameter. */ 2778ebb25defSChristoph Hellwig if (params->sack_delay > 500) 2779d364d927SWei Yongjun return -EINVAL; 2780d364d927SWei Yongjun 27819c5829e1SXin Long /* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the 27829c5829e1SXin Long * socket is a one to many style socket, and an association 27839c5829e1SXin Long * was not found, then the id was invalid. 27847708610bSFrank Filz */ 2785ebb25defSChristoph Hellwig asoc = sctp_id2assoc(sk, params->sack_assoc_id); 2786ebb25defSChristoph Hellwig if (!asoc && params->sack_assoc_id > SCTP_ALL_ASSOC && 27879c5829e1SXin Long sctp_style(sk, UDP)) 27887708610bSFrank Filz return -EINVAL; 27897708610bSFrank Filz 27907708610bSFrank Filz if (asoc) { 2791ebb25defSChristoph Hellwig sctp_apply_asoc_delayed_ack(params, asoc); 27929c5829e1SXin Long 27939c5829e1SXin Long return 0; 27949c5829e1SXin Long } 27959c5829e1SXin Long 27968e2614fcSXin Long if (sctp_style(sk, TCP)) 2797ebb25defSChristoph Hellwig params->sack_assoc_id = SCTP_FUTURE_ASSOC; 27988e2614fcSXin Long 2799ebb25defSChristoph Hellwig if (params->sack_assoc_id == SCTP_FUTURE_ASSOC || 2800ebb25defSChristoph Hellwig params->sack_assoc_id == SCTP_ALL_ASSOC) { 2801ebb25defSChristoph Hellwig if (params->sack_delay) { 2802ebb25defSChristoph Hellwig sp->sackdelay = params->sack_delay; 28037708610bSFrank Filz sp->param_flags = 28040ea5e4dfSwangweidong sctp_spp_sackdelay_enable(sp->param_flags); 28057708610bSFrank Filz } 2806ebb25defSChristoph Hellwig if (params->sack_freq == 1) { 28077708610bSFrank Filz sp->param_flags = 28080ea5e4dfSwangweidong sctp_spp_sackdelay_disable(sp->param_flags); 2809ebb25defSChristoph Hellwig } else if (params->sack_freq > 1) { 2810ebb25defSChristoph Hellwig sp->sackfreq = params->sack_freq; 2811d364d927SWei Yongjun sp->param_flags = 28120ea5e4dfSwangweidong sctp_spp_sackdelay_enable(sp->param_flags); 2813d364d927SWei Yongjun } 28147708610bSFrank Filz } 28157708610bSFrank Filz 2816ebb25defSChristoph Hellwig if (params->sack_assoc_id == SCTP_CURRENT_ASSOC || 2817ebb25defSChristoph Hellwig params->sack_assoc_id == SCTP_ALL_ASSOC) 28189c5829e1SXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) 2819ebb25defSChristoph Hellwig sctp_apply_asoc_delayed_ack(params, asoc); 28207708610bSFrank Filz 28217708610bSFrank Filz return 0; 28227708610bSFrank Filz } 28237708610bSFrank Filz 28241da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG) 28251da177e4SLinus Torvalds * 28261da177e4SLinus Torvalds * Applications can specify protocol parameters for the default association 28271da177e4SLinus Torvalds * initialization. The option name argument to setsockopt() and getsockopt() 28281da177e4SLinus Torvalds * is SCTP_INITMSG. 28291da177e4SLinus Torvalds * 28301da177e4SLinus Torvalds * Setting initialization parameters is effective only on an unconnected 28311da177e4SLinus Torvalds * socket (for UDP-style sockets only future associations are effected 28321da177e4SLinus Torvalds * by the change). With TCP-style sockets, this option is inherited by 28331da177e4SLinus Torvalds * sockets derived from a listener socket. 28341da177e4SLinus Torvalds */ 28359dfa6f04SChristoph Hellwig static int sctp_setsockopt_initmsg(struct sock *sk, struct sctp_initmsg *sinit, 28369dfa6f04SChristoph Hellwig unsigned int optlen) 28371da177e4SLinus Torvalds { 28381da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 28391da177e4SLinus Torvalds 28401da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_initmsg)) 28411da177e4SLinus Torvalds return -EINVAL; 28421da177e4SLinus Torvalds 28439dfa6f04SChristoph Hellwig if (sinit->sinit_num_ostreams) 28449dfa6f04SChristoph Hellwig sp->initmsg.sinit_num_ostreams = sinit->sinit_num_ostreams; 28459dfa6f04SChristoph Hellwig if (sinit->sinit_max_instreams) 28469dfa6f04SChristoph Hellwig sp->initmsg.sinit_max_instreams = sinit->sinit_max_instreams; 28479dfa6f04SChristoph Hellwig if (sinit->sinit_max_attempts) 28489dfa6f04SChristoph Hellwig sp->initmsg.sinit_max_attempts = sinit->sinit_max_attempts; 28499dfa6f04SChristoph Hellwig if (sinit->sinit_max_init_timeo) 28509dfa6f04SChristoph Hellwig sp->initmsg.sinit_max_init_timeo = sinit->sinit_max_init_timeo; 28511da177e4SLinus Torvalds 28521da177e4SLinus Torvalds return 0; 28531da177e4SLinus Torvalds } 28541da177e4SLinus Torvalds 28551da177e4SLinus Torvalds /* 28561da177e4SLinus Torvalds * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 28571da177e4SLinus Torvalds * 28581da177e4SLinus Torvalds * Applications that wish to use the sendto() system call may wish to 28591da177e4SLinus Torvalds * specify a default set of parameters that would normally be supplied 28601da177e4SLinus Torvalds * through the inclusion of ancillary data. This socket option allows 28611da177e4SLinus Torvalds * such an application to set the default sctp_sndrcvinfo structure. 28621da177e4SLinus Torvalds * The application that wishes to use this socket option simply passes 28631da177e4SLinus Torvalds * in to this call the sctp_sndrcvinfo structure defined in Section 28641da177e4SLinus Torvalds * 5.2.2) The input parameters accepted by this call include 28651da177e4SLinus Torvalds * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 28661da177e4SLinus Torvalds * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 28671da177e4SLinus Torvalds * to this call if the caller is using the UDP model. 28681da177e4SLinus Torvalds */ 28691da177e4SLinus Torvalds static int sctp_setsockopt_default_send_param(struct sock *sk, 2870c23ad6d2SChristoph Hellwig struct sctp_sndrcvinfo *info, 2871b7058842SDavid S. Miller unsigned int optlen) 28721da177e4SLinus Torvalds { 28731da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 28746b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 28751da177e4SLinus Torvalds 2876c23ad6d2SChristoph Hellwig if (optlen != sizeof(*info)) 28771da177e4SLinus Torvalds return -EINVAL; 2878c23ad6d2SChristoph Hellwig if (info->sinfo_flags & 28796b3fd5f3SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 28806b3fd5f3SGeir Ola Vaagland SCTP_ABORT | SCTP_EOF)) 28816b3fd5f3SGeir Ola Vaagland return -EINVAL; 28821da177e4SLinus Torvalds 2883c23ad6d2SChristoph Hellwig asoc = sctp_id2assoc(sk, info->sinfo_assoc_id); 2884c23ad6d2SChristoph Hellwig if (!asoc && info->sinfo_assoc_id > SCTP_ALL_ASSOC && 2885707e45b3SXin Long sctp_style(sk, UDP)) 28861da177e4SLinus Torvalds return -EINVAL; 2887707e45b3SXin Long 28881da177e4SLinus Torvalds if (asoc) { 2889c23ad6d2SChristoph Hellwig asoc->default_stream = info->sinfo_stream; 2890c23ad6d2SChristoph Hellwig asoc->default_flags = info->sinfo_flags; 2891c23ad6d2SChristoph Hellwig asoc->default_ppid = info->sinfo_ppid; 2892c23ad6d2SChristoph Hellwig asoc->default_context = info->sinfo_context; 2893c23ad6d2SChristoph Hellwig asoc->default_timetolive = info->sinfo_timetolive; 2894707e45b3SXin Long 2895707e45b3SXin Long return 0; 2896707e45b3SXin Long } 2897707e45b3SXin Long 28981354e72fSMarcelo Ricardo Leitner if (sctp_style(sk, TCP)) 2899c23ad6d2SChristoph Hellwig info->sinfo_assoc_id = SCTP_FUTURE_ASSOC; 29001354e72fSMarcelo Ricardo Leitner 2901c23ad6d2SChristoph Hellwig if (info->sinfo_assoc_id == SCTP_FUTURE_ASSOC || 2902c23ad6d2SChristoph Hellwig info->sinfo_assoc_id == SCTP_ALL_ASSOC) { 2903c23ad6d2SChristoph Hellwig sp->default_stream = info->sinfo_stream; 2904c23ad6d2SChristoph Hellwig sp->default_flags = info->sinfo_flags; 2905c23ad6d2SChristoph Hellwig sp->default_ppid = info->sinfo_ppid; 2906c23ad6d2SChristoph Hellwig sp->default_context = info->sinfo_context; 2907c23ad6d2SChristoph Hellwig sp->default_timetolive = info->sinfo_timetolive; 29081da177e4SLinus Torvalds } 29091da177e4SLinus Torvalds 2910c23ad6d2SChristoph Hellwig if (info->sinfo_assoc_id == SCTP_CURRENT_ASSOC || 2911c23ad6d2SChristoph Hellwig info->sinfo_assoc_id == SCTP_ALL_ASSOC) { 2912707e45b3SXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 2913c23ad6d2SChristoph Hellwig asoc->default_stream = info->sinfo_stream; 2914c23ad6d2SChristoph Hellwig asoc->default_flags = info->sinfo_flags; 2915c23ad6d2SChristoph Hellwig asoc->default_ppid = info->sinfo_ppid; 2916c23ad6d2SChristoph Hellwig asoc->default_context = info->sinfo_context; 2917c23ad6d2SChristoph Hellwig asoc->default_timetolive = info->sinfo_timetolive; 2918707e45b3SXin Long } 2919707e45b3SXin Long } 2920707e45b3SXin Long 29211da177e4SLinus Torvalds return 0; 29221da177e4SLinus Torvalds } 29231da177e4SLinus Torvalds 29246b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters 29256b3fd5f3SGeir Ola Vaagland * (SCTP_DEFAULT_SNDINFO) 29266b3fd5f3SGeir Ola Vaagland */ 29276b3fd5f3SGeir Ola Vaagland static int sctp_setsockopt_default_sndinfo(struct sock *sk, 29288a2409d3SChristoph Hellwig struct sctp_sndinfo *info, 29296b3fd5f3SGeir Ola Vaagland unsigned int optlen) 29306b3fd5f3SGeir Ola Vaagland { 29316b3fd5f3SGeir Ola Vaagland struct sctp_sock *sp = sctp_sk(sk); 29326b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 29336b3fd5f3SGeir Ola Vaagland 29348a2409d3SChristoph Hellwig if (optlen != sizeof(*info)) 29356b3fd5f3SGeir Ola Vaagland return -EINVAL; 29368a2409d3SChristoph Hellwig if (info->snd_flags & 29376b3fd5f3SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 29386b3fd5f3SGeir Ola Vaagland SCTP_ABORT | SCTP_EOF)) 29396b3fd5f3SGeir Ola Vaagland return -EINVAL; 29406b3fd5f3SGeir Ola Vaagland 29418a2409d3SChristoph Hellwig asoc = sctp_id2assoc(sk, info->snd_assoc_id); 29428a2409d3SChristoph Hellwig if (!asoc && info->snd_assoc_id > SCTP_ALL_ASSOC && 294392fc3bd9SXin Long sctp_style(sk, UDP)) 29446b3fd5f3SGeir Ola Vaagland return -EINVAL; 294592fc3bd9SXin Long 29466b3fd5f3SGeir Ola Vaagland if (asoc) { 29478a2409d3SChristoph Hellwig asoc->default_stream = info->snd_sid; 29488a2409d3SChristoph Hellwig asoc->default_flags = info->snd_flags; 29498a2409d3SChristoph Hellwig asoc->default_ppid = info->snd_ppid; 29508a2409d3SChristoph Hellwig asoc->default_context = info->snd_context; 295192fc3bd9SXin Long 295292fc3bd9SXin Long return 0; 295392fc3bd9SXin Long } 295492fc3bd9SXin Long 2955a842e65bSXin Long if (sctp_style(sk, TCP)) 29568a2409d3SChristoph Hellwig info->snd_assoc_id = SCTP_FUTURE_ASSOC; 2957a842e65bSXin Long 29588a2409d3SChristoph Hellwig if (info->snd_assoc_id == SCTP_FUTURE_ASSOC || 29598a2409d3SChristoph Hellwig info->snd_assoc_id == SCTP_ALL_ASSOC) { 29608a2409d3SChristoph Hellwig sp->default_stream = info->snd_sid; 29618a2409d3SChristoph Hellwig sp->default_flags = info->snd_flags; 29628a2409d3SChristoph Hellwig sp->default_ppid = info->snd_ppid; 29638a2409d3SChristoph Hellwig sp->default_context = info->snd_context; 29646b3fd5f3SGeir Ola Vaagland } 29656b3fd5f3SGeir Ola Vaagland 29668a2409d3SChristoph Hellwig if (info->snd_assoc_id == SCTP_CURRENT_ASSOC || 29678a2409d3SChristoph Hellwig info->snd_assoc_id == SCTP_ALL_ASSOC) { 296892fc3bd9SXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 29698a2409d3SChristoph Hellwig asoc->default_stream = info->snd_sid; 29708a2409d3SChristoph Hellwig asoc->default_flags = info->snd_flags; 29718a2409d3SChristoph Hellwig asoc->default_ppid = info->snd_ppid; 29728a2409d3SChristoph Hellwig asoc->default_context = info->snd_context; 297392fc3bd9SXin Long } 297492fc3bd9SXin Long } 297592fc3bd9SXin Long 29766b3fd5f3SGeir Ola Vaagland return 0; 29776b3fd5f3SGeir Ola Vaagland } 29786b3fd5f3SGeir Ola Vaagland 29791da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 29801da177e4SLinus Torvalds * 29811da177e4SLinus Torvalds * Requests that the local SCTP stack use the enclosed peer address as 29821da177e4SLinus Torvalds * the association primary. The enclosed address must be one of the 29831da177e4SLinus Torvalds * association peer's addresses. 29841da177e4SLinus Torvalds */ 29851eec6958SChristoph Hellwig static int sctp_setsockopt_primary_addr(struct sock *sk, struct sctp_prim *prim, 2986b7058842SDavid S. Miller unsigned int optlen) 29871da177e4SLinus Torvalds { 29881da177e4SLinus Torvalds struct sctp_transport *trans; 29892277c7cdSRichard Haines struct sctp_af *af; 29902277c7cdSRichard Haines int err; 29911da177e4SLinus Torvalds 29921da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_prim)) 29931da177e4SLinus Torvalds return -EINVAL; 29941da177e4SLinus Torvalds 29952277c7cdSRichard Haines /* Allow security module to validate address but need address len. */ 29961eec6958SChristoph Hellwig af = sctp_get_af_specific(prim->ssp_addr.ss_family); 29972277c7cdSRichard Haines if (!af) 29982277c7cdSRichard Haines return -EINVAL; 29992277c7cdSRichard Haines 30002277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR, 30011eec6958SChristoph Hellwig (struct sockaddr *)&prim->ssp_addr, 30022277c7cdSRichard Haines af->sockaddr_len); 30032277c7cdSRichard Haines if (err) 30042277c7cdSRichard Haines return err; 30052277c7cdSRichard Haines 30061eec6958SChristoph Hellwig trans = sctp_addr_id2transport(sk, &prim->ssp_addr, prim->ssp_assoc_id); 30071da177e4SLinus Torvalds if (!trans) 30081da177e4SLinus Torvalds return -EINVAL; 30091da177e4SLinus Torvalds 30101da177e4SLinus Torvalds sctp_assoc_set_primary(trans->asoc, trans); 30111da177e4SLinus Torvalds 30121da177e4SLinus Torvalds return 0; 30131da177e4SLinus Torvalds } 30141da177e4SLinus Torvalds 30151da177e4SLinus Torvalds /* 30161da177e4SLinus Torvalds * 7.1.5 SCTP_NODELAY 30171da177e4SLinus Torvalds * 30181da177e4SLinus Torvalds * Turn on/off any Nagle-like algorithm. This means that packets are 30191da177e4SLinus Torvalds * generally sent as soon as possible and no unnecessary delays are 30201da177e4SLinus Torvalds * introduced, at the cost of more packets in the network. Expects an 30211da177e4SLinus Torvalds * integer boolean flag. 30221da177e4SLinus Torvalds */ 3023f87ddbc0SChristoph Hellwig static int sctp_setsockopt_nodelay(struct sock *sk, int *val, 3024b7058842SDavid S. Miller unsigned int optlen) 30251da177e4SLinus Torvalds { 30261da177e4SLinus Torvalds if (optlen < sizeof(int)) 30271da177e4SLinus Torvalds return -EINVAL; 3028f87ddbc0SChristoph Hellwig sctp_sk(sk)->nodelay = (*val == 0) ? 0 : 1; 30291da177e4SLinus Torvalds return 0; 30301da177e4SLinus Torvalds } 30311da177e4SLinus Torvalds 30321da177e4SLinus Torvalds /* 30331da177e4SLinus Torvalds * 30341da177e4SLinus Torvalds * 7.1.1 SCTP_RTOINFO 30351da177e4SLinus Torvalds * 30361da177e4SLinus Torvalds * The protocol parameters used to initialize and bound retransmission 30371da177e4SLinus Torvalds * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 30381da177e4SLinus Torvalds * and modify these parameters. 30391da177e4SLinus Torvalds * All parameters are time values, in milliseconds. A value of 0, when 30401da177e4SLinus Torvalds * modifying the parameters, indicates that the current value should not 30411da177e4SLinus Torvalds * be changed. 30421da177e4SLinus Torvalds * 30431da177e4SLinus Torvalds */ 3044af5ae60eSChristoph Hellwig static int sctp_setsockopt_rtoinfo(struct sock *sk, 3045af5ae60eSChristoph Hellwig struct sctp_rtoinfo *rtoinfo, 3046af5ae60eSChristoph Hellwig unsigned int optlen) 3047b7058842SDavid S. Miller { 30481da177e4SLinus Torvalds struct sctp_association *asoc; 304985f935d4Swangweidong unsigned long rto_min, rto_max; 305085f935d4Swangweidong struct sctp_sock *sp = sctp_sk(sk); 30511da177e4SLinus Torvalds 30521da177e4SLinus Torvalds if (optlen != sizeof (struct sctp_rtoinfo)) 30531da177e4SLinus Torvalds return -EINVAL; 30541da177e4SLinus Torvalds 3055af5ae60eSChristoph Hellwig asoc = sctp_id2assoc(sk, rtoinfo->srto_assoc_id); 30561da177e4SLinus Torvalds 30571da177e4SLinus Torvalds /* Set the values to the specific association */ 3058af5ae60eSChristoph Hellwig if (!asoc && rtoinfo->srto_assoc_id != SCTP_FUTURE_ASSOC && 30597adb5ed5SXin Long sctp_style(sk, UDP)) 30601da177e4SLinus Torvalds return -EINVAL; 30611da177e4SLinus Torvalds 3062af5ae60eSChristoph Hellwig rto_max = rtoinfo->srto_max; 3063af5ae60eSChristoph Hellwig rto_min = rtoinfo->srto_min; 306485f935d4Swangweidong 306585f935d4Swangweidong if (rto_max) 306685f935d4Swangweidong rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max; 306785f935d4Swangweidong else 306885f935d4Swangweidong rto_max = asoc ? asoc->rto_max : sp->rtoinfo.srto_max; 306985f935d4Swangweidong 307085f935d4Swangweidong if (rto_min) 307185f935d4Swangweidong rto_min = asoc ? msecs_to_jiffies(rto_min) : rto_min; 307285f935d4Swangweidong else 307385f935d4Swangweidong rto_min = asoc ? asoc->rto_min : sp->rtoinfo.srto_min; 307485f935d4Swangweidong 307585f935d4Swangweidong if (rto_min > rto_max) 307685f935d4Swangweidong return -EINVAL; 307785f935d4Swangweidong 30781da177e4SLinus Torvalds if (asoc) { 3079af5ae60eSChristoph Hellwig if (rtoinfo->srto_initial != 0) 30801da177e4SLinus Torvalds asoc->rto_initial = 3081af5ae60eSChristoph Hellwig msecs_to_jiffies(rtoinfo->srto_initial); 308285f935d4Swangweidong asoc->rto_max = rto_max; 308385f935d4Swangweidong asoc->rto_min = rto_min; 30841da177e4SLinus Torvalds } else { 30851da177e4SLinus Torvalds /* If there is no association or the association-id = 0 30861da177e4SLinus Torvalds * set the values to the endpoint. 30871da177e4SLinus Torvalds */ 3088af5ae60eSChristoph Hellwig if (rtoinfo->srto_initial != 0) 3089af5ae60eSChristoph Hellwig sp->rtoinfo.srto_initial = rtoinfo->srto_initial; 309085f935d4Swangweidong sp->rtoinfo.srto_max = rto_max; 309185f935d4Swangweidong sp->rtoinfo.srto_min = rto_min; 30921da177e4SLinus Torvalds } 30931da177e4SLinus Torvalds 30941da177e4SLinus Torvalds return 0; 30951da177e4SLinus Torvalds } 30961da177e4SLinus Torvalds 30971da177e4SLinus Torvalds /* 30981da177e4SLinus Torvalds * 30991da177e4SLinus Torvalds * 7.1.2 SCTP_ASSOCINFO 31001da177e4SLinus Torvalds * 310159c51591SMichael Opdenacker * This option is used to tune the maximum retransmission attempts 31021da177e4SLinus Torvalds * of the association. 31031da177e4SLinus Torvalds * Returns an error if the new association retransmission value is 31041da177e4SLinus Torvalds * greater than the sum of the retransmission value of the peer. 31051da177e4SLinus Torvalds * See [SCTP] for more information. 31061da177e4SLinus Torvalds * 31071da177e4SLinus Torvalds */ 31085b864c8dSChristoph Hellwig static int sctp_setsockopt_associnfo(struct sock *sk, 31095b864c8dSChristoph Hellwig struct sctp_assocparams *assocparams, 31105b864c8dSChristoph Hellwig unsigned int optlen) 31111da177e4SLinus Torvalds { 31121da177e4SLinus Torvalds 31131da177e4SLinus Torvalds struct sctp_association *asoc; 31141da177e4SLinus Torvalds 31151da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_assocparams)) 31161da177e4SLinus Torvalds return -EINVAL; 31171da177e4SLinus Torvalds 31185b864c8dSChristoph Hellwig asoc = sctp_id2assoc(sk, assocparams->sasoc_assoc_id); 31191da177e4SLinus Torvalds 31205b864c8dSChristoph Hellwig if (!asoc && assocparams->sasoc_assoc_id != SCTP_FUTURE_ASSOC && 31218889394dSXin Long sctp_style(sk, UDP)) 31221da177e4SLinus Torvalds return -EINVAL; 31231da177e4SLinus Torvalds 31241da177e4SLinus Torvalds /* Set the values to the specific association */ 31251da177e4SLinus Torvalds if (asoc) { 31265b864c8dSChristoph Hellwig if (assocparams->sasoc_asocmaxrxt != 0) { 3127402d68c4SVlad Yasevich __u32 path_sum = 0; 3128402d68c4SVlad Yasevich int paths = 0; 3129402d68c4SVlad Yasevich struct sctp_transport *peer_addr; 3130402d68c4SVlad Yasevich 31319dbc15f0SRobert P. J. Day list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list, 31329dbc15f0SRobert P. J. Day transports) { 3133402d68c4SVlad Yasevich path_sum += peer_addr->pathmaxrxt; 3134402d68c4SVlad Yasevich paths++; 3135402d68c4SVlad Yasevich } 3136402d68c4SVlad Yasevich 3137025dfdafSFrederik Schwarzer /* Only validate asocmaxrxt if we have more than 3138402d68c4SVlad Yasevich * one path/transport. We do this because path 3139402d68c4SVlad Yasevich * retransmissions are only counted when we have more 3140402d68c4SVlad Yasevich * then one path. 3141402d68c4SVlad Yasevich */ 3142402d68c4SVlad Yasevich if (paths > 1 && 31435b864c8dSChristoph Hellwig assocparams->sasoc_asocmaxrxt > path_sum) 3144402d68c4SVlad Yasevich return -EINVAL; 3145402d68c4SVlad Yasevich 31465b864c8dSChristoph Hellwig asoc->max_retrans = assocparams->sasoc_asocmaxrxt; 3147402d68c4SVlad Yasevich } 3148402d68c4SVlad Yasevich 31495b864c8dSChristoph Hellwig if (assocparams->sasoc_cookie_life != 0) 31505b864c8dSChristoph Hellwig asoc->cookie_life = 31515b864c8dSChristoph Hellwig ms_to_ktime(assocparams->sasoc_cookie_life); 31521da177e4SLinus Torvalds } else { 31531da177e4SLinus Torvalds /* Set the values to the endpoint */ 31541da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 31551da177e4SLinus Torvalds 31565b864c8dSChristoph Hellwig if (assocparams->sasoc_asocmaxrxt != 0) 31571da177e4SLinus Torvalds sp->assocparams.sasoc_asocmaxrxt = 31585b864c8dSChristoph Hellwig assocparams->sasoc_asocmaxrxt; 31595b864c8dSChristoph Hellwig if (assocparams->sasoc_cookie_life != 0) 31601da177e4SLinus Torvalds sp->assocparams.sasoc_cookie_life = 31615b864c8dSChristoph Hellwig assocparams->sasoc_cookie_life; 31621da177e4SLinus Torvalds } 31631da177e4SLinus Torvalds return 0; 31641da177e4SLinus Torvalds } 31651da177e4SLinus Torvalds 31661da177e4SLinus Torvalds /* 31671da177e4SLinus Torvalds * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 31681da177e4SLinus Torvalds * 31691da177e4SLinus Torvalds * This socket option is a boolean flag which turns on or off mapped V4 31701da177e4SLinus Torvalds * addresses. If this option is turned on and the socket is type 31711da177e4SLinus Torvalds * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 31721da177e4SLinus Torvalds * If this option is turned off, then no mapping will be done of V4 31731da177e4SLinus Torvalds * addresses and a user will receive both PF_INET6 and PF_INET type 31741da177e4SLinus Torvalds * addresses on the socket. 31751da177e4SLinus Torvalds */ 3176ffc08f08SChristoph Hellwig static int sctp_setsockopt_mappedv4(struct sock *sk, int *val, 3177ffc08f08SChristoph Hellwig unsigned int optlen) 31781da177e4SLinus Torvalds { 31791da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 31801da177e4SLinus Torvalds 31811da177e4SLinus Torvalds if (optlen < sizeof(int)) 31821da177e4SLinus Torvalds return -EINVAL; 3183ffc08f08SChristoph Hellwig if (*val) 31841da177e4SLinus Torvalds sp->v4mapped = 1; 31851da177e4SLinus Torvalds else 31861da177e4SLinus Torvalds sp->v4mapped = 0; 31871da177e4SLinus Torvalds 31881da177e4SLinus Torvalds return 0; 31891da177e4SLinus Torvalds } 31901da177e4SLinus Torvalds 31911da177e4SLinus Torvalds /* 3192e89c2095SWei Yongjun * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 3193e89c2095SWei Yongjun * This option will get or set the maximum size to put in any outgoing 3194e89c2095SWei Yongjun * SCTP DATA chunk. If a message is larger than this size it will be 31951da177e4SLinus Torvalds * fragmented by SCTP into the specified size. Note that the underlying 31961da177e4SLinus Torvalds * SCTP implementation may fragment into smaller sized chunks when the 31971da177e4SLinus Torvalds * PMTU of the underlying association is smaller than the value set by 3198e89c2095SWei Yongjun * the user. The default value for this option is '0' which indicates 3199e89c2095SWei Yongjun * the user is NOT limiting fragmentation and only the PMTU will effect 3200e89c2095SWei Yongjun * SCTP's choice of DATA chunk size. Note also that values set larger 3201e89c2095SWei Yongjun * than the maximum size of an IP datagram will effectively let SCTP 3202e89c2095SWei Yongjun * control fragmentation (i.e. the same as setting this option to 0). 3203e89c2095SWei Yongjun * 3204e89c2095SWei Yongjun * The following structure is used to access and modify this parameter: 3205e89c2095SWei Yongjun * 3206e89c2095SWei Yongjun * struct sctp_assoc_value { 3207e89c2095SWei Yongjun * sctp_assoc_t assoc_id; 3208e89c2095SWei Yongjun * uint32_t assoc_value; 3209e89c2095SWei Yongjun * }; 3210e89c2095SWei Yongjun * 3211e89c2095SWei Yongjun * assoc_id: This parameter is ignored for one-to-one style sockets. 3212e89c2095SWei Yongjun * For one-to-many style sockets this parameter indicates which 3213e89c2095SWei Yongjun * association the user is performing an action upon. Note that if 3214e89c2095SWei Yongjun * this field's value is zero then the endpoints default value is 3215e89c2095SWei Yongjun * changed (effecting future associations only). 3216e89c2095SWei Yongjun * assoc_value: This parameter specifies the maximum size in bytes. 32171da177e4SLinus Torvalds */ 3218dcd03575SChristoph Hellwig static int sctp_setsockopt_maxseg(struct sock *sk, 3219dcd03575SChristoph Hellwig struct sctp_assoc_value *params, 3220dcd03575SChristoph Hellwig unsigned int optlen) 32211da177e4SLinus Torvalds { 3222ecca8f88SXin Long struct sctp_sock *sp = sctp_sk(sk); 32231da177e4SLinus Torvalds struct sctp_association *asoc; 3224dcd03575SChristoph Hellwig sctp_assoc_t assoc_id; 32251da177e4SLinus Torvalds int val; 32261da177e4SLinus Torvalds 3227e89c2095SWei Yongjun if (optlen == sizeof(int)) { 322894f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 3229f916ec96SNeil Horman "%s (pid %d) " 323094f65193SNeil Horman "Use of int in maxseg socket option.\n" 3231f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 3232f916ec96SNeil Horman current->comm, task_pid_nr(current)); 3233dcd03575SChristoph Hellwig assoc_id = SCTP_FUTURE_ASSOC; 3234dcd03575SChristoph Hellwig val = *(int *)params; 3235e89c2095SWei Yongjun } else if (optlen == sizeof(struct sctp_assoc_value)) { 3236dcd03575SChristoph Hellwig assoc_id = params->assoc_id; 3237dcd03575SChristoph Hellwig val = params->assoc_value; 3238ecca8f88SXin Long } else { 3239e89c2095SWei Yongjun return -EINVAL; 3240ecca8f88SXin Long } 3241e89c2095SWei Yongjun 3242dcd03575SChristoph Hellwig asoc = sctp_id2assoc(sk, assoc_id); 3243dcd03575SChristoph Hellwig if (!asoc && assoc_id != SCTP_FUTURE_ASSOC && 32446fd769beSXin Long sctp_style(sk, UDP)) 32456fd769beSXin Long return -EINVAL; 3246439ef030SMarcelo Ricardo Leitner 3247ecca8f88SXin Long if (val) { 3248ecca8f88SXin Long int min_len, max_len; 3249439ef030SMarcelo Ricardo Leitner __u16 datasize = asoc ? sctp_datachk_len(&asoc->stream) : 3250ecca8f88SXin Long sizeof(struct sctp_data_chunk); 3251ecca8f88SXin Long 3252afd0a800SJakub Audykowicz min_len = sctp_min_frag_point(sp, datasize); 3253439ef030SMarcelo Ricardo Leitner max_len = SCTP_MAX_CHUNK_LEN - datasize; 3254ecca8f88SXin Long 3255ecca8f88SXin Long if (val < min_len || val > max_len) 32561da177e4SLinus Torvalds return -EINVAL; 3257ecca8f88SXin Long } 3258e89c2095SWei Yongjun 3259e89c2095SWei Yongjun if (asoc) { 3260f68b2e05SVlad Yasevich asoc->user_frag = val; 32612f5e3c9dSMarcelo Ricardo Leitner sctp_assoc_update_frag_point(asoc); 3262e89c2095SWei Yongjun } else { 32631da177e4SLinus Torvalds sp->user_frag = val; 3264e89c2095SWei Yongjun } 32651da177e4SLinus Torvalds 32661da177e4SLinus Torvalds return 0; 32671da177e4SLinus Torvalds } 32681da177e4SLinus Torvalds 32691da177e4SLinus Torvalds 32701da177e4SLinus Torvalds /* 32711da177e4SLinus Torvalds * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) 32721da177e4SLinus Torvalds * 32731da177e4SLinus Torvalds * Requests that the peer mark the enclosed address as the association 32741da177e4SLinus Torvalds * primary. The enclosed address must be one of the association's 32751da177e4SLinus Torvalds * locally bound addresses. The following structure is used to make a 32761da177e4SLinus Torvalds * set primary request: 32771da177e4SLinus Torvalds */ 327846a0ae9dSChristoph Hellwig static int sctp_setsockopt_peer_primary_addr(struct sock *sk, 327946a0ae9dSChristoph Hellwig struct sctp_setpeerprim *prim, 3280b7058842SDavid S. Miller unsigned int optlen) 32811da177e4SLinus Torvalds { 32821da177e4SLinus Torvalds struct sctp_sock *sp; 32831da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 32841da177e4SLinus Torvalds struct sctp_chunk *chunk; 328540a01039SWei Yongjun struct sctp_af *af; 32861da177e4SLinus Torvalds int err; 32871da177e4SLinus Torvalds 32881da177e4SLinus Torvalds sp = sctp_sk(sk); 32891da177e4SLinus Torvalds 32904e27428fSXin Long if (!sp->ep->asconf_enable) 32911da177e4SLinus Torvalds return -EPERM; 32921da177e4SLinus Torvalds 32931da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_setpeerprim)) 32941da177e4SLinus Torvalds return -EINVAL; 32951da177e4SLinus Torvalds 329646a0ae9dSChristoph Hellwig asoc = sctp_id2assoc(sk, prim->sspp_assoc_id); 32971da177e4SLinus Torvalds if (!asoc) 32981da177e4SLinus Torvalds return -EINVAL; 32991da177e4SLinus Torvalds 33001da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 33011da177e4SLinus Torvalds return -EPERM; 33021da177e4SLinus Torvalds 33031da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_SET_PRIMARY) 33041da177e4SLinus Torvalds return -EPERM; 33051da177e4SLinus Torvalds 33061da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 33071da177e4SLinus Torvalds return -ENOTCONN; 33081da177e4SLinus Torvalds 330946a0ae9dSChristoph Hellwig af = sctp_get_af_specific(prim->sspp_addr.ss_family); 331040a01039SWei Yongjun if (!af) 331140a01039SWei Yongjun return -EINVAL; 331240a01039SWei Yongjun 331346a0ae9dSChristoph Hellwig if (!af->addr_valid((union sctp_addr *)&prim->sspp_addr, sp, NULL)) 331440a01039SWei Yongjun return -EADDRNOTAVAIL; 331540a01039SWei Yongjun 331646a0ae9dSChristoph Hellwig if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim->sspp_addr)) 33171da177e4SLinus Torvalds return -EADDRNOTAVAIL; 33181da177e4SLinus Torvalds 33192277c7cdSRichard Haines /* Allow security module to validate address. */ 33202277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR, 332146a0ae9dSChristoph Hellwig (struct sockaddr *)&prim->sspp_addr, 33222277c7cdSRichard Haines af->sockaddr_len); 33232277c7cdSRichard Haines if (err) 33242277c7cdSRichard Haines return err; 33252277c7cdSRichard Haines 33261da177e4SLinus Torvalds /* Create an ASCONF chunk with SET_PRIMARY parameter */ 33271da177e4SLinus Torvalds chunk = sctp_make_asconf_set_prim(asoc, 332846a0ae9dSChristoph Hellwig (union sctp_addr *)&prim->sspp_addr); 33291da177e4SLinus Torvalds if (!chunk) 33301da177e4SLinus Torvalds return -ENOMEM; 33311da177e4SLinus Torvalds 33321da177e4SLinus Torvalds err = sctp_send_asconf(asoc, chunk); 33331da177e4SLinus Torvalds 3334bb33381dSDaniel Borkmann pr_debug("%s: we set peer primary addr primitively\n", __func__); 33351da177e4SLinus Torvalds 33361da177e4SLinus Torvalds return err; 33371da177e4SLinus Torvalds } 33381da177e4SLinus Torvalds 333907e5035cSChristoph Hellwig static int sctp_setsockopt_adaptation_layer(struct sock *sk, 334007e5035cSChristoph Hellwig struct sctp_setadaptation *adapt, 3341b7058842SDavid S. Miller unsigned int optlen) 33421da177e4SLinus Torvalds { 33430f3fffd8SIvan Skytte Jorgensen if (optlen != sizeof(struct sctp_setadaptation)) 33441da177e4SLinus Torvalds return -EINVAL; 33451da177e4SLinus Torvalds 334607e5035cSChristoph Hellwig sctp_sk(sk)->adaptation_ind = adapt->ssb_adaptation_ind; 33471da177e4SLinus Torvalds 33481da177e4SLinus Torvalds return 0; 33491da177e4SLinus Torvalds } 33501da177e4SLinus Torvalds 33516ab792f5SIvan Skytte Jorgensen /* 33526ab792f5SIvan Skytte Jorgensen * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 33536ab792f5SIvan Skytte Jorgensen * 33546ab792f5SIvan Skytte Jorgensen * The context field in the sctp_sndrcvinfo structure is normally only 33556ab792f5SIvan Skytte Jorgensen * used when a failed message is retrieved holding the value that was 33566ab792f5SIvan Skytte Jorgensen * sent down on the actual send call. This option allows the setting of 33576ab792f5SIvan Skytte Jorgensen * a default context on an association basis that will be received on 33586ab792f5SIvan Skytte Jorgensen * reading messages from the peer. This is especially helpful in the 33596ab792f5SIvan Skytte Jorgensen * one-2-many model for an application to keep some reference to an 33606ab792f5SIvan Skytte Jorgensen * internal state machine that is processing messages on the 33616ab792f5SIvan Skytte Jorgensen * association. Note that the setting of this value only effects 33626ab792f5SIvan Skytte Jorgensen * received messages from the peer and does not effect the value that is 33636ab792f5SIvan Skytte Jorgensen * saved with outbound messages. 33646ab792f5SIvan Skytte Jorgensen */ 3365722eca9eSChristoph Hellwig static int sctp_setsockopt_context(struct sock *sk, 3366722eca9eSChristoph Hellwig struct sctp_assoc_value *params, 3367b7058842SDavid S. Miller unsigned int optlen) 33686ab792f5SIvan Skytte Jorgensen { 336949b037acSXin Long struct sctp_sock *sp = sctp_sk(sk); 33706ab792f5SIvan Skytte Jorgensen struct sctp_association *asoc; 33716ab792f5SIvan Skytte Jorgensen 33726ab792f5SIvan Skytte Jorgensen if (optlen != sizeof(struct sctp_assoc_value)) 33736ab792f5SIvan Skytte Jorgensen return -EINVAL; 33746ab792f5SIvan Skytte Jorgensen 3375722eca9eSChristoph Hellwig asoc = sctp_id2assoc(sk, params->assoc_id); 3376722eca9eSChristoph Hellwig if (!asoc && params->assoc_id > SCTP_ALL_ASSOC && 337749b037acSXin Long sctp_style(sk, UDP)) 33786ab792f5SIvan Skytte Jorgensen return -EINVAL; 337949b037acSXin Long 338049b037acSXin Long if (asoc) { 3381722eca9eSChristoph Hellwig asoc->default_rcv_context = params->assoc_value; 338249b037acSXin Long 338349b037acSXin Long return 0; 33846ab792f5SIvan Skytte Jorgensen } 33856ab792f5SIvan Skytte Jorgensen 3386cface2cbSXin Long if (sctp_style(sk, TCP)) 3387722eca9eSChristoph Hellwig params->assoc_id = SCTP_FUTURE_ASSOC; 3388cface2cbSXin Long 3389722eca9eSChristoph Hellwig if (params->assoc_id == SCTP_FUTURE_ASSOC || 3390722eca9eSChristoph Hellwig params->assoc_id == SCTP_ALL_ASSOC) 3391722eca9eSChristoph Hellwig sp->default_rcv_context = params->assoc_value; 339249b037acSXin Long 3393722eca9eSChristoph Hellwig if (params->assoc_id == SCTP_CURRENT_ASSOC || 3394722eca9eSChristoph Hellwig params->assoc_id == SCTP_ALL_ASSOC) 339549b037acSXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) 3396722eca9eSChristoph Hellwig asoc->default_rcv_context = params->assoc_value; 339749b037acSXin Long 33986ab792f5SIvan Skytte Jorgensen return 0; 33996ab792f5SIvan Skytte Jorgensen } 34006ab792f5SIvan Skytte Jorgensen 3401b6e1331fSVlad Yasevich /* 3402b6e1331fSVlad Yasevich * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 3403b6e1331fSVlad Yasevich * 3404b6e1331fSVlad Yasevich * This options will at a minimum specify if the implementation is doing 3405b6e1331fSVlad Yasevich * fragmented interleave. Fragmented interleave, for a one to many 3406b6e1331fSVlad Yasevich * socket, is when subsequent calls to receive a message may return 3407b6e1331fSVlad Yasevich * parts of messages from different associations. Some implementations 3408b6e1331fSVlad Yasevich * may allow you to turn this value on or off. If so, when turned off, 3409b6e1331fSVlad Yasevich * no fragment interleave will occur (which will cause a head of line 3410b6e1331fSVlad Yasevich * blocking amongst multiple associations sharing the same one to many 3411b6e1331fSVlad Yasevich * socket). When this option is turned on, then each receive call may 3412b6e1331fSVlad Yasevich * come from a different association (thus the user must receive data 3413b6e1331fSVlad Yasevich * with the extended calls (e.g. sctp_recvmsg) to keep track of which 3414b6e1331fSVlad Yasevich * association each receive belongs to. 3415b6e1331fSVlad Yasevich * 3416b6e1331fSVlad Yasevich * This option takes a boolean value. A non-zero value indicates that 3417b6e1331fSVlad Yasevich * fragmented interleave is on. A value of zero indicates that 3418b6e1331fSVlad Yasevich * fragmented interleave is off. 3419b6e1331fSVlad Yasevich * 3420b6e1331fSVlad Yasevich * Note that it is important that an implementation that allows this 3421b6e1331fSVlad Yasevich * option to be turned on, have it off by default. Otherwise an unaware 3422b6e1331fSVlad Yasevich * application using the one to many model may become confused and act 3423b6e1331fSVlad Yasevich * incorrectly. 3424b6e1331fSVlad Yasevich */ 34251031cea0SChristoph Hellwig static int sctp_setsockopt_fragment_interleave(struct sock *sk, int *val, 3426b7058842SDavid S. Miller unsigned int optlen) 3427b6e1331fSVlad Yasevich { 3428b6e1331fSVlad Yasevich if (optlen != sizeof(int)) 3429b6e1331fSVlad Yasevich return -EINVAL; 3430b6e1331fSVlad Yasevich 34311031cea0SChristoph Hellwig sctp_sk(sk)->frag_interleave = !!*val; 3432772a5869SXin Long 3433772a5869SXin Long if (!sctp_sk(sk)->frag_interleave) 3434e55f4b8bSXin Long sctp_sk(sk)->ep->intl_enable = 0; 3435b6e1331fSVlad Yasevich 3436b6e1331fSVlad Yasevich return 0; 3437b6e1331fSVlad Yasevich } 3438b6e1331fSVlad Yasevich 3439d49d91d7SVlad Yasevich /* 34408510b937SWei Yongjun * 8.1.21. Set or Get the SCTP Partial Delivery Point 3441d49d91d7SVlad Yasevich * (SCTP_PARTIAL_DELIVERY_POINT) 34428510b937SWei Yongjun * 3443d49d91d7SVlad Yasevich * This option will set or get the SCTP partial delivery point. This 3444d49d91d7SVlad Yasevich * point is the size of a message where the partial delivery API will be 3445d49d91d7SVlad Yasevich * invoked to help free up rwnd space for the peer. Setting this to a 34468510b937SWei Yongjun * lower value will cause partial deliveries to happen more often. The 3447d49d91d7SVlad Yasevich * calls argument is an integer that sets or gets the partial delivery 34488510b937SWei Yongjun * point. Note also that the call will fail if the user attempts to set 34498510b937SWei Yongjun * this value larger than the socket receive buffer size. 34508510b937SWei Yongjun * 34518510b937SWei Yongjun * Note that any single message having a length smaller than or equal to 34528510b937SWei Yongjun * the SCTP partial delivery point will be delivered in one single read 34538510b937SWei Yongjun * call as long as the user provided buffer is large enough to hold the 34548510b937SWei Yongjun * message. 3455d49d91d7SVlad Yasevich */ 3456bb13d647SChristoph Hellwig static int sctp_setsockopt_partial_delivery_point(struct sock *sk, u32 *val, 3457b7058842SDavid S. Miller unsigned int optlen) 3458d49d91d7SVlad Yasevich { 3459d49d91d7SVlad Yasevich if (optlen != sizeof(u32)) 3460d49d91d7SVlad Yasevich return -EINVAL; 3461d49d91d7SVlad Yasevich 34628510b937SWei Yongjun /* Note: We double the receive buffer from what the user sets 34638510b937SWei Yongjun * it to be, also initial rwnd is based on rcvbuf/2. 34648510b937SWei Yongjun */ 3465bb13d647SChristoph Hellwig if (*val > (sk->sk_rcvbuf >> 1)) 34668510b937SWei Yongjun return -EINVAL; 34678510b937SWei Yongjun 3468bb13d647SChristoph Hellwig sctp_sk(sk)->pd_point = *val; 3469d49d91d7SVlad Yasevich 3470d49d91d7SVlad Yasevich return 0; /* is this the right error code? */ 3471d49d91d7SVlad Yasevich } 3472d49d91d7SVlad Yasevich 347370331571SVlad Yasevich /* 347470331571SVlad Yasevich * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 347570331571SVlad Yasevich * 347670331571SVlad Yasevich * This option will allow a user to change the maximum burst of packets 347770331571SVlad Yasevich * that can be emitted by this association. Note that the default value 347870331571SVlad Yasevich * is 4, and some implementations may restrict this setting so that it 347970331571SVlad Yasevich * can only be lowered. 348070331571SVlad Yasevich * 348170331571SVlad Yasevich * NOTE: This text doesn't seem right. Do this on a socket basis with 348270331571SVlad Yasevich * future associations inheriting the socket value. 348370331571SVlad Yasevich */ 348470331571SVlad Yasevich static int sctp_setsockopt_maxburst(struct sock *sk, 3485f5bee0adSChristoph Hellwig struct sctp_assoc_value *params, 3486b7058842SDavid S. Miller unsigned int optlen) 348770331571SVlad Yasevich { 3488e0651a0dSXin Long struct sctp_sock *sp = sctp_sk(sk); 3489219b99a9SNeil Horman struct sctp_association *asoc; 3490f5bee0adSChristoph Hellwig sctp_assoc_t assoc_id; 3491f5bee0adSChristoph Hellwig u32 assoc_value; 349270331571SVlad Yasevich 3493219b99a9SNeil Horman if (optlen == sizeof(int)) { 349494f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 3495f916ec96SNeil Horman "%s (pid %d) " 349694f65193SNeil Horman "Use of int in max_burst socket option deprecated.\n" 3497f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 3498f916ec96SNeil Horman current->comm, task_pid_nr(current)); 3499f5bee0adSChristoph Hellwig assoc_id = SCTP_FUTURE_ASSOC; 3500f5bee0adSChristoph Hellwig assoc_value = *((int *)params); 3501219b99a9SNeil Horman } else if (optlen == sizeof(struct sctp_assoc_value)) { 3502f5bee0adSChristoph Hellwig assoc_id = params->assoc_id; 3503f5bee0adSChristoph Hellwig assoc_value = params->assoc_value; 3504219b99a9SNeil Horman } else 350570331571SVlad Yasevich return -EINVAL; 350670331571SVlad Yasevich 3507f5bee0adSChristoph Hellwig asoc = sctp_id2assoc(sk, assoc_id); 3508f5bee0adSChristoph Hellwig if (!asoc && assoc_id > SCTP_ALL_ASSOC && sctp_style(sk, UDP)) 3509219b99a9SNeil Horman return -EINVAL; 3510e0651a0dSXin Long 3511e0651a0dSXin Long if (asoc) { 3512f5bee0adSChristoph Hellwig asoc->max_burst = assoc_value; 3513e0651a0dSXin Long 3514e0651a0dSXin Long return 0; 3515e0651a0dSXin Long } 3516e0651a0dSXin Long 3517746bc215SXin Long if (sctp_style(sk, TCP)) 3518f5bee0adSChristoph Hellwig assoc_id = SCTP_FUTURE_ASSOC; 3519746bc215SXin Long 3520f5bee0adSChristoph Hellwig if (assoc_id == SCTP_FUTURE_ASSOC || assoc_id == SCTP_ALL_ASSOC) 3521f5bee0adSChristoph Hellwig sp->max_burst = assoc_value; 3522e0651a0dSXin Long 3523f5bee0adSChristoph Hellwig if (assoc_id == SCTP_CURRENT_ASSOC || assoc_id == SCTP_ALL_ASSOC) 3524e0651a0dSXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) 3525f5bee0adSChristoph Hellwig asoc->max_burst = assoc_value; 352670331571SVlad Yasevich 352770331571SVlad Yasevich return 0; 352870331571SVlad Yasevich } 352970331571SVlad Yasevich 353065b07e5dSVlad Yasevich /* 353165b07e5dSVlad Yasevich * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) 353265b07e5dSVlad Yasevich * 353365b07e5dSVlad Yasevich * This set option adds a chunk type that the user is requesting to be 353465b07e5dSVlad Yasevich * received only in an authenticated way. Changes to the list of chunks 353565b07e5dSVlad Yasevich * will only effect future associations on the socket. 353665b07e5dSVlad Yasevich */ 353765b07e5dSVlad Yasevich static int sctp_setsockopt_auth_chunk(struct sock *sk, 353888266d31SChristoph Hellwig struct sctp_authchunk *val, 3539b7058842SDavid S. Miller unsigned int optlen) 354065b07e5dSVlad Yasevich { 3541b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 354265b07e5dSVlad Yasevich 3543b14878ccSVlad Yasevich if (!ep->auth_enable) 35445e739d17SVlad Yasevich return -EACCES; 35455e739d17SVlad Yasevich 354665b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authchunk)) 354765b07e5dSVlad Yasevich return -EINVAL; 354865b07e5dSVlad Yasevich 354988266d31SChristoph Hellwig switch (val->sauth_chunk) { 355065b07e5dSVlad Yasevich case SCTP_CID_INIT: 355165b07e5dSVlad Yasevich case SCTP_CID_INIT_ACK: 355265b07e5dSVlad Yasevich case SCTP_CID_SHUTDOWN_COMPLETE: 355365b07e5dSVlad Yasevich case SCTP_CID_AUTH: 355465b07e5dSVlad Yasevich return -EINVAL; 355565b07e5dSVlad Yasevich } 355665b07e5dSVlad Yasevich 355765b07e5dSVlad Yasevich /* add this chunk id to the endpoint */ 355888266d31SChristoph Hellwig return sctp_auth_ep_add_chunkid(ep, val->sauth_chunk); 355965b07e5dSVlad Yasevich } 356065b07e5dSVlad Yasevich 356165b07e5dSVlad Yasevich /* 356265b07e5dSVlad Yasevich * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) 356365b07e5dSVlad Yasevich * 356465b07e5dSVlad Yasevich * This option gets or sets the list of HMAC algorithms that the local 356565b07e5dSVlad Yasevich * endpoint requires the peer to use. 356665b07e5dSVlad Yasevich */ 356765b07e5dSVlad Yasevich static int sctp_setsockopt_hmac_ident(struct sock *sk, 35683564ef44SChristoph Hellwig struct sctp_hmacalgo *hmacs, 3569b7058842SDavid S. Miller unsigned int optlen) 357065b07e5dSVlad Yasevich { 3571b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 3572d9724055SVlad Yasevich u32 idents; 357365b07e5dSVlad Yasevich 3574b14878ccSVlad Yasevich if (!ep->auth_enable) 35755e739d17SVlad Yasevich return -EACCES; 35765e739d17SVlad Yasevich 357765b07e5dSVlad Yasevich if (optlen < sizeof(struct sctp_hmacalgo)) 357865b07e5dSVlad Yasevich return -EINVAL; 35795960cefaSMarcelo Ricardo Leitner optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) + 35805960cefaSMarcelo Ricardo Leitner SCTP_AUTH_NUM_HMACS * sizeof(u16)); 358165b07e5dSVlad Yasevich 3582d9724055SVlad Yasevich idents = hmacs->shmac_num_idents; 3583d9724055SVlad Yasevich if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || 35843564ef44SChristoph Hellwig (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) 35853564ef44SChristoph Hellwig return -EINVAL; 358665b07e5dSVlad Yasevich 35873564ef44SChristoph Hellwig return sctp_auth_ep_set_hmacs(ep, hmacs); 358865b07e5dSVlad Yasevich } 358965b07e5dSVlad Yasevich 359065b07e5dSVlad Yasevich /* 359165b07e5dSVlad Yasevich * 7.1.20. Set a shared key (SCTP_AUTH_KEY) 359265b07e5dSVlad Yasevich * 359365b07e5dSVlad Yasevich * This option will set a shared secret key which is used to build an 359465b07e5dSVlad Yasevich * association shared key. 359565b07e5dSVlad Yasevich */ 359665b07e5dSVlad Yasevich static int sctp_setsockopt_auth_key(struct sock *sk, 3597534d13d0SChristoph Hellwig struct sctp_authkey *authkey, 3598b7058842SDavid S. Miller unsigned int optlen) 359965b07e5dSVlad Yasevich { 3600b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 360165b07e5dSVlad Yasevich struct sctp_association *asoc; 36027fb3be13SXin Long int ret = -EINVAL; 360365b07e5dSVlad Yasevich 360465b07e5dSVlad Yasevich if (optlen <= sizeof(struct sctp_authkey)) 360565b07e5dSVlad Yasevich return -EINVAL; 36065960cefaSMarcelo Ricardo Leitner /* authkey->sca_keylength is u16, so optlen can't be bigger than 36075960cefaSMarcelo Ricardo Leitner * this. 36085960cefaSMarcelo Ricardo Leitner */ 36097fb3be13SXin Long optlen = min_t(unsigned int, optlen, USHRT_MAX + sizeof(*authkey)); 361065b07e5dSVlad Yasevich 36117fb3be13SXin Long if (authkey->sca_keylength > optlen - sizeof(*authkey)) 361230c2235cSVlad Yasevich goto out; 361330c2235cSVlad Yasevich 361465b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); 36157fb3be13SXin Long if (!asoc && authkey->sca_assoc_id > SCTP_ALL_ASSOC && 36167fb3be13SXin Long sctp_style(sk, UDP)) 36177fb3be13SXin Long goto out; 36187fb3be13SXin Long 36197fb3be13SXin Long if (asoc) { 36207fb3be13SXin Long ret = sctp_auth_set_key(ep, asoc, authkey); 362165b07e5dSVlad Yasevich goto out; 362265b07e5dSVlad Yasevich } 362365b07e5dSVlad Yasevich 36240685d6b7SXin Long if (sctp_style(sk, TCP)) 36250685d6b7SXin Long authkey->sca_assoc_id = SCTP_FUTURE_ASSOC; 36260685d6b7SXin Long 36277fb3be13SXin Long if (authkey->sca_assoc_id == SCTP_FUTURE_ASSOC || 36287fb3be13SXin Long authkey->sca_assoc_id == SCTP_ALL_ASSOC) { 3629b14878ccSVlad Yasevich ret = sctp_auth_set_key(ep, asoc, authkey); 36307fb3be13SXin Long if (ret) 36317fb3be13SXin Long goto out; 36327fb3be13SXin Long } 36337fb3be13SXin Long 36347fb3be13SXin Long ret = 0; 36357fb3be13SXin Long 36367fb3be13SXin Long if (authkey->sca_assoc_id == SCTP_CURRENT_ASSOC || 36377fb3be13SXin Long authkey->sca_assoc_id == SCTP_ALL_ASSOC) { 36387fb3be13SXin Long list_for_each_entry(asoc, &ep->asocs, asocs) { 36397fb3be13SXin Long int res = sctp_auth_set_key(ep, asoc, authkey); 36407fb3be13SXin Long 36417fb3be13SXin Long if (res && !ret) 36427fb3be13SXin Long ret = res; 36437fb3be13SXin Long } 36447fb3be13SXin Long } 36457fb3be13SXin Long 364665b07e5dSVlad Yasevich out: 364789fae01eSChristoph Hellwig memzero_explicit(authkey, optlen); 364865b07e5dSVlad Yasevich return ret; 364965b07e5dSVlad Yasevich } 365065b07e5dSVlad Yasevich 365165b07e5dSVlad Yasevich /* 365265b07e5dSVlad Yasevich * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) 365365b07e5dSVlad Yasevich * 365465b07e5dSVlad Yasevich * This option will get or set the active shared key to be used to build 365565b07e5dSVlad Yasevich * the association shared key. 365665b07e5dSVlad Yasevich */ 365765b07e5dSVlad Yasevich static int sctp_setsockopt_active_key(struct sock *sk, 3658dcab0a7aSChristoph Hellwig struct sctp_authkeyid *val, 3659b7058842SDavid S. Miller unsigned int optlen) 366065b07e5dSVlad Yasevich { 3661b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 366265b07e5dSVlad Yasevich struct sctp_association *asoc; 3663bf9fb6adSXin Long int ret = 0; 366465b07e5dSVlad Yasevich 366565b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authkeyid)) 366665b07e5dSVlad Yasevich return -EINVAL; 366765b07e5dSVlad Yasevich 3668dcab0a7aSChristoph Hellwig asoc = sctp_id2assoc(sk, val->scact_assoc_id); 3669dcab0a7aSChristoph Hellwig if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC && 3670bf9fb6adSXin Long sctp_style(sk, UDP)) 367165b07e5dSVlad Yasevich return -EINVAL; 367265b07e5dSVlad Yasevich 3673bf9fb6adSXin Long if (asoc) 3674dcab0a7aSChristoph Hellwig return sctp_auth_set_active_key(ep, asoc, val->scact_keynumber); 3675bf9fb6adSXin Long 367606b39e85SXin Long if (sctp_style(sk, TCP)) 3677dcab0a7aSChristoph Hellwig val->scact_assoc_id = SCTP_FUTURE_ASSOC; 367806b39e85SXin Long 3679dcab0a7aSChristoph Hellwig if (val->scact_assoc_id == SCTP_FUTURE_ASSOC || 3680dcab0a7aSChristoph Hellwig val->scact_assoc_id == SCTP_ALL_ASSOC) { 3681dcab0a7aSChristoph Hellwig ret = sctp_auth_set_active_key(ep, asoc, val->scact_keynumber); 3682bf9fb6adSXin Long if (ret) 3683bf9fb6adSXin Long return ret; 3684bf9fb6adSXin Long } 3685bf9fb6adSXin Long 3686dcab0a7aSChristoph Hellwig if (val->scact_assoc_id == SCTP_CURRENT_ASSOC || 3687dcab0a7aSChristoph Hellwig val->scact_assoc_id == SCTP_ALL_ASSOC) { 3688bf9fb6adSXin Long list_for_each_entry(asoc, &ep->asocs, asocs) { 3689bf9fb6adSXin Long int res = sctp_auth_set_active_key(ep, asoc, 3690dcab0a7aSChristoph Hellwig val->scact_keynumber); 3691bf9fb6adSXin Long 3692bf9fb6adSXin Long if (res && !ret) 3693bf9fb6adSXin Long ret = res; 3694bf9fb6adSXin Long } 3695bf9fb6adSXin Long } 3696bf9fb6adSXin Long 3697bf9fb6adSXin Long return ret; 369865b07e5dSVlad Yasevich } 369965b07e5dSVlad Yasevich 370065b07e5dSVlad Yasevich /* 370165b07e5dSVlad Yasevich * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY) 370265b07e5dSVlad Yasevich * 370365b07e5dSVlad Yasevich * This set option will delete a shared secret key from use. 370465b07e5dSVlad Yasevich */ 370565b07e5dSVlad Yasevich static int sctp_setsockopt_del_key(struct sock *sk, 370697dc9f2eSChristoph Hellwig struct sctp_authkeyid *val, 3707b7058842SDavid S. Miller unsigned int optlen) 370865b07e5dSVlad Yasevich { 3709b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 371065b07e5dSVlad Yasevich struct sctp_association *asoc; 37113adcc300SXin Long int ret = 0; 371265b07e5dSVlad Yasevich 371365b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authkeyid)) 371465b07e5dSVlad Yasevich return -EINVAL; 371565b07e5dSVlad Yasevich 371697dc9f2eSChristoph Hellwig asoc = sctp_id2assoc(sk, val->scact_assoc_id); 371797dc9f2eSChristoph Hellwig if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC && 37183adcc300SXin Long sctp_style(sk, UDP)) 371965b07e5dSVlad Yasevich return -EINVAL; 372065b07e5dSVlad Yasevich 37213adcc300SXin Long if (asoc) 372297dc9f2eSChristoph Hellwig return sctp_auth_del_key_id(ep, asoc, val->scact_keynumber); 372365b07e5dSVlad Yasevich 3724220675ebSXin Long if (sctp_style(sk, TCP)) 372597dc9f2eSChristoph Hellwig val->scact_assoc_id = SCTP_FUTURE_ASSOC; 3726220675ebSXin Long 372797dc9f2eSChristoph Hellwig if (val->scact_assoc_id == SCTP_FUTURE_ASSOC || 372897dc9f2eSChristoph Hellwig val->scact_assoc_id == SCTP_ALL_ASSOC) { 372997dc9f2eSChristoph Hellwig ret = sctp_auth_del_key_id(ep, asoc, val->scact_keynumber); 37303adcc300SXin Long if (ret) 37313adcc300SXin Long return ret; 37323adcc300SXin Long } 37333adcc300SXin Long 373497dc9f2eSChristoph Hellwig if (val->scact_assoc_id == SCTP_CURRENT_ASSOC || 373597dc9f2eSChristoph Hellwig val->scact_assoc_id == SCTP_ALL_ASSOC) { 37363adcc300SXin Long list_for_each_entry(asoc, &ep->asocs, asocs) { 37373adcc300SXin Long int res = sctp_auth_del_key_id(ep, asoc, 373897dc9f2eSChristoph Hellwig val->scact_keynumber); 37393adcc300SXin Long 37403adcc300SXin Long if (res && !ret) 37413adcc300SXin Long ret = res; 37423adcc300SXin Long } 37433adcc300SXin Long } 37443adcc300SXin Long 37453adcc300SXin Long return ret; 374665b07e5dSVlad Yasevich } 374765b07e5dSVlad Yasevich 37487dc04d71SMichio Honda /* 3749601590ecSXin Long * 8.3.4 Deactivate a Shared Key (SCTP_AUTH_DEACTIVATE_KEY) 3750601590ecSXin Long * 3751601590ecSXin Long * This set option will deactivate a shared secret key. 3752601590ecSXin Long */ 375376b3d0c4SChristoph Hellwig static int sctp_setsockopt_deactivate_key(struct sock *sk, 375476b3d0c4SChristoph Hellwig struct sctp_authkeyid *val, 3755601590ecSXin Long unsigned int optlen) 3756601590ecSXin Long { 3757601590ecSXin Long struct sctp_endpoint *ep = sctp_sk(sk)->ep; 3758601590ecSXin Long struct sctp_association *asoc; 37592af66ff3SXin Long int ret = 0; 3760601590ecSXin Long 3761601590ecSXin Long if (optlen != sizeof(struct sctp_authkeyid)) 3762601590ecSXin Long return -EINVAL; 3763601590ecSXin Long 376476b3d0c4SChristoph Hellwig asoc = sctp_id2assoc(sk, val->scact_assoc_id); 376576b3d0c4SChristoph Hellwig if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC && 37662af66ff3SXin Long sctp_style(sk, UDP)) 3767601590ecSXin Long return -EINVAL; 3768601590ecSXin Long 37692af66ff3SXin Long if (asoc) 377076b3d0c4SChristoph Hellwig return sctp_auth_deact_key_id(ep, asoc, val->scact_keynumber); 37712af66ff3SXin Long 3772200f3a3bSXin Long if (sctp_style(sk, TCP)) 377376b3d0c4SChristoph Hellwig val->scact_assoc_id = SCTP_FUTURE_ASSOC; 3774200f3a3bSXin Long 377576b3d0c4SChristoph Hellwig if (val->scact_assoc_id == SCTP_FUTURE_ASSOC || 377676b3d0c4SChristoph Hellwig val->scact_assoc_id == SCTP_ALL_ASSOC) { 377776b3d0c4SChristoph Hellwig ret = sctp_auth_deact_key_id(ep, asoc, val->scact_keynumber); 37782af66ff3SXin Long if (ret) 37792af66ff3SXin Long return ret; 37802af66ff3SXin Long } 37812af66ff3SXin Long 378276b3d0c4SChristoph Hellwig if (val->scact_assoc_id == SCTP_CURRENT_ASSOC || 378376b3d0c4SChristoph Hellwig val->scact_assoc_id == SCTP_ALL_ASSOC) { 37842af66ff3SXin Long list_for_each_entry(asoc, &ep->asocs, asocs) { 37852af66ff3SXin Long int res = sctp_auth_deact_key_id(ep, asoc, 378676b3d0c4SChristoph Hellwig val->scact_keynumber); 37872af66ff3SXin Long 37882af66ff3SXin Long if (res && !ret) 37892af66ff3SXin Long ret = res; 37902af66ff3SXin Long } 37912af66ff3SXin Long } 37922af66ff3SXin Long 37932af66ff3SXin Long return ret; 3794601590ecSXin Long } 3795601590ecSXin Long 3796601590ecSXin Long /* 37977dc04d71SMichio Honda * 8.1.23 SCTP_AUTO_ASCONF 37987dc04d71SMichio Honda * 37997dc04d71SMichio Honda * This option will enable or disable the use of the automatic generation of 38007dc04d71SMichio Honda * ASCONF chunks to add and delete addresses to an existing association. Note 38017dc04d71SMichio Honda * that this option has two caveats namely: a) it only affects sockets that 38027dc04d71SMichio Honda * are bound to all addresses available to the SCTP stack, and b) the system 38037dc04d71SMichio Honda * administrator may have an overriding control that turns the ASCONF feature 38047dc04d71SMichio Honda * off no matter what setting the socket option may have. 38057dc04d71SMichio Honda * This option expects an integer boolean flag, where a non-zero value turns on 38067dc04d71SMichio Honda * the option, and a zero value turns off the option. 38077dc04d71SMichio Honda * Note. In this implementation, socket operation overrides default parameter 38087dc04d71SMichio Honda * being set by sysctl as well as FreeBSD implementation 38097dc04d71SMichio Honda */ 3810c9abc2c1SChristoph Hellwig static int sctp_setsockopt_auto_asconf(struct sock *sk, int *val, 38117dc04d71SMichio Honda unsigned int optlen) 38127dc04d71SMichio Honda { 38137dc04d71SMichio Honda struct sctp_sock *sp = sctp_sk(sk); 38147dc04d71SMichio Honda 38157dc04d71SMichio Honda if (optlen < sizeof(int)) 38167dc04d71SMichio Honda return -EINVAL; 3817c9abc2c1SChristoph Hellwig if (!sctp_is_ep_boundall(sk) && *val) 38187dc04d71SMichio Honda return -EINVAL; 3819c9abc2c1SChristoph Hellwig if ((*val && sp->do_auto_asconf) || (!*val && !sp->do_auto_asconf)) 38207dc04d71SMichio Honda return 0; 38217dc04d71SMichio Honda 38222d45a02dSMarcelo Ricardo Leitner spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock); 3823c9abc2c1SChristoph Hellwig if (*val == 0 && sp->do_auto_asconf) { 38247dc04d71SMichio Honda list_del(&sp->auto_asconf_list); 38257dc04d71SMichio Honda sp->do_auto_asconf = 0; 3826c9abc2c1SChristoph Hellwig } else if (*val && !sp->do_auto_asconf) { 38277dc04d71SMichio Honda list_add_tail(&sp->auto_asconf_list, 38284db67e80SEric W. Biederman &sock_net(sk)->sctp.auto_asconf_splist); 38297dc04d71SMichio Honda sp->do_auto_asconf = 1; 38307dc04d71SMichio Honda } 38312d45a02dSMarcelo Ricardo Leitner spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock); 38327dc04d71SMichio Honda return 0; 38337dc04d71SMichio Honda } 38347dc04d71SMichio Honda 38355aa93bcfSNeil Horman /* 38365aa93bcfSNeil Horman * SCTP_PEER_ADDR_THLDS 38375aa93bcfSNeil Horman * 38385aa93bcfSNeil Horman * This option allows us to alter the partially failed threshold for one or all 38395aa93bcfSNeil Horman * transports in an association. See Section 6.1 of: 38405aa93bcfSNeil Horman * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 38415aa93bcfSNeil Horman */ 38425aa93bcfSNeil Horman static int sctp_setsockopt_paddr_thresholds(struct sock *sk, 3843b0ac3bb8SChristoph Hellwig struct sctp_paddrthlds_v2 *val, 3844d467ac0aSXin Long unsigned int optlen, bool v2) 38455aa93bcfSNeil Horman { 38465aa93bcfSNeil Horman struct sctp_transport *trans; 38475aa93bcfSNeil Horman struct sctp_association *asoc; 3848d467ac0aSXin Long int len; 38495aa93bcfSNeil Horman 3850b0ac3bb8SChristoph Hellwig len = v2 ? sizeof(*val) : sizeof(struct sctp_paddrthlds); 3851d467ac0aSXin Long if (optlen < len) 38525aa93bcfSNeil Horman return -EINVAL; 38535aa93bcfSNeil Horman 3854b0ac3bb8SChristoph Hellwig if (v2 && val->spt_pathpfthld > val->spt_pathcpthld) 3855d467ac0aSXin Long return -EINVAL; 3856d467ac0aSXin Long 3857b0ac3bb8SChristoph Hellwig if (!sctp_is_any(sk, (const union sctp_addr *)&val->spt_address)) { 3858b0ac3bb8SChristoph Hellwig trans = sctp_addr_id2transport(sk, &val->spt_address, 3859b0ac3bb8SChristoph Hellwig val->spt_assoc_id); 38608add543eSXin Long if (!trans) 38615aa93bcfSNeil Horman return -ENOENT; 38628add543eSXin Long 3863b0ac3bb8SChristoph Hellwig if (val->spt_pathmaxrxt) 3864b0ac3bb8SChristoph Hellwig trans->pathmaxrxt = val->spt_pathmaxrxt; 3865d467ac0aSXin Long if (v2) 3866b0ac3bb8SChristoph Hellwig trans->ps_retrans = val->spt_pathcpthld; 3867b0ac3bb8SChristoph Hellwig trans->pf_retrans = val->spt_pathpfthld; 38688add543eSXin Long 38698add543eSXin Long return 0; 38708add543eSXin Long } 38718add543eSXin Long 3872b0ac3bb8SChristoph Hellwig asoc = sctp_id2assoc(sk, val->spt_assoc_id); 3873b0ac3bb8SChristoph Hellwig if (!asoc && val->spt_assoc_id != SCTP_FUTURE_ASSOC && 38748add543eSXin Long sctp_style(sk, UDP)) 38758add543eSXin Long return -EINVAL; 38768add543eSXin Long 38778add543eSXin Long if (asoc) { 38785aa93bcfSNeil Horman list_for_each_entry(trans, &asoc->peer.transport_addr_list, 38795aa93bcfSNeil Horman transports) { 3880b0ac3bb8SChristoph Hellwig if (val->spt_pathmaxrxt) 3881b0ac3bb8SChristoph Hellwig trans->pathmaxrxt = val->spt_pathmaxrxt; 3882d467ac0aSXin Long if (v2) 3883b0ac3bb8SChristoph Hellwig trans->ps_retrans = val->spt_pathcpthld; 3884b0ac3bb8SChristoph Hellwig trans->pf_retrans = val->spt_pathpfthld; 38855aa93bcfSNeil Horman } 38865aa93bcfSNeil Horman 3887b0ac3bb8SChristoph Hellwig if (val->spt_pathmaxrxt) 3888b0ac3bb8SChristoph Hellwig asoc->pathmaxrxt = val->spt_pathmaxrxt; 3889d467ac0aSXin Long if (v2) 3890b0ac3bb8SChristoph Hellwig asoc->ps_retrans = val->spt_pathcpthld; 3891b0ac3bb8SChristoph Hellwig asoc->pf_retrans = val->spt_pathpfthld; 38925aa93bcfSNeil Horman } else { 38938add543eSXin Long struct sctp_sock *sp = sctp_sk(sk); 38945aa93bcfSNeil Horman 3895b0ac3bb8SChristoph Hellwig if (val->spt_pathmaxrxt) 3896b0ac3bb8SChristoph Hellwig sp->pathmaxrxt = val->spt_pathmaxrxt; 3897d467ac0aSXin Long if (v2) 3898b0ac3bb8SChristoph Hellwig sp->ps_retrans = val->spt_pathcpthld; 3899b0ac3bb8SChristoph Hellwig sp->pf_retrans = val->spt_pathpfthld; 39005aa93bcfSNeil Horman } 39015aa93bcfSNeil Horman 39025aa93bcfSNeil Horman return 0; 39035aa93bcfSNeil Horman } 39045aa93bcfSNeil Horman 3905a98af7c8SChristoph Hellwig static int sctp_setsockopt_recvrcvinfo(struct sock *sk, int *val, 39060d3a421dSGeir Ola Vaagland unsigned int optlen) 39070d3a421dSGeir Ola Vaagland { 39080d3a421dSGeir Ola Vaagland if (optlen < sizeof(int)) 39090d3a421dSGeir Ola Vaagland return -EINVAL; 39100d3a421dSGeir Ola Vaagland 3911a98af7c8SChristoph Hellwig sctp_sk(sk)->recvrcvinfo = (*val == 0) ? 0 : 1; 39120d3a421dSGeir Ola Vaagland 39130d3a421dSGeir Ola Vaagland return 0; 39140d3a421dSGeir Ola Vaagland } 39150d3a421dSGeir Ola Vaagland 3916cfa6fde2SChristoph Hellwig static int sctp_setsockopt_recvnxtinfo(struct sock *sk, int *val, 39172347c80fSGeir Ola Vaagland unsigned int optlen) 39182347c80fSGeir Ola Vaagland { 39192347c80fSGeir Ola Vaagland if (optlen < sizeof(int)) 39202347c80fSGeir Ola Vaagland return -EINVAL; 39212347c80fSGeir Ola Vaagland 3922cfa6fde2SChristoph Hellwig sctp_sk(sk)->recvnxtinfo = (*val == 0) ? 0 : 1; 39232347c80fSGeir Ola Vaagland 39242347c80fSGeir Ola Vaagland return 0; 39252347c80fSGeir Ola Vaagland } 39262347c80fSGeir Ola Vaagland 392728aa4c26SXin Long static int sctp_setsockopt_pr_supported(struct sock *sk, 39284a97fa4fSChristoph Hellwig struct sctp_assoc_value *params, 392928aa4c26SXin Long unsigned int optlen) 393028aa4c26SXin Long { 3931fb195605SXin Long struct sctp_association *asoc; 393228aa4c26SXin Long 39334a97fa4fSChristoph Hellwig if (optlen != sizeof(*params)) 3934cc3ccf26SXin Long return -EINVAL; 393528aa4c26SXin Long 39364a97fa4fSChristoph Hellwig asoc = sctp_id2assoc(sk, params->assoc_id); 39374a97fa4fSChristoph Hellwig if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC && 3938fb195605SXin Long sctp_style(sk, UDP)) 3939fb195605SXin Long return -EINVAL; 3940fb195605SXin Long 39414a97fa4fSChristoph Hellwig sctp_sk(sk)->ep->prsctp_enable = !!params->assoc_value; 394228aa4c26SXin Long 3943cc3ccf26SXin Long return 0; 394428aa4c26SXin Long } 394528aa4c26SXin Long 3946f959fb44SXin Long static int sctp_setsockopt_default_prinfo(struct sock *sk, 3947ac37435bSChristoph Hellwig struct sctp_default_prinfo *info, 3948f959fb44SXin Long unsigned int optlen) 3949f959fb44SXin Long { 39503a583059SXin Long struct sctp_sock *sp = sctp_sk(sk); 3951f959fb44SXin Long struct sctp_association *asoc; 3952f959fb44SXin Long int retval = -EINVAL; 3953f959fb44SXin Long 3954ac37435bSChristoph Hellwig if (optlen != sizeof(*info)) 3955f959fb44SXin Long goto out; 3956f959fb44SXin Long 3957ac37435bSChristoph Hellwig if (info->pr_policy & ~SCTP_PR_SCTP_MASK) 3958f959fb44SXin Long goto out; 3959f959fb44SXin Long 3960ac37435bSChristoph Hellwig if (info->pr_policy == SCTP_PR_SCTP_NONE) 3961ac37435bSChristoph Hellwig info->pr_value = 0; 3962f959fb44SXin Long 3963ac37435bSChristoph Hellwig asoc = sctp_id2assoc(sk, info->pr_assoc_id); 3964ac37435bSChristoph Hellwig if (!asoc && info->pr_assoc_id > SCTP_ALL_ASSOC && 39653a583059SXin Long sctp_style(sk, UDP)) 39663a583059SXin Long goto out; 39673a583059SXin Long 39683a583059SXin Long retval = 0; 39693a583059SXin Long 3970f959fb44SXin Long if (asoc) { 3971ac37435bSChristoph Hellwig SCTP_PR_SET_POLICY(asoc->default_flags, info->pr_policy); 3972ac37435bSChristoph Hellwig asoc->default_timetolive = info->pr_value; 3973f959fb44SXin Long goto out; 3974f959fb44SXin Long } 3975f959fb44SXin Long 3976cbb45c6cSXin Long if (sctp_style(sk, TCP)) 3977ac37435bSChristoph Hellwig info->pr_assoc_id = SCTP_FUTURE_ASSOC; 3978cbb45c6cSXin Long 3979ac37435bSChristoph Hellwig if (info->pr_assoc_id == SCTP_FUTURE_ASSOC || 3980ac37435bSChristoph Hellwig info->pr_assoc_id == SCTP_ALL_ASSOC) { 3981ac37435bSChristoph Hellwig SCTP_PR_SET_POLICY(sp->default_flags, info->pr_policy); 3982ac37435bSChristoph Hellwig sp->default_timetolive = info->pr_value; 39833a583059SXin Long } 39843a583059SXin Long 3985ac37435bSChristoph Hellwig if (info->pr_assoc_id == SCTP_CURRENT_ASSOC || 3986ac37435bSChristoph Hellwig info->pr_assoc_id == SCTP_ALL_ASSOC) { 39873a583059SXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 3988ac37435bSChristoph Hellwig SCTP_PR_SET_POLICY(asoc->default_flags, 3989ac37435bSChristoph Hellwig info->pr_policy); 3990ac37435bSChristoph Hellwig asoc->default_timetolive = info->pr_value; 39913a583059SXin Long } 39923a583059SXin Long } 3993f959fb44SXin Long 3994f959fb44SXin Long out: 3995f959fb44SXin Long return retval; 3996f959fb44SXin Long } 3997f959fb44SXin Long 3998c0d8bab6SXin Long static int sctp_setsockopt_reconfig_supported(struct sock *sk, 39993f49f720SChristoph Hellwig struct sctp_assoc_value *params, 4000c0d8bab6SXin Long unsigned int optlen) 4001c0d8bab6SXin Long { 4002c0d8bab6SXin Long struct sctp_association *asoc; 4003c0d8bab6SXin Long int retval = -EINVAL; 4004c0d8bab6SXin Long 40053f49f720SChristoph Hellwig if (optlen != sizeof(*params)) 4006c0d8bab6SXin Long goto out; 4007c0d8bab6SXin Long 40083f49f720SChristoph Hellwig asoc = sctp_id2assoc(sk, params->assoc_id); 40093f49f720SChristoph Hellwig if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC && 4010acce7f3bSXin Long sctp_style(sk, UDP)) 4011c0d8bab6SXin Long goto out; 4012acce7f3bSXin Long 40133f49f720SChristoph Hellwig sctp_sk(sk)->ep->reconf_enable = !!params->assoc_value; 4014c0d8bab6SXin Long 4015c0d8bab6SXin Long retval = 0; 4016c0d8bab6SXin Long 4017c0d8bab6SXin Long out: 4018c0d8bab6SXin Long return retval; 4019c0d8bab6SXin Long } 4020c0d8bab6SXin Long 40219fb657aeSXin Long static int sctp_setsockopt_enable_strreset(struct sock *sk, 4022356dc6f1SChristoph Hellwig struct sctp_assoc_value *params, 40239fb657aeSXin Long unsigned int optlen) 40249fb657aeSXin Long { 402599a62135SXin Long struct sctp_endpoint *ep = sctp_sk(sk)->ep; 40269fb657aeSXin Long struct sctp_association *asoc; 40279fb657aeSXin Long int retval = -EINVAL; 40289fb657aeSXin Long 4029356dc6f1SChristoph Hellwig if (optlen != sizeof(*params)) 40309fb657aeSXin Long goto out; 40319fb657aeSXin Long 4032356dc6f1SChristoph Hellwig if (params->assoc_value & (~SCTP_ENABLE_STRRESET_MASK)) 40339fb657aeSXin Long goto out; 40349fb657aeSXin Long 4035356dc6f1SChristoph Hellwig asoc = sctp_id2assoc(sk, params->assoc_id); 4036356dc6f1SChristoph Hellwig if (!asoc && params->assoc_id > SCTP_ALL_ASSOC && 403799a62135SXin Long sctp_style(sk, UDP)) 403899a62135SXin Long goto out; 403999a62135SXin Long 404099a62135SXin Long retval = 0; 404199a62135SXin Long 40429fb657aeSXin Long if (asoc) { 4043356dc6f1SChristoph Hellwig asoc->strreset_enable = params->assoc_value; 40449fb657aeSXin Long goto out; 40459fb657aeSXin Long } 40469fb657aeSXin Long 40479430ff99SXin Long if (sctp_style(sk, TCP)) 4048356dc6f1SChristoph Hellwig params->assoc_id = SCTP_FUTURE_ASSOC; 40499430ff99SXin Long 4050356dc6f1SChristoph Hellwig if (params->assoc_id == SCTP_FUTURE_ASSOC || 4051356dc6f1SChristoph Hellwig params->assoc_id == SCTP_ALL_ASSOC) 4052356dc6f1SChristoph Hellwig ep->strreset_enable = params->assoc_value; 405399a62135SXin Long 4054356dc6f1SChristoph Hellwig if (params->assoc_id == SCTP_CURRENT_ASSOC || 4055356dc6f1SChristoph Hellwig params->assoc_id == SCTP_ALL_ASSOC) 405699a62135SXin Long list_for_each_entry(asoc, &ep->asocs, asocs) 4057356dc6f1SChristoph Hellwig asoc->strreset_enable = params->assoc_value; 40589fb657aeSXin Long 40599fb657aeSXin Long out: 40609fb657aeSXin Long return retval; 40619fb657aeSXin Long } 40629fb657aeSXin Long 40637f9d68acSXin Long static int sctp_setsockopt_reset_streams(struct sock *sk, 4064d4922434SChristoph Hellwig struct sctp_reset_streams *params, 40657f9d68acSXin Long unsigned int optlen) 40667f9d68acSXin Long { 40677f9d68acSXin Long struct sctp_association *asoc; 40687f9d68acSXin Long 40692342b8d9SXin Long if (optlen < sizeof(*params)) 40707f9d68acSXin Long return -EINVAL; 40715960cefaSMarcelo Ricardo Leitner /* srs_number_streams is u16, so optlen can't be bigger than this. */ 40725960cefaSMarcelo Ricardo Leitner optlen = min_t(unsigned int, optlen, USHRT_MAX + 40735960cefaSMarcelo Ricardo Leitner sizeof(__u16) * sizeof(*params)); 40747f9d68acSXin Long 40752342b8d9SXin Long if (params->srs_number_streams * sizeof(__u16) > 40762342b8d9SXin Long optlen - sizeof(*params)) 4077d4922434SChristoph Hellwig return -EINVAL; 40782342b8d9SXin Long 40797f9d68acSXin Long asoc = sctp_id2assoc(sk, params->srs_assoc_id); 40807f9d68acSXin Long if (!asoc) 4081d4922434SChristoph Hellwig return -EINVAL; 40827f9d68acSXin Long 4083d4922434SChristoph Hellwig return sctp_send_reset_streams(asoc, params); 40847f9d68acSXin Long } 40857f9d68acSXin Long 4086b97d20ceSChristoph Hellwig static int sctp_setsockopt_reset_assoc(struct sock *sk, sctp_assoc_t *associd, 4087a92ce1a4SXin Long unsigned int optlen) 4088a92ce1a4SXin Long { 4089a92ce1a4SXin Long struct sctp_association *asoc; 4090a92ce1a4SXin Long 4091b97d20ceSChristoph Hellwig if (optlen != sizeof(*associd)) 4092b97d20ceSChristoph Hellwig return -EINVAL; 4093a92ce1a4SXin Long 4094b97d20ceSChristoph Hellwig asoc = sctp_id2assoc(sk, *associd); 4095a92ce1a4SXin Long if (!asoc) 4096b97d20ceSChristoph Hellwig return -EINVAL; 4097a92ce1a4SXin Long 4098b97d20ceSChristoph Hellwig return sctp_send_reset_assoc(asoc); 4099a92ce1a4SXin Long } 4100a92ce1a4SXin Long 4101242bd2d5SXin Long static int sctp_setsockopt_add_streams(struct sock *sk, 41024d6fb260SChristoph Hellwig struct sctp_add_streams *params, 4103242bd2d5SXin Long unsigned int optlen) 4104242bd2d5SXin Long { 4105242bd2d5SXin Long struct sctp_association *asoc; 4106242bd2d5SXin Long 41074d6fb260SChristoph Hellwig if (optlen != sizeof(*params)) 41084d6fb260SChristoph Hellwig return -EINVAL; 4109242bd2d5SXin Long 41104d6fb260SChristoph Hellwig asoc = sctp_id2assoc(sk, params->sas_assoc_id); 4111242bd2d5SXin Long if (!asoc) 41124d6fb260SChristoph Hellwig return -EINVAL; 4113242bd2d5SXin Long 41144d6fb260SChristoph Hellwig return sctp_send_add_streams(asoc, params); 4115242bd2d5SXin Long } 4116242bd2d5SXin Long 411713aa8770SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler(struct sock *sk, 41184d2fba3aSChristoph Hellwig struct sctp_assoc_value *params, 411913aa8770SMarcelo Ricardo Leitner unsigned int optlen) 412013aa8770SMarcelo Ricardo Leitner { 41217efba10dSXin Long struct sctp_sock *sp = sctp_sk(sk); 412213aa8770SMarcelo Ricardo Leitner struct sctp_association *asoc; 41237efba10dSXin Long int retval = 0; 412413aa8770SMarcelo Ricardo Leitner 41254d2fba3aSChristoph Hellwig if (optlen < sizeof(*params)) 41267efba10dSXin Long return -EINVAL; 412713aa8770SMarcelo Ricardo Leitner 41284d2fba3aSChristoph Hellwig if (params->assoc_value > SCTP_SS_MAX) 41297efba10dSXin Long return -EINVAL; 413013aa8770SMarcelo Ricardo Leitner 41314d2fba3aSChristoph Hellwig asoc = sctp_id2assoc(sk, params->assoc_id); 41324d2fba3aSChristoph Hellwig if (!asoc && params->assoc_id > SCTP_ALL_ASSOC && 41337efba10dSXin Long sctp_style(sk, UDP)) 41347efba10dSXin Long return -EINVAL; 413513aa8770SMarcelo Ricardo Leitner 41367efba10dSXin Long if (asoc) 41374d2fba3aSChristoph Hellwig return sctp_sched_set_sched(asoc, params->assoc_value); 413813aa8770SMarcelo Ricardo Leitner 4139b59c19d9SXin Long if (sctp_style(sk, TCP)) 41404d2fba3aSChristoph Hellwig params->assoc_id = SCTP_FUTURE_ASSOC; 4141b59c19d9SXin Long 41424d2fba3aSChristoph Hellwig if (params->assoc_id == SCTP_FUTURE_ASSOC || 41434d2fba3aSChristoph Hellwig params->assoc_id == SCTP_ALL_ASSOC) 41444d2fba3aSChristoph Hellwig sp->default_ss = params->assoc_value; 41457efba10dSXin Long 41464d2fba3aSChristoph Hellwig if (params->assoc_id == SCTP_CURRENT_ASSOC || 41474d2fba3aSChristoph Hellwig params->assoc_id == SCTP_ALL_ASSOC) { 41487efba10dSXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 41497efba10dSXin Long int ret = sctp_sched_set_sched(asoc, 41504d2fba3aSChristoph Hellwig params->assoc_value); 41517efba10dSXin Long 41527efba10dSXin Long if (ret && !retval) 41537efba10dSXin Long retval = ret; 41547efba10dSXin Long } 41557efba10dSXin Long } 41567efba10dSXin Long 415713aa8770SMarcelo Ricardo Leitner return retval; 415813aa8770SMarcelo Ricardo Leitner } 415913aa8770SMarcelo Ricardo Leitner 41600ccdf3c7SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler_value(struct sock *sk, 4161d636e7f3SChristoph Hellwig struct sctp_stream_value *params, 41620ccdf3c7SMarcelo Ricardo Leitner unsigned int optlen) 41630ccdf3c7SMarcelo Ricardo Leitner { 4164e7f28248SXin Long struct sctp_association *asoc; 41650ccdf3c7SMarcelo Ricardo Leitner int retval = -EINVAL; 41660ccdf3c7SMarcelo Ricardo Leitner 4167d636e7f3SChristoph Hellwig if (optlen < sizeof(*params)) 41680ccdf3c7SMarcelo Ricardo Leitner goto out; 41690ccdf3c7SMarcelo Ricardo Leitner 4170d636e7f3SChristoph Hellwig asoc = sctp_id2assoc(sk, params->assoc_id); 4171d636e7f3SChristoph Hellwig if (!asoc && params->assoc_id != SCTP_CURRENT_ASSOC && 4172e7f28248SXin Long sctp_style(sk, UDP)) 41730ccdf3c7SMarcelo Ricardo Leitner goto out; 41740ccdf3c7SMarcelo Ricardo Leitner 4175e7f28248SXin Long if (asoc) { 4176d636e7f3SChristoph Hellwig retval = sctp_sched_set_value(asoc, params->stream_id, 4177d636e7f3SChristoph Hellwig params->stream_value, GFP_KERNEL); 4178e7f28248SXin Long goto out; 4179e7f28248SXin Long } 4180e7f28248SXin Long 4181e7f28248SXin Long retval = 0; 4182e7f28248SXin Long 4183e7f28248SXin Long list_for_each_entry(asoc, &sctp_sk(sk)->ep->asocs, asocs) { 4184d636e7f3SChristoph Hellwig int ret = sctp_sched_set_value(asoc, params->stream_id, 4185d636e7f3SChristoph Hellwig params->stream_value, 4186d636e7f3SChristoph Hellwig GFP_KERNEL); 4187e7f28248SXin Long if (ret && !retval) /* try to return the 1st error. */ 4188e7f28248SXin Long retval = ret; 4189e7f28248SXin Long } 41900ccdf3c7SMarcelo Ricardo Leitner 41910ccdf3c7SMarcelo Ricardo Leitner out: 41920ccdf3c7SMarcelo Ricardo Leitner return retval; 41930ccdf3c7SMarcelo Ricardo Leitner } 41940ccdf3c7SMarcelo Ricardo Leitner 4195772a5869SXin Long static int sctp_setsockopt_interleaving_supported(struct sock *sk, 4196*5b8d3b24SChristoph Hellwig struct sctp_assoc_value *p, 4197772a5869SXin Long unsigned int optlen) 4198772a5869SXin Long { 4199772a5869SXin Long struct sctp_sock *sp = sctp_sk(sk); 42002e7709d1SXin Long struct sctp_association *asoc; 4201772a5869SXin Long 4202*5b8d3b24SChristoph Hellwig if (optlen < sizeof(*p)) 4203*5b8d3b24SChristoph Hellwig return -EINVAL; 4204772a5869SXin Long 4205*5b8d3b24SChristoph Hellwig asoc = sctp_id2assoc(sk, p->assoc_id); 4206*5b8d3b24SChristoph Hellwig if (!asoc && p->assoc_id != SCTP_FUTURE_ASSOC && sctp_style(sk, UDP)) 4207*5b8d3b24SChristoph Hellwig return -EINVAL; 4208772a5869SXin Long 42092e7709d1SXin Long if (!sock_net(sk)->sctp.intl_enable || !sp->frag_interleave) { 4210*5b8d3b24SChristoph Hellwig return -EPERM; 4211772a5869SXin Long } 4212772a5869SXin Long 4213*5b8d3b24SChristoph Hellwig sp->ep->intl_enable = !!p->assoc_value; 4214*5b8d3b24SChristoph Hellwig return 0; 4215772a5869SXin Long } 4216772a5869SXin Long 4217b0e9a2feSXin Long static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval, 4218b0e9a2feSXin Long unsigned int optlen) 4219b0e9a2feSXin Long { 4220b0e9a2feSXin Long int val; 4221b0e9a2feSXin Long 4222b0e9a2feSXin Long if (!sctp_style(sk, TCP)) 4223b0e9a2feSXin Long return -EOPNOTSUPP; 4224b0e9a2feSXin Long 4225b0e9a2feSXin Long if (sctp_sk(sk)->ep->base.bind_addr.port) 4226b0e9a2feSXin Long return -EFAULT; 4227b0e9a2feSXin Long 4228b0e9a2feSXin Long if (optlen < sizeof(int)) 4229b0e9a2feSXin Long return -EINVAL; 4230b0e9a2feSXin Long 4231b0e9a2feSXin Long if (get_user(val, (int __user *)optval)) 4232b0e9a2feSXin Long return -EFAULT; 4233b0e9a2feSXin Long 4234b0e9a2feSXin Long sctp_sk(sk)->reuse = !!val; 4235b0e9a2feSXin Long 4236b0e9a2feSXin Long return 0; 4237b0e9a2feSXin Long } 4238b0e9a2feSXin Long 4239d251f05eSXin Long static int sctp_assoc_ulpevent_type_set(struct sctp_event *param, 4240d251f05eSXin Long struct sctp_association *asoc) 4241480ba9c1SXin Long { 4242480ba9c1SXin Long struct sctp_ulpevent *event; 4243480ba9c1SXin Long 4244d251f05eSXin Long sctp_ulpevent_type_set(&asoc->subscribe, param->se_type, param->se_on); 4245480ba9c1SXin Long 4246d251f05eSXin Long if (param->se_type == SCTP_SENDER_DRY_EVENT && param->se_on) { 4247480ba9c1SXin Long if (sctp_outq_is_empty(&asoc->outqueue)) { 4248480ba9c1SXin Long event = sctp_ulpevent_make_sender_dry_event(asoc, 4249480ba9c1SXin Long GFP_USER | __GFP_NOWARN); 4250d251f05eSXin Long if (!event) 4251d251f05eSXin Long return -ENOMEM; 4252480ba9c1SXin Long 4253480ba9c1SXin Long asoc->stream.si->enqueue_event(&asoc->ulpq, event); 4254480ba9c1SXin Long } 4255480ba9c1SXin Long } 4256480ba9c1SXin Long 4257d251f05eSXin Long return 0; 4258d251f05eSXin Long } 4259d251f05eSXin Long 4260d251f05eSXin Long static int sctp_setsockopt_event(struct sock *sk, char __user *optval, 4261d251f05eSXin Long unsigned int optlen) 4262d251f05eSXin Long { 4263d251f05eSXin Long struct sctp_sock *sp = sctp_sk(sk); 4264d251f05eSXin Long struct sctp_association *asoc; 4265d251f05eSXin Long struct sctp_event param; 4266d251f05eSXin Long int retval = 0; 4267d251f05eSXin Long 4268d251f05eSXin Long if (optlen < sizeof(param)) 4269d251f05eSXin Long return -EINVAL; 4270d251f05eSXin Long 4271d251f05eSXin Long optlen = sizeof(param); 4272d251f05eSXin Long if (copy_from_user(¶m, optval, optlen)) 4273d251f05eSXin Long return -EFAULT; 4274d251f05eSXin Long 4275d251f05eSXin Long if (param.se_type < SCTP_SN_TYPE_BASE || 4276d251f05eSXin Long param.se_type > SCTP_SN_TYPE_MAX) 4277d251f05eSXin Long return -EINVAL; 4278d251f05eSXin Long 4279d251f05eSXin Long asoc = sctp_id2assoc(sk, param.se_assoc_id); 4280d251f05eSXin Long if (!asoc && param.se_assoc_id > SCTP_ALL_ASSOC && 4281d251f05eSXin Long sctp_style(sk, UDP)) 4282d251f05eSXin Long return -EINVAL; 4283d251f05eSXin Long 4284d251f05eSXin Long if (asoc) 4285d251f05eSXin Long return sctp_assoc_ulpevent_type_set(¶m, asoc); 4286d251f05eSXin Long 428799518619SXin Long if (sctp_style(sk, TCP)) 428899518619SXin Long param.se_assoc_id = SCTP_FUTURE_ASSOC; 428999518619SXin Long 4290d251f05eSXin Long if (param.se_assoc_id == SCTP_FUTURE_ASSOC || 4291d251f05eSXin Long param.se_assoc_id == SCTP_ALL_ASSOC) 4292d251f05eSXin Long sctp_ulpevent_type_set(&sp->subscribe, 4293d251f05eSXin Long param.se_type, param.se_on); 4294d251f05eSXin Long 4295d251f05eSXin Long if (param.se_assoc_id == SCTP_CURRENT_ASSOC || 4296d251f05eSXin Long param.se_assoc_id == SCTP_ALL_ASSOC) { 4297d251f05eSXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 4298d251f05eSXin Long int ret = sctp_assoc_ulpevent_type_set(¶m, asoc); 4299d251f05eSXin Long 4300d251f05eSXin Long if (ret && !retval) 4301d251f05eSXin Long retval = ret; 4302d251f05eSXin Long } 4303d251f05eSXin Long } 4304d251f05eSXin Long 4305480ba9c1SXin Long return retval; 4306480ba9c1SXin Long } 4307480ba9c1SXin Long 4308df2c71ffSXin Long static int sctp_setsockopt_asconf_supported(struct sock *sk, 4309df2c71ffSXin Long char __user *optval, 4310df2c71ffSXin Long unsigned int optlen) 4311df2c71ffSXin Long { 4312df2c71ffSXin Long struct sctp_assoc_value params; 4313df2c71ffSXin Long struct sctp_association *asoc; 4314df2c71ffSXin Long struct sctp_endpoint *ep; 4315df2c71ffSXin Long int retval = -EINVAL; 4316df2c71ffSXin Long 4317df2c71ffSXin Long if (optlen != sizeof(params)) 4318df2c71ffSXin Long goto out; 4319df2c71ffSXin Long 4320df2c71ffSXin Long if (copy_from_user(¶ms, optval, optlen)) { 4321df2c71ffSXin Long retval = -EFAULT; 4322df2c71ffSXin Long goto out; 4323df2c71ffSXin Long } 4324df2c71ffSXin Long 4325df2c71ffSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 4326df2c71ffSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 4327df2c71ffSXin Long sctp_style(sk, UDP)) 4328df2c71ffSXin Long goto out; 4329df2c71ffSXin Long 4330df2c71ffSXin Long ep = sctp_sk(sk)->ep; 4331df2c71ffSXin Long ep->asconf_enable = !!params.assoc_value; 4332df2c71ffSXin Long 4333df2c71ffSXin Long if (ep->asconf_enable && ep->auth_enable) { 4334df2c71ffSXin Long sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF); 4335df2c71ffSXin Long sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK); 4336df2c71ffSXin Long } 4337df2c71ffSXin Long 4338df2c71ffSXin Long retval = 0; 4339df2c71ffSXin Long 4340df2c71ffSXin Long out: 4341df2c71ffSXin Long return retval; 4342df2c71ffSXin Long } 4343df2c71ffSXin Long 434456dd525aSXin Long static int sctp_setsockopt_auth_supported(struct sock *sk, 434556dd525aSXin Long char __user *optval, 434656dd525aSXin Long unsigned int optlen) 434756dd525aSXin Long { 434856dd525aSXin Long struct sctp_assoc_value params; 434956dd525aSXin Long struct sctp_association *asoc; 435056dd525aSXin Long struct sctp_endpoint *ep; 435156dd525aSXin Long int retval = -EINVAL; 435256dd525aSXin Long 435356dd525aSXin Long if (optlen != sizeof(params)) 435456dd525aSXin Long goto out; 435556dd525aSXin Long 435656dd525aSXin Long if (copy_from_user(¶ms, optval, optlen)) { 435756dd525aSXin Long retval = -EFAULT; 435856dd525aSXin Long goto out; 435956dd525aSXin Long } 436056dd525aSXin Long 436156dd525aSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 436256dd525aSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 436356dd525aSXin Long sctp_style(sk, UDP)) 436456dd525aSXin Long goto out; 436556dd525aSXin Long 436656dd525aSXin Long ep = sctp_sk(sk)->ep; 436756dd525aSXin Long if (params.assoc_value) { 436856dd525aSXin Long retval = sctp_auth_init(ep, GFP_KERNEL); 436956dd525aSXin Long if (retval) 437056dd525aSXin Long goto out; 437156dd525aSXin Long if (ep->asconf_enable) { 437256dd525aSXin Long sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF); 437356dd525aSXin Long sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK); 437456dd525aSXin Long } 437556dd525aSXin Long } 437656dd525aSXin Long 437756dd525aSXin Long ep->auth_enable = !!params.assoc_value; 437856dd525aSXin Long retval = 0; 437956dd525aSXin Long 438056dd525aSXin Long out: 438156dd525aSXin Long return retval; 438256dd525aSXin Long } 438356dd525aSXin Long 4384d5886b91SXin Long static int sctp_setsockopt_ecn_supported(struct sock *sk, 4385d5886b91SXin Long char __user *optval, 4386d5886b91SXin Long unsigned int optlen) 4387d5886b91SXin Long { 4388d5886b91SXin Long struct sctp_assoc_value params; 4389d5886b91SXin Long struct sctp_association *asoc; 4390d5886b91SXin Long int retval = -EINVAL; 4391d5886b91SXin Long 4392d5886b91SXin Long if (optlen != sizeof(params)) 4393d5886b91SXin Long goto out; 4394d5886b91SXin Long 4395d5886b91SXin Long if (copy_from_user(¶ms, optval, optlen)) { 4396d5886b91SXin Long retval = -EFAULT; 4397d5886b91SXin Long goto out; 4398d5886b91SXin Long } 4399d5886b91SXin Long 4400d5886b91SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 4401d5886b91SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 4402d5886b91SXin Long sctp_style(sk, UDP)) 4403d5886b91SXin Long goto out; 4404d5886b91SXin Long 4405d5886b91SXin Long sctp_sk(sk)->ep->ecn_enable = !!params.assoc_value; 4406d5886b91SXin Long retval = 0; 4407d5886b91SXin Long 4408d5886b91SXin Long out: 4409d5886b91SXin Long return retval; 4410d5886b91SXin Long } 4411d5886b91SXin Long 44128d2a6935SXin Long static int sctp_setsockopt_pf_expose(struct sock *sk, 44138d2a6935SXin Long char __user *optval, 44148d2a6935SXin Long unsigned int optlen) 44158d2a6935SXin Long { 44168d2a6935SXin Long struct sctp_assoc_value params; 44178d2a6935SXin Long struct sctp_association *asoc; 44188d2a6935SXin Long int retval = -EINVAL; 44198d2a6935SXin Long 44208d2a6935SXin Long if (optlen != sizeof(params)) 44218d2a6935SXin Long goto out; 44228d2a6935SXin Long 44238d2a6935SXin Long if (copy_from_user(¶ms, optval, optlen)) { 44248d2a6935SXin Long retval = -EFAULT; 44258d2a6935SXin Long goto out; 44268d2a6935SXin Long } 44278d2a6935SXin Long 44288d2a6935SXin Long if (params.assoc_value > SCTP_PF_EXPOSE_MAX) 44298d2a6935SXin Long goto out; 44308d2a6935SXin Long 44318d2a6935SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 44328d2a6935SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 44338d2a6935SXin Long sctp_style(sk, UDP)) 44348d2a6935SXin Long goto out; 44358d2a6935SXin Long 44368d2a6935SXin Long if (asoc) 44378d2a6935SXin Long asoc->pf_expose = params.assoc_value; 44388d2a6935SXin Long else 44398d2a6935SXin Long sctp_sk(sk)->pf_expose = params.assoc_value; 44408d2a6935SXin Long retval = 0; 44418d2a6935SXin Long 44428d2a6935SXin Long out: 44438d2a6935SXin Long return retval; 44448d2a6935SXin Long } 44458d2a6935SXin Long 44461da177e4SLinus Torvalds /* API 6.2 setsockopt(), getsockopt() 44471da177e4SLinus Torvalds * 44481da177e4SLinus Torvalds * Applications use setsockopt() and getsockopt() to set or retrieve 44491da177e4SLinus Torvalds * socket options. Socket options are used to change the default 44501da177e4SLinus Torvalds * behavior of sockets calls. They are described in Section 7. 44511da177e4SLinus Torvalds * 44521da177e4SLinus Torvalds * The syntax is: 44531da177e4SLinus Torvalds * 44541da177e4SLinus Torvalds * ret = getsockopt(int sd, int level, int optname, void __user *optval, 44551da177e4SLinus Torvalds * int __user *optlen); 44561da177e4SLinus Torvalds * ret = setsockopt(int sd, int level, int optname, const void __user *optval, 44571da177e4SLinus Torvalds * int optlen); 44581da177e4SLinus Torvalds * 44591da177e4SLinus Torvalds * sd - the socket descript. 44601da177e4SLinus Torvalds * level - set to IPPROTO_SCTP for all SCTP options. 44611da177e4SLinus Torvalds * optname - the option name. 44621da177e4SLinus Torvalds * optval - the buffer to store the value of the option. 44631da177e4SLinus Torvalds * optlen - the size of the buffer. 44641da177e4SLinus Torvalds */ 4465dda91928SDaniel Borkmann static int sctp_setsockopt(struct sock *sk, int level, int optname, 4466b7058842SDavid S. Miller char __user *optval, unsigned int optlen) 44671da177e4SLinus Torvalds { 4468ca84bd05SChristoph Hellwig void *kopt = NULL; 44691da177e4SLinus Torvalds int retval = 0; 44701da177e4SLinus Torvalds 4471bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 44721da177e4SLinus Torvalds 44731da177e4SLinus Torvalds /* I can hardly begin to describe how wrong this is. This is 44741da177e4SLinus Torvalds * so broken as to be worse than useless. The API draft 44751da177e4SLinus Torvalds * REALLY is NOT helpful here... I am not convinced that the 44761da177e4SLinus Torvalds * semantics of setsockopt() with a level OTHER THAN SOL_SCTP 44771da177e4SLinus Torvalds * are at all well-founded. 44781da177e4SLinus Torvalds */ 44791da177e4SLinus Torvalds if (level != SOL_SCTP) { 44801da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 44811da177e4SLinus Torvalds retval = af->setsockopt(sk, level, optname, optval, optlen); 44821da177e4SLinus Torvalds goto out_nounlock; 44831da177e4SLinus Torvalds } 44841da177e4SLinus Torvalds 4485ca84bd05SChristoph Hellwig if (optlen > 0) { 4486ca84bd05SChristoph Hellwig kopt = memdup_user(optval, optlen); 4487ca84bd05SChristoph Hellwig if (IS_ERR(kopt)) 4488ca84bd05SChristoph Hellwig return PTR_ERR(kopt); 4489ca84bd05SChristoph Hellwig } 4490ca84bd05SChristoph Hellwig 4491048ed4b6Swangweidong lock_sock(sk); 44921da177e4SLinus Torvalds 44931da177e4SLinus Torvalds switch (optname) { 44941da177e4SLinus Torvalds case SCTP_SOCKOPT_BINDX_ADD: 44951da177e4SLinus Torvalds /* 'optlen' is the size of the addresses buffer. */ 44968c7517f5SChristoph Hellwig retval = sctp_setsockopt_bindx(sk, kopt, optlen, 44978c7517f5SChristoph Hellwig SCTP_BINDX_ADD_ADDR); 44981da177e4SLinus Torvalds break; 44991da177e4SLinus Torvalds 45001da177e4SLinus Torvalds case SCTP_SOCKOPT_BINDX_REM: 45011da177e4SLinus Torvalds /* 'optlen' is the size of the addresses buffer. */ 45028c7517f5SChristoph Hellwig retval = sctp_setsockopt_bindx(sk, kopt, optlen, 45038c7517f5SChristoph Hellwig SCTP_BINDX_REM_ADDR); 45041da177e4SLinus Torvalds break; 45051da177e4SLinus Torvalds 450688a0a948SVlad Yasevich case SCTP_SOCKOPT_CONNECTX_OLD: 450788a0a948SVlad Yasevich /* 'optlen' is the size of the addresses buffer. */ 4508ce5b2f89SChristoph Hellwig retval = sctp_setsockopt_connectx_old(sk, kopt, optlen); 450988a0a948SVlad Yasevich break; 451088a0a948SVlad Yasevich 45113f7a87d2SFrank Filz case SCTP_SOCKOPT_CONNECTX: 45123f7a87d2SFrank Filz /* 'optlen' is the size of the addresses buffer. */ 4513ce5b2f89SChristoph Hellwig retval = sctp_setsockopt_connectx(sk, kopt, optlen); 45143f7a87d2SFrank Filz break; 45153f7a87d2SFrank Filz 45161da177e4SLinus Torvalds case SCTP_DISABLE_FRAGMENTS: 451710835825SChristoph Hellwig retval = sctp_setsockopt_disable_fragments(sk, kopt, optlen); 45181da177e4SLinus Torvalds break; 45191da177e4SLinus Torvalds 45201da177e4SLinus Torvalds case SCTP_EVENTS: 4521a98d21a1SChristoph Hellwig retval = sctp_setsockopt_events(sk, kopt, optlen); 45221da177e4SLinus Torvalds break; 45231da177e4SLinus Torvalds 45241da177e4SLinus Torvalds case SCTP_AUTOCLOSE: 45250b49a65cSChristoph Hellwig retval = sctp_setsockopt_autoclose(sk, kopt, optlen); 45261da177e4SLinus Torvalds break; 45271da177e4SLinus Torvalds 45281da177e4SLinus Torvalds case SCTP_PEER_ADDR_PARAMS: 45299b7b0d1aSChristoph Hellwig retval = sctp_setsockopt_peer_addr_params(sk, kopt, optlen); 45301da177e4SLinus Torvalds break; 45311da177e4SLinus Torvalds 45324580ccc0SShan Wei case SCTP_DELAYED_SACK: 4533ebb25defSChristoph Hellwig retval = sctp_setsockopt_delayed_ack(sk, kopt, optlen); 45347708610bSFrank Filz break; 4535d49d91d7SVlad Yasevich case SCTP_PARTIAL_DELIVERY_POINT: 4536bb13d647SChristoph Hellwig retval = sctp_setsockopt_partial_delivery_point(sk, kopt, optlen); 4537d49d91d7SVlad Yasevich break; 45387708610bSFrank Filz 45391da177e4SLinus Torvalds case SCTP_INITMSG: 45409dfa6f04SChristoph Hellwig retval = sctp_setsockopt_initmsg(sk, kopt, optlen); 45411da177e4SLinus Torvalds break; 45421da177e4SLinus Torvalds case SCTP_DEFAULT_SEND_PARAM: 4543c23ad6d2SChristoph Hellwig retval = sctp_setsockopt_default_send_param(sk, kopt, optlen); 45441da177e4SLinus Torvalds break; 45456b3fd5f3SGeir Ola Vaagland case SCTP_DEFAULT_SNDINFO: 45468a2409d3SChristoph Hellwig retval = sctp_setsockopt_default_sndinfo(sk, kopt, optlen); 45476b3fd5f3SGeir Ola Vaagland break; 45481da177e4SLinus Torvalds case SCTP_PRIMARY_ADDR: 45491eec6958SChristoph Hellwig retval = sctp_setsockopt_primary_addr(sk, kopt, optlen); 45501da177e4SLinus Torvalds break; 45511da177e4SLinus Torvalds case SCTP_SET_PEER_PRIMARY_ADDR: 455246a0ae9dSChristoph Hellwig retval = sctp_setsockopt_peer_primary_addr(sk, kopt, optlen); 45531da177e4SLinus Torvalds break; 45541da177e4SLinus Torvalds case SCTP_NODELAY: 4555f87ddbc0SChristoph Hellwig retval = sctp_setsockopt_nodelay(sk, kopt, optlen); 45561da177e4SLinus Torvalds break; 45571da177e4SLinus Torvalds case SCTP_RTOINFO: 4558af5ae60eSChristoph Hellwig retval = sctp_setsockopt_rtoinfo(sk, kopt, optlen); 45591da177e4SLinus Torvalds break; 45601da177e4SLinus Torvalds case SCTP_ASSOCINFO: 45615b864c8dSChristoph Hellwig retval = sctp_setsockopt_associnfo(sk, kopt, optlen); 45621da177e4SLinus Torvalds break; 45631da177e4SLinus Torvalds case SCTP_I_WANT_MAPPED_V4_ADDR: 4564ffc08f08SChristoph Hellwig retval = sctp_setsockopt_mappedv4(sk, kopt, optlen); 45651da177e4SLinus Torvalds break; 45661da177e4SLinus Torvalds case SCTP_MAXSEG: 4567dcd03575SChristoph Hellwig retval = sctp_setsockopt_maxseg(sk, kopt, optlen); 45681da177e4SLinus Torvalds break; 45690f3fffd8SIvan Skytte Jorgensen case SCTP_ADAPTATION_LAYER: 457007e5035cSChristoph Hellwig retval = sctp_setsockopt_adaptation_layer(sk, kopt, optlen); 45711da177e4SLinus Torvalds break; 45726ab792f5SIvan Skytte Jorgensen case SCTP_CONTEXT: 4573722eca9eSChristoph Hellwig retval = sctp_setsockopt_context(sk, kopt, optlen); 45746ab792f5SIvan Skytte Jorgensen break; 4575b6e1331fSVlad Yasevich case SCTP_FRAGMENT_INTERLEAVE: 45761031cea0SChristoph Hellwig retval = sctp_setsockopt_fragment_interleave(sk, kopt, optlen); 4577b6e1331fSVlad Yasevich break; 457870331571SVlad Yasevich case SCTP_MAX_BURST: 4579f5bee0adSChristoph Hellwig retval = sctp_setsockopt_maxburst(sk, kopt, optlen); 458070331571SVlad Yasevich break; 458165b07e5dSVlad Yasevich case SCTP_AUTH_CHUNK: 458288266d31SChristoph Hellwig retval = sctp_setsockopt_auth_chunk(sk, kopt, optlen); 458365b07e5dSVlad Yasevich break; 458465b07e5dSVlad Yasevich case SCTP_HMAC_IDENT: 45853564ef44SChristoph Hellwig retval = sctp_setsockopt_hmac_ident(sk, kopt, optlen); 458665b07e5dSVlad Yasevich break; 458765b07e5dSVlad Yasevich case SCTP_AUTH_KEY: 4588534d13d0SChristoph Hellwig retval = sctp_setsockopt_auth_key(sk, kopt, optlen); 458965b07e5dSVlad Yasevich break; 459065b07e5dSVlad Yasevich case SCTP_AUTH_ACTIVE_KEY: 4591dcab0a7aSChristoph Hellwig retval = sctp_setsockopt_active_key(sk, kopt, optlen); 459265b07e5dSVlad Yasevich break; 459365b07e5dSVlad Yasevich case SCTP_AUTH_DELETE_KEY: 459497dc9f2eSChristoph Hellwig retval = sctp_setsockopt_del_key(sk, kopt, optlen); 459565b07e5dSVlad Yasevich break; 4596601590ecSXin Long case SCTP_AUTH_DEACTIVATE_KEY: 459776b3d0c4SChristoph Hellwig retval = sctp_setsockopt_deactivate_key(sk, kopt, optlen); 4598601590ecSXin Long break; 45997dc04d71SMichio Honda case SCTP_AUTO_ASCONF: 4600c9abc2c1SChristoph Hellwig retval = sctp_setsockopt_auto_asconf(sk, kopt, optlen); 46017dc04d71SMichio Honda break; 46025aa93bcfSNeil Horman case SCTP_PEER_ADDR_THLDS: 4603b0ac3bb8SChristoph Hellwig retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen, 4604d467ac0aSXin Long false); 4605d467ac0aSXin Long break; 4606d467ac0aSXin Long case SCTP_PEER_ADDR_THLDS_V2: 4607b0ac3bb8SChristoph Hellwig retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen, 4608d467ac0aSXin Long true); 46095aa93bcfSNeil Horman break; 46100d3a421dSGeir Ola Vaagland case SCTP_RECVRCVINFO: 4611a98af7c8SChristoph Hellwig retval = sctp_setsockopt_recvrcvinfo(sk, kopt, optlen); 46120d3a421dSGeir Ola Vaagland break; 46132347c80fSGeir Ola Vaagland case SCTP_RECVNXTINFO: 4614cfa6fde2SChristoph Hellwig retval = sctp_setsockopt_recvnxtinfo(sk, kopt, optlen); 46152347c80fSGeir Ola Vaagland break; 461628aa4c26SXin Long case SCTP_PR_SUPPORTED: 46174a97fa4fSChristoph Hellwig retval = sctp_setsockopt_pr_supported(sk, kopt, optlen); 461828aa4c26SXin Long break; 4619f959fb44SXin Long case SCTP_DEFAULT_PRINFO: 4620ac37435bSChristoph Hellwig retval = sctp_setsockopt_default_prinfo(sk, kopt, optlen); 4621f959fb44SXin Long break; 4622c0d8bab6SXin Long case SCTP_RECONFIG_SUPPORTED: 46233f49f720SChristoph Hellwig retval = sctp_setsockopt_reconfig_supported(sk, kopt, optlen); 4624c0d8bab6SXin Long break; 46259fb657aeSXin Long case SCTP_ENABLE_STREAM_RESET: 4626356dc6f1SChristoph Hellwig retval = sctp_setsockopt_enable_strreset(sk, kopt, optlen); 46279fb657aeSXin Long break; 46287f9d68acSXin Long case SCTP_RESET_STREAMS: 4629d4922434SChristoph Hellwig retval = sctp_setsockopt_reset_streams(sk, kopt, optlen); 46307f9d68acSXin Long break; 4631a92ce1a4SXin Long case SCTP_RESET_ASSOC: 4632b97d20ceSChristoph Hellwig retval = sctp_setsockopt_reset_assoc(sk, kopt, optlen); 4633a92ce1a4SXin Long break; 4634242bd2d5SXin Long case SCTP_ADD_STREAMS: 46354d6fb260SChristoph Hellwig retval = sctp_setsockopt_add_streams(sk, kopt, optlen); 4636242bd2d5SXin Long break; 463713aa8770SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER: 46384d2fba3aSChristoph Hellwig retval = sctp_setsockopt_scheduler(sk, kopt, optlen); 463913aa8770SMarcelo Ricardo Leitner break; 46400ccdf3c7SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER_VALUE: 4641d636e7f3SChristoph Hellwig retval = sctp_setsockopt_scheduler_value(sk, kopt, optlen); 46420ccdf3c7SMarcelo Ricardo Leitner break; 4643772a5869SXin Long case SCTP_INTERLEAVING_SUPPORTED: 4644*5b8d3b24SChristoph Hellwig retval = sctp_setsockopt_interleaving_supported(sk, kopt, 4645772a5869SXin Long optlen); 4646772a5869SXin Long break; 4647b0e9a2feSXin Long case SCTP_REUSE_PORT: 4648b0e9a2feSXin Long retval = sctp_setsockopt_reuse_port(sk, optval, optlen); 4649b0e9a2feSXin Long break; 4650480ba9c1SXin Long case SCTP_EVENT: 4651480ba9c1SXin Long retval = sctp_setsockopt_event(sk, optval, optlen); 4652480ba9c1SXin Long break; 4653df2c71ffSXin Long case SCTP_ASCONF_SUPPORTED: 4654df2c71ffSXin Long retval = sctp_setsockopt_asconf_supported(sk, optval, optlen); 4655df2c71ffSXin Long break; 465656dd525aSXin Long case SCTP_AUTH_SUPPORTED: 465756dd525aSXin Long retval = sctp_setsockopt_auth_supported(sk, optval, optlen); 465856dd525aSXin Long break; 4659d5886b91SXin Long case SCTP_ECN_SUPPORTED: 4660d5886b91SXin Long retval = sctp_setsockopt_ecn_supported(sk, optval, optlen); 4661d5886b91SXin Long break; 46628d2a6935SXin Long case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: 46638d2a6935SXin Long retval = sctp_setsockopt_pf_expose(sk, optval, optlen); 46648d2a6935SXin Long break; 46651da177e4SLinus Torvalds default: 46661da177e4SLinus Torvalds retval = -ENOPROTOOPT; 46671da177e4SLinus Torvalds break; 46683ff50b79SStephen Hemminger } 46691da177e4SLinus Torvalds 4670048ed4b6Swangweidong release_sock(sk); 4671ca84bd05SChristoph Hellwig kfree(kopt); 46721da177e4SLinus Torvalds 46731da177e4SLinus Torvalds out_nounlock: 46741da177e4SLinus Torvalds return retval; 46751da177e4SLinus Torvalds } 46761da177e4SLinus Torvalds 46771da177e4SLinus Torvalds /* API 3.1.6 connect() - UDP Style Syntax 46781da177e4SLinus Torvalds * 46791da177e4SLinus Torvalds * An application may use the connect() call in the UDP model to initiate an 46801da177e4SLinus Torvalds * association without sending data. 46811da177e4SLinus Torvalds * 46821da177e4SLinus Torvalds * The syntax is: 46831da177e4SLinus Torvalds * 46841da177e4SLinus Torvalds * ret = connect(int sd, const struct sockaddr *nam, socklen_t len); 46851da177e4SLinus Torvalds * 46861da177e4SLinus Torvalds * sd: the socket descriptor to have a new association added to. 46871da177e4SLinus Torvalds * 46881da177e4SLinus Torvalds * nam: the address structure (either struct sockaddr_in or struct 46891da177e4SLinus Torvalds * sockaddr_in6 defined in RFC2553 [7]). 46901da177e4SLinus Torvalds * 46911da177e4SLinus Torvalds * len: the size of the address. 46921da177e4SLinus Torvalds */ 4693dda91928SDaniel Borkmann static int sctp_connect(struct sock *sk, struct sockaddr *addr, 4694644fbdeaSXin Long int addr_len, int flags) 46951da177e4SLinus Torvalds { 46963f7a87d2SFrank Filz struct sctp_af *af; 46979b6c0887SXin Long int err = -EINVAL; 46981da177e4SLinus Torvalds 4699048ed4b6Swangweidong lock_sock(sk); 4700bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk, 4701bb33381dSDaniel Borkmann addr, addr_len); 47021da177e4SLinus Torvalds 47033f7a87d2SFrank Filz /* Validate addr_len before calling common connect/connectx routine. */ 47049b6c0887SXin Long af = sctp_get_af_specific(addr->sa_family); 47059b6c0887SXin Long if (af && addr_len >= af->sockaddr_len) 4706644fbdeaSXin Long err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL); 47071da177e4SLinus Torvalds 4708048ed4b6Swangweidong release_sock(sk); 47091da177e4SLinus Torvalds return err; 47101da177e4SLinus Torvalds } 47111da177e4SLinus Torvalds 4712644fbdeaSXin Long int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr, 4713644fbdeaSXin Long int addr_len, int flags) 4714644fbdeaSXin Long { 4715644fbdeaSXin Long if (addr_len < sizeof(uaddr->sa_family)) 4716644fbdeaSXin Long return -EINVAL; 4717644fbdeaSXin Long 4718644fbdeaSXin Long if (uaddr->sa_family == AF_UNSPEC) 4719644fbdeaSXin Long return -EOPNOTSUPP; 4720644fbdeaSXin Long 4721644fbdeaSXin Long return sctp_connect(sock->sk, uaddr, addr_len, flags); 4722644fbdeaSXin Long } 4723644fbdeaSXin Long 47241da177e4SLinus Torvalds /* FIXME: Write comments. */ 4725dda91928SDaniel Borkmann static int sctp_disconnect(struct sock *sk, int flags) 47261da177e4SLinus Torvalds { 47271da177e4SLinus Torvalds return -EOPNOTSUPP; /* STUB */ 47281da177e4SLinus Torvalds } 47291da177e4SLinus Torvalds 47301da177e4SLinus Torvalds /* 4.1.4 accept() - TCP Style Syntax 47311da177e4SLinus Torvalds * 47321da177e4SLinus Torvalds * Applications use accept() call to remove an established SCTP 47331da177e4SLinus Torvalds * association from the accept queue of the endpoint. A new socket 47341da177e4SLinus Torvalds * descriptor will be returned from accept() to represent the newly 47351da177e4SLinus Torvalds * formed association. 47361da177e4SLinus Torvalds */ 4737cdfbabfbSDavid Howells static struct sock *sctp_accept(struct sock *sk, int flags, int *err, bool kern) 47381da177e4SLinus Torvalds { 47391da177e4SLinus Torvalds struct sctp_sock *sp; 47401da177e4SLinus Torvalds struct sctp_endpoint *ep; 47411da177e4SLinus Torvalds struct sock *newsk = NULL; 47421da177e4SLinus Torvalds struct sctp_association *asoc; 47431da177e4SLinus Torvalds long timeo; 47441da177e4SLinus Torvalds int error = 0; 47451da177e4SLinus Torvalds 4746048ed4b6Swangweidong lock_sock(sk); 47471da177e4SLinus Torvalds 47481da177e4SLinus Torvalds sp = sctp_sk(sk); 47491da177e4SLinus Torvalds ep = sp->ep; 47501da177e4SLinus Torvalds 47511da177e4SLinus Torvalds if (!sctp_style(sk, TCP)) { 47521da177e4SLinus Torvalds error = -EOPNOTSUPP; 47531da177e4SLinus Torvalds goto out; 47541da177e4SLinus Torvalds } 47551da177e4SLinus Torvalds 47561da177e4SLinus Torvalds if (!sctp_sstate(sk, LISTENING)) { 47571da177e4SLinus Torvalds error = -EINVAL; 47581da177e4SLinus Torvalds goto out; 47591da177e4SLinus Torvalds } 47601da177e4SLinus Torvalds 47618abfedd8SSridhar Samudrala timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 47621da177e4SLinus Torvalds 47631da177e4SLinus Torvalds error = sctp_wait_for_accept(sk, timeo); 47641da177e4SLinus Torvalds if (error) 47651da177e4SLinus Torvalds goto out; 47661da177e4SLinus Torvalds 47671da177e4SLinus Torvalds /* We treat the list of associations on the endpoint as the accept 47681da177e4SLinus Torvalds * queue and pick the first association on the list. 47691da177e4SLinus Torvalds */ 47701da177e4SLinus Torvalds asoc = list_entry(ep->asocs.next, struct sctp_association, asocs); 47711da177e4SLinus Torvalds 4772cdfbabfbSDavid Howells newsk = sp->pf->create_accept_sk(sk, asoc, kern); 47731da177e4SLinus Torvalds if (!newsk) { 47741da177e4SLinus Torvalds error = -ENOMEM; 47751da177e4SLinus Torvalds goto out; 47761da177e4SLinus Torvalds } 47771da177e4SLinus Torvalds 47781da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the 47791da177e4SLinus Torvalds * asoc to the newsk. 47801da177e4SLinus Torvalds */ 478189664c62SXin Long error = sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); 478289664c62SXin Long if (error) { 478389664c62SXin Long sk_common_release(newsk); 478489664c62SXin Long newsk = NULL; 478589664c62SXin Long } 47861da177e4SLinus Torvalds 47871da177e4SLinus Torvalds out: 4788048ed4b6Swangweidong release_sock(sk); 47891da177e4SLinus Torvalds *err = error; 47901da177e4SLinus Torvalds return newsk; 47911da177e4SLinus Torvalds } 47921da177e4SLinus Torvalds 47931da177e4SLinus Torvalds /* The SCTP ioctl handler. */ 4794dda91928SDaniel Borkmann static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) 47951da177e4SLinus Torvalds { 479665040c33SDiego Elio 'Flameeyes' Pettenò int rc = -ENOTCONN; 479765040c33SDiego Elio 'Flameeyes' Pettenò 4798048ed4b6Swangweidong lock_sock(sk); 479965040c33SDiego Elio 'Flameeyes' Pettenò 480065040c33SDiego Elio 'Flameeyes' Pettenò /* 480165040c33SDiego Elio 'Flameeyes' Pettenò * SEQPACKET-style sockets in LISTENING state are valid, for 480265040c33SDiego Elio 'Flameeyes' Pettenò * SCTP, so only discard TCP-style sockets in LISTENING state. 480365040c33SDiego Elio 'Flameeyes' Pettenò */ 480465040c33SDiego Elio 'Flameeyes' Pettenò if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 480565040c33SDiego Elio 'Flameeyes' Pettenò goto out; 480665040c33SDiego Elio 'Flameeyes' Pettenò 480765040c33SDiego Elio 'Flameeyes' Pettenò switch (cmd) { 480865040c33SDiego Elio 'Flameeyes' Pettenò case SIOCINQ: { 480965040c33SDiego Elio 'Flameeyes' Pettenò struct sk_buff *skb; 481065040c33SDiego Elio 'Flameeyes' Pettenò unsigned int amount = 0; 481165040c33SDiego Elio 'Flameeyes' Pettenò 481265040c33SDiego Elio 'Flameeyes' Pettenò skb = skb_peek(&sk->sk_receive_queue); 481365040c33SDiego Elio 'Flameeyes' Pettenò if (skb != NULL) { 481465040c33SDiego Elio 'Flameeyes' Pettenò /* 481565040c33SDiego Elio 'Flameeyes' Pettenò * We will only return the amount of this packet since 481665040c33SDiego Elio 'Flameeyes' Pettenò * that is all that will be read. 481765040c33SDiego Elio 'Flameeyes' Pettenò */ 481865040c33SDiego Elio 'Flameeyes' Pettenò amount = skb->len; 481965040c33SDiego Elio 'Flameeyes' Pettenò } 482065040c33SDiego Elio 'Flameeyes' Pettenò rc = put_user(amount, (int __user *)arg); 482165040c33SDiego Elio 'Flameeyes' Pettenò break; 48229a7241c2SDavid S. Miller } 482365040c33SDiego Elio 'Flameeyes' Pettenò default: 482465040c33SDiego Elio 'Flameeyes' Pettenò rc = -ENOIOCTLCMD; 482565040c33SDiego Elio 'Flameeyes' Pettenò break; 482665040c33SDiego Elio 'Flameeyes' Pettenò } 482765040c33SDiego Elio 'Flameeyes' Pettenò out: 4828048ed4b6Swangweidong release_sock(sk); 482965040c33SDiego Elio 'Flameeyes' Pettenò return rc; 48301da177e4SLinus Torvalds } 48311da177e4SLinus Torvalds 48321da177e4SLinus Torvalds /* This is the function which gets called during socket creation to 48331da177e4SLinus Torvalds * initialized the SCTP-specific portion of the sock. 48341da177e4SLinus Torvalds * The sock structure should already be zero-filled memory. 48351da177e4SLinus Torvalds */ 4836dda91928SDaniel Borkmann static int sctp_init_sock(struct sock *sk) 48371da177e4SLinus Torvalds { 4838e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 48391da177e4SLinus Torvalds struct sctp_sock *sp; 48401da177e4SLinus Torvalds 4841bb33381dSDaniel Borkmann pr_debug("%s: sk:%p\n", __func__, sk); 48421da177e4SLinus Torvalds 48431da177e4SLinus Torvalds sp = sctp_sk(sk); 48441da177e4SLinus Torvalds 48451da177e4SLinus Torvalds /* Initialize the SCTP per socket area. */ 48461da177e4SLinus Torvalds switch (sk->sk_type) { 48471da177e4SLinus Torvalds case SOCK_SEQPACKET: 48481da177e4SLinus Torvalds sp->type = SCTP_SOCKET_UDP; 48491da177e4SLinus Torvalds break; 48501da177e4SLinus Torvalds case SOCK_STREAM: 48511da177e4SLinus Torvalds sp->type = SCTP_SOCKET_TCP; 48521da177e4SLinus Torvalds break; 48531da177e4SLinus Torvalds default: 48541da177e4SLinus Torvalds return -ESOCKTNOSUPPORT; 48551da177e4SLinus Torvalds } 48561da177e4SLinus Torvalds 485790017accSMarcelo Ricardo Leitner sk->sk_gso_type = SKB_GSO_SCTP; 485890017accSMarcelo Ricardo Leitner 48591da177e4SLinus Torvalds /* Initialize default send parameters. These parameters can be 48601da177e4SLinus Torvalds * modified with the SCTP_DEFAULT_SEND_PARAM socket option. 48611da177e4SLinus Torvalds */ 48621da177e4SLinus Torvalds sp->default_stream = 0; 48631da177e4SLinus Torvalds sp->default_ppid = 0; 48641da177e4SLinus Torvalds sp->default_flags = 0; 48651da177e4SLinus Torvalds sp->default_context = 0; 48661da177e4SLinus Torvalds sp->default_timetolive = 0; 48671da177e4SLinus Torvalds 48686ab792f5SIvan Skytte Jorgensen sp->default_rcv_context = 0; 4869e1fc3b14SEric W. Biederman sp->max_burst = net->sctp.max_burst; 48706ab792f5SIvan Skytte Jorgensen 48713c68198eSNeil Horman sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg; 48723c68198eSNeil Horman 48731da177e4SLinus Torvalds /* Initialize default setup parameters. These parameters 48741da177e4SLinus Torvalds * can be modified with the SCTP_INITMSG socket option or 48751da177e4SLinus Torvalds * overridden by the SCTP_INIT CMSG. 48761da177e4SLinus Torvalds */ 48771da177e4SLinus Torvalds sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; 48781da177e4SLinus Torvalds sp->initmsg.sinit_max_instreams = sctp_max_instreams; 4879e1fc3b14SEric W. Biederman sp->initmsg.sinit_max_attempts = net->sctp.max_retrans_init; 4880e1fc3b14SEric W. Biederman sp->initmsg.sinit_max_init_timeo = net->sctp.rto_max; 48811da177e4SLinus Torvalds 48821da177e4SLinus Torvalds /* Initialize default RTO related parameters. These parameters can 48831da177e4SLinus Torvalds * be modified for with the SCTP_RTOINFO socket option. 48841da177e4SLinus Torvalds */ 4885e1fc3b14SEric W. Biederman sp->rtoinfo.srto_initial = net->sctp.rto_initial; 4886e1fc3b14SEric W. Biederman sp->rtoinfo.srto_max = net->sctp.rto_max; 4887e1fc3b14SEric W. Biederman sp->rtoinfo.srto_min = net->sctp.rto_min; 48881da177e4SLinus Torvalds 48891da177e4SLinus Torvalds /* Initialize default association related parameters. These parameters 48901da177e4SLinus Torvalds * can be modified with the SCTP_ASSOCINFO socket option. 48911da177e4SLinus Torvalds */ 4892e1fc3b14SEric W. Biederman sp->assocparams.sasoc_asocmaxrxt = net->sctp.max_retrans_association; 48931da177e4SLinus Torvalds sp->assocparams.sasoc_number_peer_destinations = 0; 48941da177e4SLinus Torvalds sp->assocparams.sasoc_peer_rwnd = 0; 48951da177e4SLinus Torvalds sp->assocparams.sasoc_local_rwnd = 0; 4896e1fc3b14SEric W. Biederman sp->assocparams.sasoc_cookie_life = net->sctp.valid_cookie_life; 48971da177e4SLinus Torvalds 48981da177e4SLinus Torvalds /* Initialize default event subscriptions. By default, all the 48991da177e4SLinus Torvalds * options are off. 49001da177e4SLinus Torvalds */ 49012cc0eeb6SXin Long sp->subscribe = 0; 49021da177e4SLinus Torvalds 49031da177e4SLinus Torvalds /* Default Peer Address Parameters. These defaults can 49041da177e4SLinus Torvalds * be modified via SCTP_PEER_ADDR_PARAMS 49051da177e4SLinus Torvalds */ 4906e1fc3b14SEric W. Biederman sp->hbinterval = net->sctp.hb_interval; 4907e1fc3b14SEric W. Biederman sp->pathmaxrxt = net->sctp.max_retrans_path; 49088add543eSXin Long sp->pf_retrans = net->sctp.pf_retrans; 490934515e94SXin Long sp->ps_retrans = net->sctp.ps_retrans; 4910aef587beSXin Long sp->pf_expose = net->sctp.pf_expose; 49114e2d52bfSwangweidong sp->pathmtu = 0; /* allow default discovery */ 4912e1fc3b14SEric W. Biederman sp->sackdelay = net->sctp.sack_timeout; 49137bfe8bdbSVlad Yasevich sp->sackfreq = 2; 491452ccb8e9SFrank Filz sp->param_flags = SPP_HB_ENABLE | 491552ccb8e9SFrank Filz SPP_PMTUD_ENABLE | 491652ccb8e9SFrank Filz SPP_SACKDELAY_ENABLE; 49177efba10dSXin Long sp->default_ss = SCTP_SS_DEFAULT; 49181da177e4SLinus Torvalds 49191da177e4SLinus Torvalds /* If enabled no SCTP message fragmentation will be performed. 49201da177e4SLinus Torvalds * Configure through SCTP_DISABLE_FRAGMENTS socket option. 49211da177e4SLinus Torvalds */ 49221da177e4SLinus Torvalds sp->disable_fragments = 0; 49231da177e4SLinus Torvalds 4924208edef6SSridhar Samudrala /* Enable Nagle algorithm by default. */ 4925208edef6SSridhar Samudrala sp->nodelay = 0; 49261da177e4SLinus Torvalds 49270d3a421dSGeir Ola Vaagland sp->recvrcvinfo = 0; 49282347c80fSGeir Ola Vaagland sp->recvnxtinfo = 0; 49290d3a421dSGeir Ola Vaagland 49301da177e4SLinus Torvalds /* Enable by default. */ 49311da177e4SLinus Torvalds sp->v4mapped = 1; 49321da177e4SLinus Torvalds 49331da177e4SLinus Torvalds /* Auto-close idle associations after the configured 49341da177e4SLinus Torvalds * number of seconds. A value of 0 disables this 49351da177e4SLinus Torvalds * feature. Configure through the SCTP_AUTOCLOSE socket option, 49361da177e4SLinus Torvalds * for UDP-style sockets only. 49371da177e4SLinus Torvalds */ 49381da177e4SLinus Torvalds sp->autoclose = 0; 49391da177e4SLinus Torvalds 49401da177e4SLinus Torvalds /* User specified fragmentation limit. */ 49411da177e4SLinus Torvalds sp->user_frag = 0; 49421da177e4SLinus Torvalds 49430f3fffd8SIvan Skytte Jorgensen sp->adaptation_ind = 0; 49441da177e4SLinus Torvalds 49451da177e4SLinus Torvalds sp->pf = sctp_get_pf_specific(sk->sk_family); 49461da177e4SLinus Torvalds 49471da177e4SLinus Torvalds /* Control variables for partial data delivery. */ 4948b6e1331fSVlad Yasevich atomic_set(&sp->pd_mode, 0); 49491da177e4SLinus Torvalds skb_queue_head_init(&sp->pd_lobby); 4950b6e1331fSVlad Yasevich sp->frag_interleave = 0; 49511da177e4SLinus Torvalds 49521da177e4SLinus Torvalds /* Create a per socket endpoint structure. Even if we 49531da177e4SLinus Torvalds * change the data structure relationships, this may still 49541da177e4SLinus Torvalds * be useful for storing pre-connect address information. 49551da177e4SLinus Torvalds */ 4956c164b838SDaniel Borkmann sp->ep = sctp_endpoint_new(sk, GFP_KERNEL); 4957c164b838SDaniel Borkmann if (!sp->ep) 49581da177e4SLinus Torvalds return -ENOMEM; 49591da177e4SLinus Torvalds 49601da177e4SLinus Torvalds sp->hmac = NULL; 49611da177e4SLinus Torvalds 49620a2fbac1SDaniel Borkmann sk->sk_destruct = sctp_destruct_sock; 49630a2fbac1SDaniel Borkmann 49641da177e4SLinus Torvalds SCTP_DBG_OBJCNT_INC(sock); 49656f756a8cSDavid S. Miller 49666f756a8cSDavid S. Miller local_bh_disable(); 49678cb38a60STonghao Zhang sk_sockets_allocated_inc(sk); 4968e1fc3b14SEric W. Biederman sock_prot_inuse_add(net, sk->sk_prot, 1); 49692d45a02dSMarcelo Ricardo Leitner 49702d45a02dSMarcelo Ricardo Leitner /* Nothing can fail after this block, otherwise 49712d45a02dSMarcelo Ricardo Leitner * sctp_destroy_sock() will be called without addr_wq_lock held 49722d45a02dSMarcelo Ricardo Leitner */ 4973e1fc3b14SEric W. Biederman if (net->sctp.default_auto_asconf) { 49742d45a02dSMarcelo Ricardo Leitner spin_lock(&sock_net(sk)->sctp.addr_wq_lock); 49759f7d653bSMichio Honda list_add_tail(&sp->auto_asconf_list, 4976e1fc3b14SEric W. Biederman &net->sctp.auto_asconf_splist); 49779f7d653bSMichio Honda sp->do_auto_asconf = 1; 49782d45a02dSMarcelo Ricardo Leitner spin_unlock(&sock_net(sk)->sctp.addr_wq_lock); 49792d45a02dSMarcelo Ricardo Leitner } else { 49809f7d653bSMichio Honda sp->do_auto_asconf = 0; 49812d45a02dSMarcelo Ricardo Leitner } 49822d45a02dSMarcelo Ricardo Leitner 49836f756a8cSDavid S. Miller local_bh_enable(); 49846f756a8cSDavid S. Miller 49851da177e4SLinus Torvalds return 0; 49861da177e4SLinus Torvalds } 49871da177e4SLinus Torvalds 49882d45a02dSMarcelo Ricardo Leitner /* Cleanup any SCTP per socket resources. Must be called with 49892d45a02dSMarcelo Ricardo Leitner * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true 49902d45a02dSMarcelo Ricardo Leitner */ 4991dda91928SDaniel Borkmann static void sctp_destroy_sock(struct sock *sk) 49921da177e4SLinus Torvalds { 49939f7d653bSMichio Honda struct sctp_sock *sp; 49941da177e4SLinus Torvalds 4995bb33381dSDaniel Borkmann pr_debug("%s: sk:%p\n", __func__, sk); 49961da177e4SLinus Torvalds 49971da177e4SLinus Torvalds /* Release our hold on the endpoint. */ 49989f7d653bSMichio Honda sp = sctp_sk(sk); 49991abd165eSDaniel Borkmann /* This could happen during socket init, thus we bail out 50001abd165eSDaniel Borkmann * early, since the rest of the below is not setup either. 50011abd165eSDaniel Borkmann */ 50021abd165eSDaniel Borkmann if (sp->ep == NULL) 50031abd165eSDaniel Borkmann return; 50041abd165eSDaniel Borkmann 50059f7d653bSMichio Honda if (sp->do_auto_asconf) { 50069f7d653bSMichio Honda sp->do_auto_asconf = 0; 50079f7d653bSMichio Honda list_del(&sp->auto_asconf_list); 50089f7d653bSMichio Honda } 50099f7d653bSMichio Honda sctp_endpoint_free(sp->ep); 50105bc0b3bfSEric Dumazet local_bh_disable(); 50118cb38a60STonghao Zhang sk_sockets_allocated_dec(sk); 50129a57f7faSEric Dumazet sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 50135bc0b3bfSEric Dumazet local_bh_enable(); 50141da177e4SLinus Torvalds } 50151da177e4SLinus Torvalds 50160a2fbac1SDaniel Borkmann /* Triggered when there are no references on the socket anymore */ 50170a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk) 50180a2fbac1SDaniel Borkmann { 50190a2fbac1SDaniel Borkmann struct sctp_sock *sp = sctp_sk(sk); 50200a2fbac1SDaniel Borkmann 50210a2fbac1SDaniel Borkmann /* Free up the HMAC transform. */ 50225821c769SHerbert Xu crypto_free_shash(sp->hmac); 50230a2fbac1SDaniel Borkmann 50240a2fbac1SDaniel Borkmann inet_sock_destruct(sk); 50250a2fbac1SDaniel Borkmann } 50260a2fbac1SDaniel Borkmann 50271da177e4SLinus Torvalds /* API 4.1.7 shutdown() - TCP Style Syntax 50281da177e4SLinus Torvalds * int shutdown(int socket, int how); 50291da177e4SLinus Torvalds * 50301da177e4SLinus Torvalds * sd - the socket descriptor of the association to be closed. 50311da177e4SLinus Torvalds * how - Specifies the type of shutdown. The values are 50321da177e4SLinus Torvalds * as follows: 50331da177e4SLinus Torvalds * SHUT_RD 50341da177e4SLinus Torvalds * Disables further receive operations. No SCTP 50351da177e4SLinus Torvalds * protocol action is taken. 50361da177e4SLinus Torvalds * SHUT_WR 50371da177e4SLinus Torvalds * Disables further send operations, and initiates 50381da177e4SLinus Torvalds * the SCTP shutdown sequence. 50391da177e4SLinus Torvalds * SHUT_RDWR 50401da177e4SLinus Torvalds * Disables further send and receive operations 50411da177e4SLinus Torvalds * and initiates the SCTP shutdown sequence. 50421da177e4SLinus Torvalds */ 5043dda91928SDaniel Borkmann static void sctp_shutdown(struct sock *sk, int how) 50441da177e4SLinus Torvalds { 504555e26eb9SEric W. Biederman struct net *net = sock_net(sk); 50461da177e4SLinus Torvalds struct sctp_endpoint *ep; 50471da177e4SLinus Torvalds 50481da177e4SLinus Torvalds if (!sctp_style(sk, TCP)) 50491da177e4SLinus Torvalds return; 50501da177e4SLinus Torvalds 50511da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 50525bf35ddfSXin Long if (how & SEND_SHUTDOWN && !list_empty(&ep->asocs)) { 50535bf35ddfSXin Long struct sctp_association *asoc; 50545bf35ddfSXin Long 5055cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_CLOSING); 50561da177e4SLinus Torvalds asoc = list_entry(ep->asocs.next, 50571da177e4SLinus Torvalds struct sctp_association, asocs); 505855e26eb9SEric W. Biederman sctp_primitive_SHUTDOWN(net, asoc, NULL); 50591da177e4SLinus Torvalds } 50601da177e4SLinus Torvalds } 50611da177e4SLinus Torvalds 506252c52a61SXin Long int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, 506352c52a61SXin Long struct sctp_info *info) 506452c52a61SXin Long { 506552c52a61SXin Long struct sctp_transport *prim; 506652c52a61SXin Long struct list_head *pos; 506752c52a61SXin Long int mask; 506852c52a61SXin Long 506952c52a61SXin Long memset(info, 0, sizeof(*info)); 507052c52a61SXin Long if (!asoc) { 507152c52a61SXin Long struct sctp_sock *sp = sctp_sk(sk); 507252c52a61SXin Long 507352c52a61SXin Long info->sctpi_s_autoclose = sp->autoclose; 507452c52a61SXin Long info->sctpi_s_adaptation_ind = sp->adaptation_ind; 507552c52a61SXin Long info->sctpi_s_pd_point = sp->pd_point; 507652c52a61SXin Long info->sctpi_s_nodelay = sp->nodelay; 507752c52a61SXin Long info->sctpi_s_disable_fragments = sp->disable_fragments; 507852c52a61SXin Long info->sctpi_s_v4mapped = sp->v4mapped; 507952c52a61SXin Long info->sctpi_s_frag_interleave = sp->frag_interleave; 508040eb90e9SXin Long info->sctpi_s_type = sp->type; 508152c52a61SXin Long 508252c52a61SXin Long return 0; 508352c52a61SXin Long } 508452c52a61SXin Long 508552c52a61SXin Long info->sctpi_tag = asoc->c.my_vtag; 508652c52a61SXin Long info->sctpi_state = asoc->state; 508752c52a61SXin Long info->sctpi_rwnd = asoc->a_rwnd; 508852c52a61SXin Long info->sctpi_unackdata = asoc->unack_data; 508952c52a61SXin Long info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 5090cee360abSXin Long info->sctpi_instrms = asoc->stream.incnt; 5091cee360abSXin Long info->sctpi_outstrms = asoc->stream.outcnt; 509252c52a61SXin Long list_for_each(pos, &asoc->base.inqueue.in_chunk_list) 509352c52a61SXin Long info->sctpi_inqueue++; 509452c52a61SXin Long list_for_each(pos, &asoc->outqueue.out_chunk_list) 509552c52a61SXin Long info->sctpi_outqueue++; 509652c52a61SXin Long info->sctpi_overall_error = asoc->overall_error_count; 509752c52a61SXin Long info->sctpi_max_burst = asoc->max_burst; 509852c52a61SXin Long info->sctpi_maxseg = asoc->frag_point; 509952c52a61SXin Long info->sctpi_peer_rwnd = asoc->peer.rwnd; 510052c52a61SXin Long info->sctpi_peer_tag = asoc->c.peer_vtag; 510152c52a61SXin Long 510252c52a61SXin Long mask = asoc->peer.ecn_capable << 1; 510352c52a61SXin Long mask = (mask | asoc->peer.ipv4_address) << 1; 510452c52a61SXin Long mask = (mask | asoc->peer.ipv6_address) << 1; 510552c52a61SXin Long mask = (mask | asoc->peer.hostname_address) << 1; 510652c52a61SXin Long mask = (mask | asoc->peer.asconf_capable) << 1; 510752c52a61SXin Long mask = (mask | asoc->peer.prsctp_capable) << 1; 510852c52a61SXin Long mask = (mask | asoc->peer.auth_capable); 510952c52a61SXin Long info->sctpi_peer_capable = mask; 511052c52a61SXin Long mask = asoc->peer.sack_needed << 1; 511152c52a61SXin Long mask = (mask | asoc->peer.sack_generation) << 1; 511252c52a61SXin Long mask = (mask | asoc->peer.zero_window_announced); 511352c52a61SXin Long info->sctpi_peer_sack = mask; 511452c52a61SXin Long 511552c52a61SXin Long info->sctpi_isacks = asoc->stats.isacks; 511652c52a61SXin Long info->sctpi_osacks = asoc->stats.osacks; 511752c52a61SXin Long info->sctpi_opackets = asoc->stats.opackets; 511852c52a61SXin Long info->sctpi_ipackets = asoc->stats.ipackets; 511952c52a61SXin Long info->sctpi_rtxchunks = asoc->stats.rtxchunks; 512052c52a61SXin Long info->sctpi_outofseqtsns = asoc->stats.outofseqtsns; 512152c52a61SXin Long info->sctpi_idupchunks = asoc->stats.idupchunks; 512252c52a61SXin Long info->sctpi_gapcnt = asoc->stats.gapcnt; 512352c52a61SXin Long info->sctpi_ouodchunks = asoc->stats.ouodchunks; 512452c52a61SXin Long info->sctpi_iuodchunks = asoc->stats.iuodchunks; 512552c52a61SXin Long info->sctpi_oodchunks = asoc->stats.oodchunks; 512652c52a61SXin Long info->sctpi_iodchunks = asoc->stats.iodchunks; 512752c52a61SXin Long info->sctpi_octrlchunks = asoc->stats.octrlchunks; 512852c52a61SXin Long info->sctpi_ictrlchunks = asoc->stats.ictrlchunks; 512952c52a61SXin Long 513052c52a61SXin Long prim = asoc->peer.primary_path; 5131ee6c88bbSStefano Brivio memcpy(&info->sctpi_p_address, &prim->ipaddr, sizeof(prim->ipaddr)); 513252c52a61SXin Long info->sctpi_p_state = prim->state; 513352c52a61SXin Long info->sctpi_p_cwnd = prim->cwnd; 513452c52a61SXin Long info->sctpi_p_srtt = prim->srtt; 513552c52a61SXin Long info->sctpi_p_rto = jiffies_to_msecs(prim->rto); 513652c52a61SXin Long info->sctpi_p_hbinterval = prim->hbinterval; 513752c52a61SXin Long info->sctpi_p_pathmaxrxt = prim->pathmaxrxt; 513852c52a61SXin Long info->sctpi_p_sackdelay = jiffies_to_msecs(prim->sackdelay); 513952c52a61SXin Long info->sctpi_p_ssthresh = prim->ssthresh; 514052c52a61SXin Long info->sctpi_p_partial_bytes_acked = prim->partial_bytes_acked; 514152c52a61SXin Long info->sctpi_p_flight_size = prim->flight_size; 514252c52a61SXin Long info->sctpi_p_error = prim->error_count; 514352c52a61SXin Long 514452c52a61SXin Long return 0; 514552c52a61SXin Long } 514652c52a61SXin Long EXPORT_SYMBOL_GPL(sctp_get_sctp_info); 514752c52a61SXin Long 5148626d16f5SXin Long /* use callback to avoid exporting the core structure */ 51496c72b774SJules Irenge void sctp_transport_walk_start(struct rhashtable_iter *iter) __acquires(RCU) 5150626d16f5SXin Long { 51517fda702fSXin Long rhltable_walk_enter(&sctp_transport_hashtable, iter); 5152626d16f5SXin Long 515397a6ec4aSTom Herbert rhashtable_walk_start(iter); 5154626d16f5SXin Long } 5155626d16f5SXin Long 5156b77b4f63SJules Irenge void sctp_transport_walk_stop(struct rhashtable_iter *iter) __releases(RCU) 5157626d16f5SXin Long { 5158626d16f5SXin Long rhashtable_walk_stop(iter); 5159626d16f5SXin Long rhashtable_walk_exit(iter); 5160626d16f5SXin Long } 5161626d16f5SXin Long 5162626d16f5SXin Long struct sctp_transport *sctp_transport_get_next(struct net *net, 5163626d16f5SXin Long struct rhashtable_iter *iter) 5164626d16f5SXin Long { 5165626d16f5SXin Long struct sctp_transport *t; 5166626d16f5SXin Long 5167626d16f5SXin Long t = rhashtable_walk_next(iter); 5168626d16f5SXin Long for (; t; t = rhashtable_walk_next(iter)) { 5169626d16f5SXin Long if (IS_ERR(t)) { 5170626d16f5SXin Long if (PTR_ERR(t) == -EAGAIN) 5171626d16f5SXin Long continue; 5172626d16f5SXin Long break; 5173626d16f5SXin Long } 5174626d16f5SXin Long 5175bab1be79SXin Long if (!sctp_transport_hold(t)) 5176bab1be79SXin Long continue; 5177bab1be79SXin Long 51784e7696d9SXin Long if (net_eq(t->asoc->base.net, net) && 5179626d16f5SXin Long t->asoc->peer.primary_path == t) 5180626d16f5SXin Long break; 5181bab1be79SXin Long 5182bab1be79SXin Long sctp_transport_put(t); 5183626d16f5SXin Long } 5184626d16f5SXin Long 5185626d16f5SXin Long return t; 5186626d16f5SXin Long } 5187626d16f5SXin Long 5188626d16f5SXin Long struct sctp_transport *sctp_transport_get_idx(struct net *net, 5189626d16f5SXin Long struct rhashtable_iter *iter, 5190626d16f5SXin Long int pos) 5191626d16f5SXin Long { 5192bab1be79SXin Long struct sctp_transport *t; 5193626d16f5SXin Long 5194bab1be79SXin Long if (!pos) 5195bab1be79SXin Long return SEQ_START_TOKEN; 5196626d16f5SXin Long 5197bab1be79SXin Long while ((t = sctp_transport_get_next(net, iter)) && !IS_ERR(t)) { 5198bab1be79SXin Long if (!--pos) 5199bab1be79SXin Long break; 5200bab1be79SXin Long sctp_transport_put(t); 5201bab1be79SXin Long } 5202bab1be79SXin Long 5203bab1be79SXin Long return t; 5204626d16f5SXin Long } 5205626d16f5SXin Long 5206626d16f5SXin Long int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), 5207626d16f5SXin Long void *p) { 5208626d16f5SXin Long int err = 0; 5209626d16f5SXin Long int hash = 0; 5210626d16f5SXin Long struct sctp_ep_common *epb; 5211626d16f5SXin Long struct sctp_hashbucket *head; 5212626d16f5SXin Long 5213626d16f5SXin Long for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize; 5214626d16f5SXin Long hash++, head++) { 5215581409daSXin Long read_lock_bh(&head->lock); 5216626d16f5SXin Long sctp_for_each_hentry(epb, &head->chain) { 5217626d16f5SXin Long err = cb(sctp_ep(epb), p); 5218626d16f5SXin Long if (err) 5219626d16f5SXin Long break; 5220626d16f5SXin Long } 5221581409daSXin Long read_unlock_bh(&head->lock); 5222626d16f5SXin Long } 5223626d16f5SXin Long 5224626d16f5SXin Long return err; 5225626d16f5SXin Long } 5226626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_for_each_endpoint); 5227626d16f5SXin Long 5228626d16f5SXin Long int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *), 5229626d16f5SXin Long struct net *net, 5230626d16f5SXin Long const union sctp_addr *laddr, 5231626d16f5SXin Long const union sctp_addr *paddr, void *p) 5232626d16f5SXin Long { 5233626d16f5SXin Long struct sctp_transport *transport; 523408abb795SXin Long int err; 5235626d16f5SXin Long 5236626d16f5SXin Long rcu_read_lock(); 5237626d16f5SXin Long transport = sctp_addrs_lookup_transport(net, laddr, paddr); 5238626d16f5SXin Long rcu_read_unlock(); 523908abb795SXin Long if (!transport) 524008abb795SXin Long return -ENOENT; 524108abb795SXin Long 52421cceda78SXin Long err = cb(transport, p); 5243cd26da4fSXin Long sctp_transport_put(transport); 52441cceda78SXin Long 5245626d16f5SXin Long return err; 5246626d16f5SXin Long } 5247626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_transport_lookup_process); 5248626d16f5SXin Long 5249626d16f5SXin Long int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *), 5250d25adbebSXin Long int (*cb_done)(struct sctp_transport *, void *), 5251d25adbebSXin Long struct net *net, int *pos, void *p) { 5252626d16f5SXin Long struct rhashtable_iter hti; 5253d25adbebSXin Long struct sctp_transport *tsp; 5254d25adbebSXin Long int ret; 5255626d16f5SXin Long 5256d25adbebSXin Long again: 5257f53d77e1SXin Long ret = 0; 525897a6ec4aSTom Herbert sctp_transport_walk_start(&hti); 5259626d16f5SXin Long 5260d25adbebSXin Long tsp = sctp_transport_get_idx(net, &hti, *pos + 1); 5261d25adbebSXin Long for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) { 5262d25adbebSXin Long ret = cb(tsp, p); 5263d25adbebSXin Long if (ret) 5264626d16f5SXin Long break; 5265d25adbebSXin Long (*pos)++; 5266d25adbebSXin Long sctp_transport_put(tsp); 5267626d16f5SXin Long } 5268626d16f5SXin Long sctp_transport_walk_stop(&hti); 526953fa1036SXin Long 5270d25adbebSXin Long if (ret) { 5271d25adbebSXin Long if (cb_done && !cb_done(tsp, p)) { 5272d25adbebSXin Long (*pos)++; 5273d25adbebSXin Long sctp_transport_put(tsp); 5274d25adbebSXin Long goto again; 5275d25adbebSXin Long } 5276d25adbebSXin Long sctp_transport_put(tsp); 5277d25adbebSXin Long } 5278d25adbebSXin Long 5279d25adbebSXin Long return ret; 5280626d16f5SXin Long } 5281626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_for_each_transport); 5282626d16f5SXin Long 52831da177e4SLinus Torvalds /* 7.2.1 Association Status (SCTP_STATUS) 52841da177e4SLinus Torvalds 52851da177e4SLinus Torvalds * Applications can retrieve current status information about an 52861da177e4SLinus Torvalds * association, including association state, peer receiver window size, 52871da177e4SLinus Torvalds * number of unacked data chunks, and number of data chunks pending 52881da177e4SLinus Torvalds * receipt. This information is read-only. 52891da177e4SLinus Torvalds */ 52901da177e4SLinus Torvalds static int sctp_getsockopt_sctp_status(struct sock *sk, int len, 52911da177e4SLinus Torvalds char __user *optval, 52921da177e4SLinus Torvalds int __user *optlen) 52931da177e4SLinus Torvalds { 52941da177e4SLinus Torvalds struct sctp_status status; 52951da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 52961da177e4SLinus Torvalds struct sctp_transport *transport; 52971da177e4SLinus Torvalds sctp_assoc_t associd; 52981da177e4SLinus Torvalds int retval = 0; 52991da177e4SLinus Torvalds 5300408f22e8SNeil Horman if (len < sizeof(status)) { 53011da177e4SLinus Torvalds retval = -EINVAL; 53021da177e4SLinus Torvalds goto out; 53031da177e4SLinus Torvalds } 53041da177e4SLinus Torvalds 5305408f22e8SNeil Horman len = sizeof(status); 5306408f22e8SNeil Horman if (copy_from_user(&status, optval, len)) { 53071da177e4SLinus Torvalds retval = -EFAULT; 53081da177e4SLinus Torvalds goto out; 53091da177e4SLinus Torvalds } 53101da177e4SLinus Torvalds 53111da177e4SLinus Torvalds associd = status.sstat_assoc_id; 53121da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, associd); 53131da177e4SLinus Torvalds if (!asoc) { 53141da177e4SLinus Torvalds retval = -EINVAL; 53151da177e4SLinus Torvalds goto out; 53161da177e4SLinus Torvalds } 53171da177e4SLinus Torvalds 53181da177e4SLinus Torvalds transport = asoc->peer.primary_path; 53191da177e4SLinus Torvalds 53201da177e4SLinus Torvalds status.sstat_assoc_id = sctp_assoc2id(asoc); 532138ab1fa9SDaniel Borkmann status.sstat_state = sctp_assoc_to_state(asoc); 53221da177e4SLinus Torvalds status.sstat_rwnd = asoc->peer.rwnd; 53231da177e4SLinus Torvalds status.sstat_unackdata = asoc->unack_data; 53241da177e4SLinus Torvalds 53251da177e4SLinus Torvalds status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 5326cee360abSXin Long status.sstat_instrms = asoc->stream.incnt; 5327cee360abSXin Long status.sstat_outstrms = asoc->stream.outcnt; 53281da177e4SLinus Torvalds status.sstat_fragmentation_point = asoc->frag_point; 53291da177e4SLinus Torvalds status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 53308cec6b80SAl Viro memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, 53318cec6b80SAl Viro transport->af_specific->sockaddr_len); 53321da177e4SLinus Torvalds /* Map ipv4 address into v4-mapped-on-v6 address. */ 5333299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), 53341da177e4SLinus Torvalds (union sctp_addr *)&status.sstat_primary.spinfo_address); 53353f7a87d2SFrank Filz status.sstat_primary.spinfo_state = transport->state; 53361da177e4SLinus Torvalds status.sstat_primary.spinfo_cwnd = transport->cwnd; 53371da177e4SLinus Torvalds status.sstat_primary.spinfo_srtt = transport->srtt; 53381da177e4SLinus Torvalds status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto); 533952ccb8e9SFrank Filz status.sstat_primary.spinfo_mtu = transport->pathmtu; 53401da177e4SLinus Torvalds 53413f7a87d2SFrank Filz if (status.sstat_primary.spinfo_state == SCTP_UNKNOWN) 53423f7a87d2SFrank Filz status.sstat_primary.spinfo_state = SCTP_ACTIVE; 53433f7a87d2SFrank Filz 53441da177e4SLinus Torvalds if (put_user(len, optlen)) { 53451da177e4SLinus Torvalds retval = -EFAULT; 53461da177e4SLinus Torvalds goto out; 53471da177e4SLinus Torvalds } 53481da177e4SLinus Torvalds 5349bb33381dSDaniel Borkmann pr_debug("%s: len:%d, state:%d, rwnd:%d, assoc_id:%d\n", 5350bb33381dSDaniel Borkmann __func__, len, status.sstat_state, status.sstat_rwnd, 53511da177e4SLinus Torvalds status.sstat_assoc_id); 53521da177e4SLinus Torvalds 53531da177e4SLinus Torvalds if (copy_to_user(optval, &status, len)) { 53541da177e4SLinus Torvalds retval = -EFAULT; 53551da177e4SLinus Torvalds goto out; 53561da177e4SLinus Torvalds } 53571da177e4SLinus Torvalds 53581da177e4SLinus Torvalds out: 5359a02cec21SEric Dumazet return retval; 53601da177e4SLinus Torvalds } 53611da177e4SLinus Torvalds 53621da177e4SLinus Torvalds 53631da177e4SLinus Torvalds /* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO) 53641da177e4SLinus Torvalds * 53651da177e4SLinus Torvalds * Applications can retrieve information about a specific peer address 53661da177e4SLinus Torvalds * of an association, including its reachability state, congestion 53671da177e4SLinus Torvalds * window, and retransmission timer values. This information is 53681da177e4SLinus Torvalds * read-only. 53691da177e4SLinus Torvalds */ 53701da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, 53711da177e4SLinus Torvalds char __user *optval, 53721da177e4SLinus Torvalds int __user *optlen) 53731da177e4SLinus Torvalds { 53741da177e4SLinus Torvalds struct sctp_paddrinfo pinfo; 53751da177e4SLinus Torvalds struct sctp_transport *transport; 53761da177e4SLinus Torvalds int retval = 0; 53771da177e4SLinus Torvalds 5378408f22e8SNeil Horman if (len < sizeof(pinfo)) { 53791da177e4SLinus Torvalds retval = -EINVAL; 53801da177e4SLinus Torvalds goto out; 53811da177e4SLinus Torvalds } 53821da177e4SLinus Torvalds 5383408f22e8SNeil Horman len = sizeof(pinfo); 5384408f22e8SNeil Horman if (copy_from_user(&pinfo, optval, len)) { 53851da177e4SLinus Torvalds retval = -EFAULT; 53861da177e4SLinus Torvalds goto out; 53871da177e4SLinus Torvalds } 53881da177e4SLinus Torvalds 53891da177e4SLinus Torvalds transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address, 53901da177e4SLinus Torvalds pinfo.spinfo_assoc_id); 5391aef587beSXin Long if (!transport) { 5392aef587beSXin Long retval = -EINVAL; 5393aef587beSXin Long goto out; 5394aef587beSXin Long } 5395aef587beSXin Long 5396aef587beSXin Long if (transport->state == SCTP_PF && 5397aef587beSXin Long transport->asoc->pf_expose == SCTP_PF_EXPOSE_DISABLE) { 5398aef587beSXin Long retval = -EACCES; 5399aef587beSXin Long goto out; 5400aef587beSXin Long } 54011da177e4SLinus Torvalds 54021da177e4SLinus Torvalds pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 54033f7a87d2SFrank Filz pinfo.spinfo_state = transport->state; 54041da177e4SLinus Torvalds pinfo.spinfo_cwnd = transport->cwnd; 54051da177e4SLinus Torvalds pinfo.spinfo_srtt = transport->srtt; 54061da177e4SLinus Torvalds pinfo.spinfo_rto = jiffies_to_msecs(transport->rto); 540752ccb8e9SFrank Filz pinfo.spinfo_mtu = transport->pathmtu; 54081da177e4SLinus Torvalds 54093f7a87d2SFrank Filz if (pinfo.spinfo_state == SCTP_UNKNOWN) 54103f7a87d2SFrank Filz pinfo.spinfo_state = SCTP_ACTIVE; 54113f7a87d2SFrank Filz 54121da177e4SLinus Torvalds if (put_user(len, optlen)) { 54131da177e4SLinus Torvalds retval = -EFAULT; 54141da177e4SLinus Torvalds goto out; 54151da177e4SLinus Torvalds } 54161da177e4SLinus Torvalds 54171da177e4SLinus Torvalds if (copy_to_user(optval, &pinfo, len)) { 54181da177e4SLinus Torvalds retval = -EFAULT; 54191da177e4SLinus Torvalds goto out; 54201da177e4SLinus Torvalds } 54211da177e4SLinus Torvalds 54221da177e4SLinus Torvalds out: 5423a02cec21SEric Dumazet return retval; 54241da177e4SLinus Torvalds } 54251da177e4SLinus Torvalds 54261da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) 54271da177e4SLinus Torvalds * 54281da177e4SLinus Torvalds * This option is a on/off flag. If enabled no SCTP message 54291da177e4SLinus Torvalds * fragmentation will be performed. Instead if a message being sent 54301da177e4SLinus Torvalds * exceeds the current PMTU size, the message will NOT be sent and 54311da177e4SLinus Torvalds * instead a error will be indicated to the user. 54321da177e4SLinus Torvalds */ 54331da177e4SLinus Torvalds static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, 54341da177e4SLinus Torvalds char __user *optval, int __user *optlen) 54351da177e4SLinus Torvalds { 54361da177e4SLinus Torvalds int val; 54371da177e4SLinus Torvalds 54381da177e4SLinus Torvalds if (len < sizeof(int)) 54391da177e4SLinus Torvalds return -EINVAL; 54401da177e4SLinus Torvalds 54411da177e4SLinus Torvalds len = sizeof(int); 54421da177e4SLinus Torvalds val = (sctp_sk(sk)->disable_fragments == 1); 54431da177e4SLinus Torvalds if (put_user(len, optlen)) 54441da177e4SLinus Torvalds return -EFAULT; 54451da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 54461da177e4SLinus Torvalds return -EFAULT; 54471da177e4SLinus Torvalds return 0; 54481da177e4SLinus Torvalds } 54491da177e4SLinus Torvalds 54501da177e4SLinus Torvalds /* 7.1.15 Set notification and ancillary events (SCTP_EVENTS) 54511da177e4SLinus Torvalds * 54521da177e4SLinus Torvalds * This socket option is used to specify various notifications and 54531da177e4SLinus Torvalds * ancillary data the user wishes to receive. 54541da177e4SLinus Torvalds */ 54551da177e4SLinus Torvalds static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, 54561da177e4SLinus Torvalds int __user *optlen) 54571da177e4SLinus Torvalds { 54582cc0eeb6SXin Long struct sctp_event_subscribe subscribe; 54592cc0eeb6SXin Long __u8 *sn_type = (__u8 *)&subscribe; 54602cc0eeb6SXin Long int i; 54612cc0eeb6SXin Long 5462a4b8e71bSJiri Slaby if (len == 0) 54631da177e4SLinus Torvalds return -EINVAL; 5464acdd5985SThomas Graf if (len > sizeof(struct sctp_event_subscribe)) 5465408f22e8SNeil Horman len = sizeof(struct sctp_event_subscribe); 5466408f22e8SNeil Horman if (put_user(len, optlen)) 5467408f22e8SNeil Horman return -EFAULT; 54682cc0eeb6SXin Long 54692cc0eeb6SXin Long for (i = 0; i < len; i++) 54702cc0eeb6SXin Long sn_type[i] = sctp_ulpevent_type_enabled(sctp_sk(sk)->subscribe, 54712cc0eeb6SXin Long SCTP_SN_TYPE_BASE + i); 54722cc0eeb6SXin Long 54732cc0eeb6SXin Long if (copy_to_user(optval, &subscribe, len)) 54741da177e4SLinus Torvalds return -EFAULT; 54752cc0eeb6SXin Long 54761da177e4SLinus Torvalds return 0; 54771da177e4SLinus Torvalds } 54781da177e4SLinus Torvalds 54791da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) 54801da177e4SLinus Torvalds * 54811da177e4SLinus Torvalds * This socket option is applicable to the UDP-style socket only. When 54821da177e4SLinus Torvalds * set it will cause associations that are idle for more than the 54831da177e4SLinus Torvalds * specified number of seconds to automatically close. An association 54841da177e4SLinus Torvalds * being idle is defined an association that has NOT sent or received 54851da177e4SLinus Torvalds * user data. The special value of '0' indicates that no automatic 54861da177e4SLinus Torvalds * close of any associations should be performed. The option expects an 54871da177e4SLinus Torvalds * integer defining the number of seconds of idle time before an 54881da177e4SLinus Torvalds * association is closed. 54891da177e4SLinus Torvalds */ 54901da177e4SLinus Torvalds static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optval, int __user *optlen) 54911da177e4SLinus Torvalds { 54921da177e4SLinus Torvalds /* Applicable to UDP-style socket only */ 54931da177e4SLinus Torvalds if (sctp_style(sk, TCP)) 54941da177e4SLinus Torvalds return -EOPNOTSUPP; 5495408f22e8SNeil Horman if (len < sizeof(int)) 54961da177e4SLinus Torvalds return -EINVAL; 5497408f22e8SNeil Horman len = sizeof(int); 5498408f22e8SNeil Horman if (put_user(len, optlen)) 5499408f22e8SNeil Horman return -EFAULT; 5500b2ce04c2SDavid Windsor if (put_user(sctp_sk(sk)->autoclose, (int __user *)optval)) 55011da177e4SLinus Torvalds return -EFAULT; 55021da177e4SLinus Torvalds return 0; 55031da177e4SLinus Torvalds } 55041da177e4SLinus Torvalds 55051da177e4SLinus Torvalds /* Helper routine to branch off an association to a new socket. */ 55060343c554SBenjamin Poirier int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) 55071da177e4SLinus Torvalds { 55080343c554SBenjamin Poirier struct sctp_association *asoc = sctp_id2assoc(sk, id); 5509299ee123SJason Gunthorpe struct sctp_sock *sp = sctp_sk(sk); 55101da177e4SLinus Torvalds struct socket *sock; 55111da177e4SLinus Torvalds int err = 0; 55121da177e4SLinus Torvalds 5513df80cd9bSXin Long /* Do not peel off from one netns to another one. */ 5514df80cd9bSXin Long if (!net_eq(current->nsproxy->net_ns, sock_net(sk))) 5515df80cd9bSXin Long return -EINVAL; 5516df80cd9bSXin Long 55170343c554SBenjamin Poirier if (!asoc) 55180343c554SBenjamin Poirier return -EINVAL; 55190343c554SBenjamin Poirier 55201da177e4SLinus Torvalds /* An association cannot be branched off from an already peeled-off 55211da177e4SLinus Torvalds * socket, nor is this supported for tcp style sockets. 55221da177e4SLinus Torvalds */ 55231da177e4SLinus Torvalds if (!sctp_style(sk, UDP)) 55241da177e4SLinus Torvalds return -EINVAL; 55251da177e4SLinus Torvalds 55261da177e4SLinus Torvalds /* Create a new socket. */ 55271da177e4SLinus Torvalds err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); 55281da177e4SLinus Torvalds if (err < 0) 55291da177e4SLinus Torvalds return err; 55301da177e4SLinus Torvalds 5531914e1c8bSVlad Yasevich sctp_copy_sock(sock->sk, sk, asoc); 55324f444308SVlad Yasevich 55334f444308SVlad Yasevich /* Make peeled-off sockets more like 1-1 accepted sockets. 5534b7e10c25SRichard Haines * Set the daddr and initialize id to something more random and also 5535b7e10c25SRichard Haines * copy over any ip options. 55364f444308SVlad Yasevich */ 5537299ee123SJason Gunthorpe sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk); 5538b7e10c25SRichard Haines sp->pf->copy_ip_options(sk, sock->sk); 5539914e1c8bSVlad Yasevich 5540914e1c8bSVlad Yasevich /* Populate the fields of the newsk from the oldsk and migrate the 5541914e1c8bSVlad Yasevich * asoc to the newsk. 5542914e1c8bSVlad Yasevich */ 554389664c62SXin Long err = sctp_sock_migrate(sk, sock->sk, asoc, 554489664c62SXin Long SCTP_SOCKET_UDP_HIGH_BANDWIDTH); 554589664c62SXin Long if (err) { 554689664c62SXin Long sock_release(sock); 554789664c62SXin Long sock = NULL; 554889664c62SXin Long } 55494f444308SVlad Yasevich 55501da177e4SLinus Torvalds *sockp = sock; 55511da177e4SLinus Torvalds 55521da177e4SLinus Torvalds return err; 55531da177e4SLinus Torvalds } 55540343c554SBenjamin Poirier EXPORT_SYMBOL(sctp_do_peeloff); 55551da177e4SLinus Torvalds 55562cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *peeloff, 55572cb5c8e3SNeil Horman struct file **newfile, unsigned flags) 55582cb5c8e3SNeil Horman { 55592cb5c8e3SNeil Horman struct socket *newsock; 55602cb5c8e3SNeil Horman int retval; 55612cb5c8e3SNeil Horman 55622cb5c8e3SNeil Horman retval = sctp_do_peeloff(sk, peeloff->associd, &newsock); 55632cb5c8e3SNeil Horman if (retval < 0) 55642cb5c8e3SNeil Horman goto out; 55652cb5c8e3SNeil Horman 55662cb5c8e3SNeil Horman /* Map the socket to an unused fd that can be returned to the user. */ 55672cb5c8e3SNeil Horman retval = get_unused_fd_flags(flags & SOCK_CLOEXEC); 55682cb5c8e3SNeil Horman if (retval < 0) { 55692cb5c8e3SNeil Horman sock_release(newsock); 55702cb5c8e3SNeil Horman goto out; 55712cb5c8e3SNeil Horman } 55722cb5c8e3SNeil Horman 55732cb5c8e3SNeil Horman *newfile = sock_alloc_file(newsock, 0, NULL); 55742cb5c8e3SNeil Horman if (IS_ERR(*newfile)) { 55752cb5c8e3SNeil Horman put_unused_fd(retval); 55762cb5c8e3SNeil Horman retval = PTR_ERR(*newfile); 55772cb5c8e3SNeil Horman *newfile = NULL; 55782cb5c8e3SNeil Horman return retval; 55792cb5c8e3SNeil Horman } 55802cb5c8e3SNeil Horman 55812cb5c8e3SNeil Horman pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk, 55822cb5c8e3SNeil Horman retval); 55832cb5c8e3SNeil Horman 55842cb5c8e3SNeil Horman peeloff->sd = retval; 55852cb5c8e3SNeil Horman 55862cb5c8e3SNeil Horman if (flags & SOCK_NONBLOCK) 55872cb5c8e3SNeil Horman (*newfile)->f_flags |= O_NONBLOCK; 55882cb5c8e3SNeil Horman out: 55892cb5c8e3SNeil Horman return retval; 55902cb5c8e3SNeil Horman } 55912cb5c8e3SNeil Horman 55921da177e4SLinus Torvalds static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) 55931da177e4SLinus Torvalds { 55941da177e4SLinus Torvalds sctp_peeloff_arg_t peeloff; 55952cb5c8e3SNeil Horman struct file *newfile = NULL; 55961da177e4SLinus Torvalds int retval = 0; 55971da177e4SLinus Torvalds 5598408f22e8SNeil Horman if (len < sizeof(sctp_peeloff_arg_t)) 55991da177e4SLinus Torvalds return -EINVAL; 5600408f22e8SNeil Horman len = sizeof(sctp_peeloff_arg_t); 56011da177e4SLinus Torvalds if (copy_from_user(&peeloff, optval, len)) 56021da177e4SLinus Torvalds return -EFAULT; 56031da177e4SLinus Torvalds 56042cb5c8e3SNeil Horman retval = sctp_getsockopt_peeloff_common(sk, &peeloff, &newfile, 0); 56051da177e4SLinus Torvalds if (retval < 0) 56061da177e4SLinus Torvalds goto out; 56071da177e4SLinus Torvalds 56081da177e4SLinus Torvalds /* Return the fd mapped to the new socket. */ 560956b31d1cSAl Viro if (put_user(len, optlen)) { 561056b31d1cSAl Viro fput(newfile); 561156b31d1cSAl Viro put_unused_fd(retval); 5612408f22e8SNeil Horman return -EFAULT; 561356b31d1cSAl Viro } 56142cb5c8e3SNeil Horman 56152cb5c8e3SNeil Horman if (copy_to_user(optval, &peeloff, len)) { 56162cb5c8e3SNeil Horman fput(newfile); 56172cb5c8e3SNeil Horman put_unused_fd(retval); 56182cb5c8e3SNeil Horman return -EFAULT; 56192cb5c8e3SNeil Horman } 56202cb5c8e3SNeil Horman fd_install(retval, newfile); 56212cb5c8e3SNeil Horman out: 56222cb5c8e3SNeil Horman return retval; 56232cb5c8e3SNeil Horman } 56242cb5c8e3SNeil Horman 56252cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len, 56262cb5c8e3SNeil Horman char __user *optval, int __user *optlen) 56272cb5c8e3SNeil Horman { 56282cb5c8e3SNeil Horman sctp_peeloff_flags_arg_t peeloff; 56292cb5c8e3SNeil Horman struct file *newfile = NULL; 56302cb5c8e3SNeil Horman int retval = 0; 56312cb5c8e3SNeil Horman 56322cb5c8e3SNeil Horman if (len < sizeof(sctp_peeloff_flags_arg_t)) 56332cb5c8e3SNeil Horman return -EINVAL; 56342cb5c8e3SNeil Horman len = sizeof(sctp_peeloff_flags_arg_t); 56352cb5c8e3SNeil Horman if (copy_from_user(&peeloff, optval, len)) 56362cb5c8e3SNeil Horman return -EFAULT; 56372cb5c8e3SNeil Horman 56382cb5c8e3SNeil Horman retval = sctp_getsockopt_peeloff_common(sk, &peeloff.p_arg, 56392cb5c8e3SNeil Horman &newfile, peeloff.flags); 56402cb5c8e3SNeil Horman if (retval < 0) 56412cb5c8e3SNeil Horman goto out; 56422cb5c8e3SNeil Horman 56432cb5c8e3SNeil Horman /* Return the fd mapped to the new socket. */ 56442cb5c8e3SNeil Horman if (put_user(len, optlen)) { 56452cb5c8e3SNeil Horman fput(newfile); 56462cb5c8e3SNeil Horman put_unused_fd(retval); 56472cb5c8e3SNeil Horman return -EFAULT; 56482cb5c8e3SNeil Horman } 56492cb5c8e3SNeil Horman 565056b31d1cSAl Viro if (copy_to_user(optval, &peeloff, len)) { 565156b31d1cSAl Viro fput(newfile); 565256b31d1cSAl Viro put_unused_fd(retval); 565356b31d1cSAl Viro return -EFAULT; 565456b31d1cSAl Viro } 565556b31d1cSAl Viro fd_install(retval, newfile); 56561da177e4SLinus Torvalds out: 56571da177e4SLinus Torvalds return retval; 56581da177e4SLinus Torvalds } 56591da177e4SLinus Torvalds 56601da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) 56611da177e4SLinus Torvalds * 56621da177e4SLinus Torvalds * Applications can enable or disable heartbeats for any peer address of 56631da177e4SLinus Torvalds * an association, modify an address's heartbeat interval, force a 56641da177e4SLinus Torvalds * heartbeat to be sent immediately, and adjust the address's maximum 56651da177e4SLinus Torvalds * number of retransmissions sent before an address is considered 56661da177e4SLinus Torvalds * unreachable. The following structure is used to access and modify an 56671da177e4SLinus Torvalds * address's parameters: 56681da177e4SLinus Torvalds * 56691da177e4SLinus Torvalds * struct sctp_paddrparams { 56701da177e4SLinus Torvalds * sctp_assoc_t spp_assoc_id; 56711da177e4SLinus Torvalds * struct sockaddr_storage spp_address; 56721da177e4SLinus Torvalds * uint32_t spp_hbinterval; 56731da177e4SLinus Torvalds * uint16_t spp_pathmaxrxt; 567452ccb8e9SFrank Filz * uint32_t spp_pathmtu; 567552ccb8e9SFrank Filz * uint32_t spp_sackdelay; 567652ccb8e9SFrank Filz * uint32_t spp_flags; 56771da177e4SLinus Torvalds * }; 56781da177e4SLinus Torvalds * 567952ccb8e9SFrank Filz * spp_assoc_id - (one-to-many style socket) This is filled in the 568052ccb8e9SFrank Filz * application, and identifies the association for 568152ccb8e9SFrank Filz * this query. 56821da177e4SLinus Torvalds * spp_address - This specifies which address is of interest. 56831da177e4SLinus Torvalds * spp_hbinterval - This contains the value of the heartbeat interval, 568452ccb8e9SFrank Filz * in milliseconds. If a value of zero 568552ccb8e9SFrank Filz * is present in this field then no changes are to 568652ccb8e9SFrank Filz * be made to this parameter. 56871da177e4SLinus Torvalds * spp_pathmaxrxt - This contains the maximum number of 56881da177e4SLinus Torvalds * retransmissions before this address shall be 568952ccb8e9SFrank Filz * considered unreachable. If a value of zero 569052ccb8e9SFrank Filz * is present in this field then no changes are to 569152ccb8e9SFrank Filz * be made to this parameter. 569252ccb8e9SFrank Filz * spp_pathmtu - When Path MTU discovery is disabled the value 569352ccb8e9SFrank Filz * specified here will be the "fixed" path mtu. 569452ccb8e9SFrank Filz * Note that if the spp_address field is empty 569552ccb8e9SFrank Filz * then all associations on this address will 569652ccb8e9SFrank Filz * have this fixed path mtu set upon them. 569752ccb8e9SFrank Filz * 569852ccb8e9SFrank Filz * spp_sackdelay - When delayed sack is enabled, this value specifies 569952ccb8e9SFrank Filz * the number of milliseconds that sacks will be delayed 570052ccb8e9SFrank Filz * for. This value will apply to all addresses of an 570152ccb8e9SFrank Filz * association if the spp_address field is empty. Note 570252ccb8e9SFrank Filz * also, that if delayed sack is enabled and this 570352ccb8e9SFrank Filz * value is set to 0, no change is made to the last 570452ccb8e9SFrank Filz * recorded delayed sack timer value. 570552ccb8e9SFrank Filz * 570652ccb8e9SFrank Filz * spp_flags - These flags are used to control various features 570752ccb8e9SFrank Filz * on an association. The flag field may contain 570852ccb8e9SFrank Filz * zero or more of the following options. 570952ccb8e9SFrank Filz * 571052ccb8e9SFrank Filz * SPP_HB_ENABLE - Enable heartbeats on the 571152ccb8e9SFrank Filz * specified address. Note that if the address 571252ccb8e9SFrank Filz * field is empty all addresses for the association 571352ccb8e9SFrank Filz * have heartbeats enabled upon them. 571452ccb8e9SFrank Filz * 571552ccb8e9SFrank Filz * SPP_HB_DISABLE - Disable heartbeats on the 571652ccb8e9SFrank Filz * speicifed address. Note that if the address 571752ccb8e9SFrank Filz * field is empty all addresses for the association 571852ccb8e9SFrank Filz * will have their heartbeats disabled. Note also 571952ccb8e9SFrank Filz * that SPP_HB_ENABLE and SPP_HB_DISABLE are 572052ccb8e9SFrank Filz * mutually exclusive, only one of these two should 572152ccb8e9SFrank Filz * be specified. Enabling both fields will have 572252ccb8e9SFrank Filz * undetermined results. 572352ccb8e9SFrank Filz * 572452ccb8e9SFrank Filz * SPP_HB_DEMAND - Request a user initiated heartbeat 572552ccb8e9SFrank Filz * to be made immediately. 572652ccb8e9SFrank Filz * 572752ccb8e9SFrank Filz * SPP_PMTUD_ENABLE - This field will enable PMTU 572852ccb8e9SFrank Filz * discovery upon the specified address. Note that 572952ccb8e9SFrank Filz * if the address feild is empty then all addresses 573052ccb8e9SFrank Filz * on the association are effected. 573152ccb8e9SFrank Filz * 573252ccb8e9SFrank Filz * SPP_PMTUD_DISABLE - This field will disable PMTU 573352ccb8e9SFrank Filz * discovery upon the specified address. Note that 573452ccb8e9SFrank Filz * if the address feild is empty then all addresses 573552ccb8e9SFrank Filz * on the association are effected. Not also that 573652ccb8e9SFrank Filz * SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually 573752ccb8e9SFrank Filz * exclusive. Enabling both will have undetermined 573852ccb8e9SFrank Filz * results. 573952ccb8e9SFrank Filz * 574052ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE - Setting this flag turns 574152ccb8e9SFrank Filz * on delayed sack. The time specified in spp_sackdelay 574252ccb8e9SFrank Filz * is used to specify the sack delay for this address. Note 574352ccb8e9SFrank Filz * that if spp_address is empty then all addresses will 574452ccb8e9SFrank Filz * enable delayed sack and take on the sack delay 574552ccb8e9SFrank Filz * value specified in spp_sackdelay. 574652ccb8e9SFrank Filz * SPP_SACKDELAY_DISABLE - Setting this flag turns 574752ccb8e9SFrank Filz * off delayed sack. If the spp_address field is blank then 574852ccb8e9SFrank Filz * delayed sack is disabled for the entire association. Note 574952ccb8e9SFrank Filz * also that this field is mutually exclusive to 575052ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE, setting both will have undefined 575152ccb8e9SFrank Filz * results. 57520b0dce7aSXin Long * 57530b0dce7aSXin Long * SPP_IPV6_FLOWLABEL: Setting this flag enables the 57540b0dce7aSXin Long * setting of the IPV6 flow label value. The value is 57550b0dce7aSXin Long * contained in the spp_ipv6_flowlabel field. 57560b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 57570b0dce7aSXin Long * the spp_ipv6_flowlabel field has a valid value returned. 57580b0dce7aSXin Long * If a specific destination address is set (in the 57590b0dce7aSXin Long * spp_address field), then the value returned is that of 57600b0dce7aSXin Long * the address. If just an association is specified (and 57610b0dce7aSXin Long * no address), then the association's default flow label 57620b0dce7aSXin Long * is returned. If neither an association nor a destination 57630b0dce7aSXin Long * is specified, then the socket's default flow label is 57640b0dce7aSXin Long * returned. For non-IPv6 sockets, this flag will be left 57650b0dce7aSXin Long * cleared. 57660b0dce7aSXin Long * 57670b0dce7aSXin Long * SPP_DSCP: Setting this flag enables the setting of the 57680b0dce7aSXin Long * Differentiated Services Code Point (DSCP) value 57690b0dce7aSXin Long * associated with either the association or a specific 57700b0dce7aSXin Long * address. The value is obtained in the spp_dscp field. 57710b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 57720b0dce7aSXin Long * the spp_dscp field has a valid value returned. If a 57730b0dce7aSXin Long * specific destination address is set when called (in the 57740b0dce7aSXin Long * spp_address field), then that specific destination 57750b0dce7aSXin Long * address's DSCP value is returned. If just an association 57760b0dce7aSXin Long * is specified, then the association's default DSCP is 57770b0dce7aSXin Long * returned. If neither an association nor a destination is 57780b0dce7aSXin Long * specified, then the socket's default DSCP is returned. 57790b0dce7aSXin Long * 57800b0dce7aSXin Long * spp_ipv6_flowlabel 57810b0dce7aSXin Long * - This field is used in conjunction with the 57820b0dce7aSXin Long * SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label. 57830b0dce7aSXin Long * The 20 least significant bits are used for the flow 57840b0dce7aSXin Long * label. This setting has precedence over any IPv6-layer 57850b0dce7aSXin Long * setting. 57860b0dce7aSXin Long * 57870b0dce7aSXin Long * spp_dscp - This field is used in conjunction with the SPP_DSCP flag 57880b0dce7aSXin Long * and contains the DSCP. The 6 most significant bits are 57890b0dce7aSXin Long * used for the DSCP. This setting has precedence over any 57900b0dce7aSXin Long * IPv4- or IPv6- layer setting. 57911da177e4SLinus Torvalds */ 57921da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, 57931da177e4SLinus Torvalds char __user *optval, int __user *optlen) 57941da177e4SLinus Torvalds { 57951da177e4SLinus Torvalds struct sctp_paddrparams params; 579652ccb8e9SFrank Filz struct sctp_transport *trans = NULL; 579752ccb8e9SFrank Filz struct sctp_association *asoc = NULL; 579852ccb8e9SFrank Filz struct sctp_sock *sp = sctp_sk(sk); 57991da177e4SLinus Torvalds 58000b0dce7aSXin Long if (len >= sizeof(params)) 58010b0dce7aSXin Long len = sizeof(params); 58020b0dce7aSXin Long else if (len >= ALIGN(offsetof(struct sctp_paddrparams, 58030b0dce7aSXin Long spp_ipv6_flowlabel), 4)) 58040b0dce7aSXin Long len = ALIGN(offsetof(struct sctp_paddrparams, 58050b0dce7aSXin Long spp_ipv6_flowlabel), 4); 58060b0dce7aSXin Long else 58071da177e4SLinus Torvalds return -EINVAL; 58080b0dce7aSXin Long 58091da177e4SLinus Torvalds if (copy_from_user(¶ms, optval, len)) 58101da177e4SLinus Torvalds return -EFAULT; 58111da177e4SLinus Torvalds 581252ccb8e9SFrank Filz /* If an address other than INADDR_ANY is specified, and 581352ccb8e9SFrank Filz * no transport is found, then the request is invalid. 58141da177e4SLinus Torvalds */ 581552cae8f0SVlad Yasevich if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { 58161da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, ¶ms.spp_address, 58171da177e4SLinus Torvalds params.spp_assoc_id); 581852ccb8e9SFrank Filz if (!trans) { 5819bb33381dSDaniel Borkmann pr_debug("%s: failed no transport\n", __func__); 58201da177e4SLinus Torvalds return -EINVAL; 582152ccb8e9SFrank Filz } 582252ccb8e9SFrank Filz } 58231da177e4SLinus Torvalds 5824b99e5e02SXin Long /* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the 5825b99e5e02SXin Long * socket is a one to many style socket, and an association 5826b99e5e02SXin Long * was not found, then the id was invalid. 58271da177e4SLinus Torvalds */ 582852ccb8e9SFrank Filz asoc = sctp_id2assoc(sk, params.spp_assoc_id); 5829b99e5e02SXin Long if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC && 5830b99e5e02SXin Long sctp_style(sk, UDP)) { 5831bb33381dSDaniel Borkmann pr_debug("%s: failed no association\n", __func__); 583252ccb8e9SFrank Filz return -EINVAL; 583352ccb8e9SFrank Filz } 58341da177e4SLinus Torvalds 583552ccb8e9SFrank Filz if (trans) { 583652ccb8e9SFrank Filz /* Fetch transport values. */ 583752ccb8e9SFrank Filz params.spp_hbinterval = jiffies_to_msecs(trans->hbinterval); 583852ccb8e9SFrank Filz params.spp_pathmtu = trans->pathmtu; 583952ccb8e9SFrank Filz params.spp_pathmaxrxt = trans->pathmaxrxt; 584052ccb8e9SFrank Filz params.spp_sackdelay = jiffies_to_msecs(trans->sackdelay); 58411da177e4SLinus Torvalds 584252ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 584352ccb8e9SFrank Filz params.spp_flags = trans->param_flags; 58440b0dce7aSXin Long if (trans->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 58450b0dce7aSXin Long params.spp_ipv6_flowlabel = trans->flowlabel & 58460b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 58470b0dce7aSXin Long params.spp_flags |= SPP_IPV6_FLOWLABEL; 58480b0dce7aSXin Long } 58490b0dce7aSXin Long if (trans->dscp & SCTP_DSCP_SET_MASK) { 58500b0dce7aSXin Long params.spp_dscp = trans->dscp & SCTP_DSCP_VAL_MASK; 58510b0dce7aSXin Long params.spp_flags |= SPP_DSCP; 58520b0dce7aSXin Long } 585352ccb8e9SFrank Filz } else if (asoc) { 585452ccb8e9SFrank Filz /* Fetch association values. */ 585552ccb8e9SFrank Filz params.spp_hbinterval = jiffies_to_msecs(asoc->hbinterval); 585652ccb8e9SFrank Filz params.spp_pathmtu = asoc->pathmtu; 585752ccb8e9SFrank Filz params.spp_pathmaxrxt = asoc->pathmaxrxt; 585852ccb8e9SFrank Filz params.spp_sackdelay = jiffies_to_msecs(asoc->sackdelay); 585952ccb8e9SFrank Filz 586052ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 586152ccb8e9SFrank Filz params.spp_flags = asoc->param_flags; 58620b0dce7aSXin Long if (asoc->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 58630b0dce7aSXin Long params.spp_ipv6_flowlabel = asoc->flowlabel & 58640b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 58650b0dce7aSXin Long params.spp_flags |= SPP_IPV6_FLOWLABEL; 58660b0dce7aSXin Long } 58670b0dce7aSXin Long if (asoc->dscp & SCTP_DSCP_SET_MASK) { 58680b0dce7aSXin Long params.spp_dscp = asoc->dscp & SCTP_DSCP_VAL_MASK; 58690b0dce7aSXin Long params.spp_flags |= SPP_DSCP; 58700b0dce7aSXin Long } 587152ccb8e9SFrank Filz } else { 587252ccb8e9SFrank Filz /* Fetch socket values. */ 587352ccb8e9SFrank Filz params.spp_hbinterval = sp->hbinterval; 587452ccb8e9SFrank Filz params.spp_pathmtu = sp->pathmtu; 587552ccb8e9SFrank Filz params.spp_sackdelay = sp->sackdelay; 587652ccb8e9SFrank Filz params.spp_pathmaxrxt = sp->pathmaxrxt; 587752ccb8e9SFrank Filz 587852ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 587952ccb8e9SFrank Filz params.spp_flags = sp->param_flags; 58800b0dce7aSXin Long if (sp->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 58810b0dce7aSXin Long params.spp_ipv6_flowlabel = sp->flowlabel & 58820b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 58830b0dce7aSXin Long params.spp_flags |= SPP_IPV6_FLOWLABEL; 58840b0dce7aSXin Long } 58850b0dce7aSXin Long if (sp->dscp & SCTP_DSCP_SET_MASK) { 58860b0dce7aSXin Long params.spp_dscp = sp->dscp & SCTP_DSCP_VAL_MASK; 58870b0dce7aSXin Long params.spp_flags |= SPP_DSCP; 58880b0dce7aSXin Long } 588952ccb8e9SFrank Filz } 589052ccb8e9SFrank Filz 58911da177e4SLinus Torvalds if (copy_to_user(optval, ¶ms, len)) 58921da177e4SLinus Torvalds return -EFAULT; 58931da177e4SLinus Torvalds 58941da177e4SLinus Torvalds if (put_user(len, optlen)) 58951da177e4SLinus Torvalds return -EFAULT; 58961da177e4SLinus Torvalds 58971da177e4SLinus Torvalds return 0; 58981da177e4SLinus Torvalds } 58991da177e4SLinus Torvalds 5900d364d927SWei Yongjun /* 5901d364d927SWei Yongjun * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 59027708610bSFrank Filz * 5903d364d927SWei Yongjun * This option will effect the way delayed acks are performed. This 5904d364d927SWei Yongjun * option allows you to get or set the delayed ack time, in 5905d364d927SWei Yongjun * milliseconds. It also allows changing the delayed ack frequency. 5906d364d927SWei Yongjun * Changing the frequency to 1 disables the delayed sack algorithm. If 5907d364d927SWei Yongjun * the assoc_id is 0, then this sets or gets the endpoints default 5908d364d927SWei Yongjun * values. If the assoc_id field is non-zero, then the set or get 5909d364d927SWei Yongjun * effects the specified association for the one to many model (the 5910d364d927SWei Yongjun * assoc_id field is ignored by the one to one model). Note that if 5911d364d927SWei Yongjun * sack_delay or sack_freq are 0 when setting this option, then the 5912d364d927SWei Yongjun * current values will remain unchanged. 59137708610bSFrank Filz * 5914d364d927SWei Yongjun * struct sctp_sack_info { 5915d364d927SWei Yongjun * sctp_assoc_t sack_assoc_id; 5916d364d927SWei Yongjun * uint32_t sack_delay; 5917d364d927SWei Yongjun * uint32_t sack_freq; 59187708610bSFrank Filz * }; 59197708610bSFrank Filz * 5920d364d927SWei Yongjun * sack_assoc_id - This parameter, indicates which association the user 5921d364d927SWei Yongjun * is performing an action upon. Note that if this field's value is 5922d364d927SWei Yongjun * zero then the endpoints default value is changed (effecting future 59237708610bSFrank Filz * associations only). 59247708610bSFrank Filz * 5925d364d927SWei Yongjun * sack_delay - This parameter contains the number of milliseconds that 5926d364d927SWei Yongjun * the user is requesting the delayed ACK timer be set to. Note that 5927d364d927SWei Yongjun * this value is defined in the standard to be between 200 and 500 5928d364d927SWei Yongjun * milliseconds. 59297708610bSFrank Filz * 5930d364d927SWei Yongjun * sack_freq - This parameter contains the number of packets that must 5931d364d927SWei Yongjun * be received before a sack is sent without waiting for the delay 5932d364d927SWei Yongjun * timer to expire. The default value for this is 2, setting this 5933d364d927SWei Yongjun * value to 1 will disable the delayed sack algorithm. 59347708610bSFrank Filz */ 5935d364d927SWei Yongjun static int sctp_getsockopt_delayed_ack(struct sock *sk, int len, 59367708610bSFrank Filz char __user *optval, 59377708610bSFrank Filz int __user *optlen) 59387708610bSFrank Filz { 5939d364d927SWei Yongjun struct sctp_sack_info params; 59407708610bSFrank Filz struct sctp_association *asoc = NULL; 59417708610bSFrank Filz struct sctp_sock *sp = sctp_sk(sk); 59427708610bSFrank Filz 5943d364d927SWei Yongjun if (len >= sizeof(struct sctp_sack_info)) { 5944d364d927SWei Yongjun len = sizeof(struct sctp_sack_info); 5945408f22e8SNeil Horman 59467708610bSFrank Filz if (copy_from_user(¶ms, optval, len)) 59477708610bSFrank Filz return -EFAULT; 5948d364d927SWei Yongjun } else if (len == sizeof(struct sctp_assoc_value)) { 594994f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 5950f916ec96SNeil Horman "%s (pid %d) " 595194f65193SNeil Horman "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 5952f916ec96SNeil Horman "Use struct sctp_sack_info instead\n", 5953f916ec96SNeil Horman current->comm, task_pid_nr(current)); 5954d364d927SWei Yongjun if (copy_from_user(¶ms, optval, len)) 5955d364d927SWei Yongjun return -EFAULT; 5956d364d927SWei Yongjun } else 5957d364d927SWei Yongjun return -EINVAL; 59587708610bSFrank Filz 59599c5829e1SXin Long /* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the 59609c5829e1SXin Long * socket is a one to many style socket, and an association 59619c5829e1SXin Long * was not found, then the id was invalid. 59627708610bSFrank Filz */ 5963d364d927SWei Yongjun asoc = sctp_id2assoc(sk, params.sack_assoc_id); 59649c5829e1SXin Long if (!asoc && params.sack_assoc_id != SCTP_FUTURE_ASSOC && 59659c5829e1SXin Long sctp_style(sk, UDP)) 59667708610bSFrank Filz return -EINVAL; 59677708610bSFrank Filz 59687708610bSFrank Filz if (asoc) { 59697708610bSFrank Filz /* Fetch association values. */ 5970d364d927SWei Yongjun if (asoc->param_flags & SPP_SACKDELAY_ENABLE) { 59719c5829e1SXin Long params.sack_delay = jiffies_to_msecs(asoc->sackdelay); 5972d364d927SWei Yongjun params.sack_freq = asoc->sackfreq; 5973d364d927SWei Yongjun 5974d364d927SWei Yongjun } else { 5975d364d927SWei Yongjun params.sack_delay = 0; 5976d364d927SWei Yongjun params.sack_freq = 1; 5977d364d927SWei Yongjun } 59787708610bSFrank Filz } else { 59797708610bSFrank Filz /* Fetch socket values. */ 5980d364d927SWei Yongjun if (sp->param_flags & SPP_SACKDELAY_ENABLE) { 5981d364d927SWei Yongjun params.sack_delay = sp->sackdelay; 5982d364d927SWei Yongjun params.sack_freq = sp->sackfreq; 5983d364d927SWei Yongjun } else { 5984d364d927SWei Yongjun params.sack_delay = 0; 5985d364d927SWei Yongjun params.sack_freq = 1; 5986d364d927SWei Yongjun } 59877708610bSFrank Filz } 59887708610bSFrank Filz 59897708610bSFrank Filz if (copy_to_user(optval, ¶ms, len)) 59907708610bSFrank Filz return -EFAULT; 59917708610bSFrank Filz 59927708610bSFrank Filz if (put_user(len, optlen)) 59937708610bSFrank Filz return -EFAULT; 59947708610bSFrank Filz 59957708610bSFrank Filz return 0; 59967708610bSFrank Filz } 59977708610bSFrank Filz 59981da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG) 59991da177e4SLinus Torvalds * 60001da177e4SLinus Torvalds * Applications can specify protocol parameters for the default association 60011da177e4SLinus Torvalds * initialization. The option name argument to setsockopt() and getsockopt() 60021da177e4SLinus Torvalds * is SCTP_INITMSG. 60031da177e4SLinus Torvalds * 60041da177e4SLinus Torvalds * Setting initialization parameters is effective only on an unconnected 60051da177e4SLinus Torvalds * socket (for UDP-style sockets only future associations are effected 60061da177e4SLinus Torvalds * by the change). With TCP-style sockets, this option is inherited by 60071da177e4SLinus Torvalds * sockets derived from a listener socket. 60081da177e4SLinus Torvalds */ 60091da177e4SLinus Torvalds static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen) 60101da177e4SLinus Torvalds { 6011408f22e8SNeil Horman if (len < sizeof(struct sctp_initmsg)) 60121da177e4SLinus Torvalds return -EINVAL; 6013408f22e8SNeil Horman len = sizeof(struct sctp_initmsg); 6014408f22e8SNeil Horman if (put_user(len, optlen)) 6015408f22e8SNeil Horman return -EFAULT; 60161da177e4SLinus Torvalds if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len)) 60171da177e4SLinus Torvalds return -EFAULT; 60181da177e4SLinus Torvalds return 0; 60191da177e4SLinus Torvalds } 60201da177e4SLinus Torvalds 60211da177e4SLinus Torvalds 60225fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, 60235fe467eeSIvan Skytte Jørgensen char __user *optval, int __user *optlen) 60245fe467eeSIvan Skytte Jørgensen { 60255fe467eeSIvan Skytte Jørgensen struct sctp_association *asoc; 60265fe467eeSIvan Skytte Jørgensen int cnt = 0; 60275fe467eeSIvan Skytte Jørgensen struct sctp_getaddrs getaddrs; 60285fe467eeSIvan Skytte Jørgensen struct sctp_transport *from; 60295fe467eeSIvan Skytte Jørgensen void __user *to; 60305fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 60315fe467eeSIvan Skytte Jørgensen struct sctp_sock *sp = sctp_sk(sk); 60325fe467eeSIvan Skytte Jørgensen int addrlen; 60335fe467eeSIvan Skytte Jørgensen size_t space_left; 60345fe467eeSIvan Skytte Jørgensen int bytes_copied; 60355fe467eeSIvan Skytte Jørgensen 60365fe467eeSIvan Skytte Jørgensen if (len < sizeof(struct sctp_getaddrs)) 60375fe467eeSIvan Skytte Jørgensen return -EINVAL; 60385fe467eeSIvan Skytte Jørgensen 60395fe467eeSIvan Skytte Jørgensen if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 60405fe467eeSIvan Skytte Jørgensen return -EFAULT; 60415fe467eeSIvan Skytte Jørgensen 60425fe467eeSIvan Skytte Jørgensen /* For UDP-style sockets, id specifies the association to query. */ 60435fe467eeSIvan Skytte Jørgensen asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 60445fe467eeSIvan Skytte Jørgensen if (!asoc) 60455fe467eeSIvan Skytte Jørgensen return -EINVAL; 60465fe467eeSIvan Skytte Jørgensen 60475fe467eeSIvan Skytte Jørgensen to = optval + offsetof(struct sctp_getaddrs, addrs); 6048186e2343SNeil Horman space_left = len - offsetof(struct sctp_getaddrs, addrs); 60495fe467eeSIvan Skytte Jørgensen 60509dbc15f0SRobert P. J. Day list_for_each_entry(from, &asoc->peer.transport_addr_list, 60519dbc15f0SRobert P. J. Day transports) { 6052b3f5b3b6SAl Viro memcpy(&temp, &from->ipaddr, sizeof(temp)); 6053299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 6054299ee123SJason Gunthorpe ->addr_to_user(sp, &temp); 60555fe467eeSIvan Skytte Jørgensen if (space_left < addrlen) 60565fe467eeSIvan Skytte Jørgensen return -ENOMEM; 60575fe467eeSIvan Skytte Jørgensen if (copy_to_user(to, &temp, addrlen)) 60585fe467eeSIvan Skytte Jørgensen return -EFAULT; 60595fe467eeSIvan Skytte Jørgensen to += addrlen; 60605fe467eeSIvan Skytte Jørgensen cnt++; 60615fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 60625fe467eeSIvan Skytte Jørgensen } 60635fe467eeSIvan Skytte Jørgensen 60645fe467eeSIvan Skytte Jørgensen if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) 60655fe467eeSIvan Skytte Jørgensen return -EFAULT; 60665fe467eeSIvan Skytte Jørgensen bytes_copied = ((char __user *)to) - optval; 60675fe467eeSIvan Skytte Jørgensen if (put_user(bytes_copied, optlen)) 60685fe467eeSIvan Skytte Jørgensen return -EFAULT; 60695fe467eeSIvan Skytte Jørgensen 60705fe467eeSIvan Skytte Jørgensen return 0; 60715fe467eeSIvan Skytte Jørgensen } 60725fe467eeSIvan Skytte Jørgensen 6073aad97f38SVlad Yasevich static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, 6074aad97f38SVlad Yasevich size_t space_left, int *bytes_copied) 60755fe467eeSIvan Skytte Jørgensen { 60765fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry *addr; 60775fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 60785fe467eeSIvan Skytte Jørgensen int cnt = 0; 60795fe467eeSIvan Skytte Jørgensen int addrlen; 60804db67e80SEric W. Biederman struct net *net = sock_net(sk); 60815fe467eeSIvan Skytte Jørgensen 608229303547SVlad Yasevich rcu_read_lock(); 60834db67e80SEric W. Biederman list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) { 608429303547SVlad Yasevich if (!addr->valid) 608529303547SVlad Yasevich continue; 608629303547SVlad Yasevich 60875fe467eeSIvan Skytte Jørgensen if ((PF_INET == sk->sk_family) && 60886244be4eSAl Viro (AF_INET6 == addr->a.sa.sa_family)) 60895fe467eeSIvan Skytte Jørgensen continue; 60907dab83deSVlad Yasevich if ((PF_INET6 == sk->sk_family) && 60917dab83deSVlad Yasevich inet_v6_ipv6only(sk) && 60927dab83deSVlad Yasevich (AF_INET == addr->a.sa.sa_family)) 60937dab83deSVlad Yasevich continue; 60946244be4eSAl Viro memcpy(&temp, &addr->a, sizeof(temp)); 6095b46ae36dSVlad Yasevich if (!temp.v4.sin_port) 6096b46ae36dSVlad Yasevich temp.v4.sin_port = htons(port); 6097b46ae36dSVlad Yasevich 6098299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 6099299ee123SJason Gunthorpe ->addr_to_user(sctp_sk(sk), &temp); 6100299ee123SJason Gunthorpe 610129303547SVlad Yasevich if (space_left < addrlen) { 610229303547SVlad Yasevich cnt = -ENOMEM; 610329303547SVlad Yasevich break; 610429303547SVlad Yasevich } 6105aad97f38SVlad Yasevich memcpy(to, &temp, addrlen); 610629c7cf96SSridhar Samudrala 6107aad97f38SVlad Yasevich to += addrlen; 61085fe467eeSIvan Skytte Jørgensen cnt++; 61095fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 61103663c306SVlad Yasevich *bytes_copied += addrlen; 61115fe467eeSIvan Skytte Jørgensen } 611229303547SVlad Yasevich rcu_read_unlock(); 61135fe467eeSIvan Skytte Jørgensen 61145fe467eeSIvan Skytte Jørgensen return cnt; 61155fe467eeSIvan Skytte Jørgensen } 61165fe467eeSIvan Skytte Jørgensen 61171da177e4SLinus Torvalds 61185fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_local_addrs(struct sock *sk, int len, 61195fe467eeSIvan Skytte Jørgensen char __user *optval, int __user *optlen) 61205fe467eeSIvan Skytte Jørgensen { 61215fe467eeSIvan Skytte Jørgensen struct sctp_bind_addr *bp; 61225fe467eeSIvan Skytte Jørgensen struct sctp_association *asoc; 61235fe467eeSIvan Skytte Jørgensen int cnt = 0; 61245fe467eeSIvan Skytte Jørgensen struct sctp_getaddrs getaddrs; 61255fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry *addr; 61265fe467eeSIvan Skytte Jørgensen void __user *to; 61275fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 61285fe467eeSIvan Skytte Jørgensen struct sctp_sock *sp = sctp_sk(sk); 61295fe467eeSIvan Skytte Jørgensen int addrlen; 61305fe467eeSIvan Skytte Jørgensen int err = 0; 61315fe467eeSIvan Skytte Jørgensen size_t space_left; 6132aad97f38SVlad Yasevich int bytes_copied = 0; 6133aad97f38SVlad Yasevich void *addrs; 613470b57b81SVlad Yasevich void *buf; 61355fe467eeSIvan Skytte Jørgensen 6136408f22e8SNeil Horman if (len < sizeof(struct sctp_getaddrs)) 61375fe467eeSIvan Skytte Jørgensen return -EINVAL; 61385fe467eeSIvan Skytte Jørgensen 61395fe467eeSIvan Skytte Jørgensen if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 61405fe467eeSIvan Skytte Jørgensen return -EFAULT; 61415fe467eeSIvan Skytte Jørgensen 61425fe467eeSIvan Skytte Jørgensen /* 61435fe467eeSIvan Skytte Jørgensen * For UDP-style sockets, id specifies the association to query. 61445fe467eeSIvan Skytte Jørgensen * If the id field is set to the value '0' then the locally bound 61455fe467eeSIvan Skytte Jørgensen * addresses are returned without regard to any particular 61465fe467eeSIvan Skytte Jørgensen * association. 61475fe467eeSIvan Skytte Jørgensen */ 61485fe467eeSIvan Skytte Jørgensen if (0 == getaddrs.assoc_id) { 61495fe467eeSIvan Skytte Jørgensen bp = &sctp_sk(sk)->ep->base.bind_addr; 61505fe467eeSIvan Skytte Jørgensen } else { 61515fe467eeSIvan Skytte Jørgensen asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 61525fe467eeSIvan Skytte Jørgensen if (!asoc) 61535fe467eeSIvan Skytte Jørgensen return -EINVAL; 61545fe467eeSIvan Skytte Jørgensen bp = &asoc->base.bind_addr; 61555fe467eeSIvan Skytte Jørgensen } 61565fe467eeSIvan Skytte Jørgensen 61575fe467eeSIvan Skytte Jørgensen to = optval + offsetof(struct sctp_getaddrs, addrs); 6158186e2343SNeil Horman space_left = len - offsetof(struct sctp_getaddrs, addrs); 6159186e2343SNeil Horman 6160cacc0621SMarcelo Ricardo Leitner addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN); 6161aad97f38SVlad Yasevich if (!addrs) 6162aad97f38SVlad Yasevich return -ENOMEM; 61635fe467eeSIvan Skytte Jørgensen 61645fe467eeSIvan Skytte Jørgensen /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid 61655fe467eeSIvan Skytte Jørgensen * addresses from the global local address list. 61665fe467eeSIvan Skytte Jørgensen */ 61675fe467eeSIvan Skytte Jørgensen if (sctp_list_single_entry(&bp->address_list)) { 61685fe467eeSIvan Skytte Jørgensen addr = list_entry(bp->address_list.next, 61695fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry, list); 617052cae8f0SVlad Yasevich if (sctp_is_any(sk, &addr->a)) { 6171aad97f38SVlad Yasevich cnt = sctp_copy_laddrs(sk, bp->port, addrs, 6172aad97f38SVlad Yasevich space_left, &bytes_copied); 61735fe467eeSIvan Skytte Jørgensen if (cnt < 0) { 61745fe467eeSIvan Skytte Jørgensen err = cnt; 6175559cf710SVlad Yasevich goto out; 61765fe467eeSIvan Skytte Jørgensen } 61775fe467eeSIvan Skytte Jørgensen goto copy_getaddrs; 61785fe467eeSIvan Skytte Jørgensen } 61795fe467eeSIvan Skytte Jørgensen } 61805fe467eeSIvan Skytte Jørgensen 618170b57b81SVlad Yasevich buf = addrs; 6182559cf710SVlad Yasevich /* Protection on the bound address list is not needed since 6183559cf710SVlad Yasevich * in the socket option context we hold a socket lock and 6184559cf710SVlad Yasevich * thus the bound address list can't change. 6185559cf710SVlad Yasevich */ 6186559cf710SVlad Yasevich list_for_each_entry(addr, &bp->address_list, list) { 61876244be4eSAl Viro memcpy(&temp, &addr->a, sizeof(temp)); 6188299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 6189299ee123SJason Gunthorpe ->addr_to_user(sp, &temp); 6190aad97f38SVlad Yasevich if (space_left < addrlen) { 6191aad97f38SVlad Yasevich err = -ENOMEM; /*fixme: right error?*/ 6192559cf710SVlad Yasevich goto out; 61935fe467eeSIvan Skytte Jørgensen } 619470b57b81SVlad Yasevich memcpy(buf, &temp, addrlen); 619570b57b81SVlad Yasevich buf += addrlen; 6196aad97f38SVlad Yasevich bytes_copied += addrlen; 61975fe467eeSIvan Skytte Jørgensen cnt++; 61985fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 61995fe467eeSIvan Skytte Jørgensen } 62005fe467eeSIvan Skytte Jørgensen 62015fe467eeSIvan Skytte Jørgensen copy_getaddrs: 6202aad97f38SVlad Yasevich if (copy_to_user(to, addrs, bytes_copied)) { 6203aad97f38SVlad Yasevich err = -EFAULT; 6204d6f9fdafSSebastian Siewior goto out; 6205aad97f38SVlad Yasevich } 6206fe979ac1SVlad Yasevich if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) { 6207fe979ac1SVlad Yasevich err = -EFAULT; 6208d6f9fdafSSebastian Siewior goto out; 6209fe979ac1SVlad Yasevich } 6210c76f97c9SMarcelo Ricardo Leitner /* XXX: We should have accounted for sizeof(struct sctp_getaddrs) too, 6211c76f97c9SMarcelo Ricardo Leitner * but we can't change it anymore. 6212c76f97c9SMarcelo Ricardo Leitner */ 62135fe467eeSIvan Skytte Jørgensen if (put_user(bytes_copied, optlen)) 6214fe979ac1SVlad Yasevich err = -EFAULT; 6215d6f9fdafSSebastian Siewior out: 6216aad97f38SVlad Yasevich kfree(addrs); 62175fe467eeSIvan Skytte Jørgensen return err; 62185fe467eeSIvan Skytte Jørgensen } 62195fe467eeSIvan Skytte Jørgensen 62201da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 62211da177e4SLinus Torvalds * 62221da177e4SLinus Torvalds * Requests that the local SCTP stack use the enclosed peer address as 62231da177e4SLinus Torvalds * the association primary. The enclosed address must be one of the 62241da177e4SLinus Torvalds * association peer's addresses. 62251da177e4SLinus Torvalds */ 62261da177e4SLinus Torvalds static int sctp_getsockopt_primary_addr(struct sock *sk, int len, 62271da177e4SLinus Torvalds char __user *optval, int __user *optlen) 62281da177e4SLinus Torvalds { 62291da177e4SLinus Torvalds struct sctp_prim prim; 62301da177e4SLinus Torvalds struct sctp_association *asoc; 62311da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 62321da177e4SLinus Torvalds 6233408f22e8SNeil Horman if (len < sizeof(struct sctp_prim)) 62341da177e4SLinus Torvalds return -EINVAL; 62351da177e4SLinus Torvalds 6236408f22e8SNeil Horman len = sizeof(struct sctp_prim); 6237408f22e8SNeil Horman 6238408f22e8SNeil Horman if (copy_from_user(&prim, optval, len)) 62391da177e4SLinus Torvalds return -EFAULT; 62401da177e4SLinus Torvalds 62411da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); 62421da177e4SLinus Torvalds if (!asoc) 62431da177e4SLinus Torvalds return -EINVAL; 62441da177e4SLinus Torvalds 62451da177e4SLinus Torvalds if (!asoc->peer.primary_path) 62461da177e4SLinus Torvalds return -ENOTCONN; 62471da177e4SLinus Torvalds 62488cec6b80SAl Viro memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, 62498cec6b80SAl Viro asoc->peer.primary_path->af_specific->sockaddr_len); 62501da177e4SLinus Torvalds 6251299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp, 62521da177e4SLinus Torvalds (union sctp_addr *)&prim.ssp_addr); 62531da177e4SLinus Torvalds 6254408f22e8SNeil Horman if (put_user(len, optlen)) 6255408f22e8SNeil Horman return -EFAULT; 6256408f22e8SNeil Horman if (copy_to_user(optval, &prim, len)) 62571da177e4SLinus Torvalds return -EFAULT; 62581da177e4SLinus Torvalds 62591da177e4SLinus Torvalds return 0; 62601da177e4SLinus Torvalds } 62611da177e4SLinus Torvalds 62621da177e4SLinus Torvalds /* 62630f3fffd8SIvan Skytte Jorgensen * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) 62641da177e4SLinus Torvalds * 62650f3fffd8SIvan Skytte Jorgensen * Requests that the local endpoint set the specified Adaptation Layer 62661da177e4SLinus Torvalds * Indication parameter for all future INIT and INIT-ACK exchanges. 62671da177e4SLinus Torvalds */ 62680f3fffd8SIvan Skytte Jorgensen static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len, 62691da177e4SLinus Torvalds char __user *optval, int __user *optlen) 62701da177e4SLinus Torvalds { 62710f3fffd8SIvan Skytte Jorgensen struct sctp_setadaptation adaptation; 62721da177e4SLinus Torvalds 6273408f22e8SNeil Horman if (len < sizeof(struct sctp_setadaptation)) 62741da177e4SLinus Torvalds return -EINVAL; 62751da177e4SLinus Torvalds 6276408f22e8SNeil Horman len = sizeof(struct sctp_setadaptation); 6277408f22e8SNeil Horman 62780f3fffd8SIvan Skytte Jorgensen adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind; 6279408f22e8SNeil Horman 6280408f22e8SNeil Horman if (put_user(len, optlen)) 6281408f22e8SNeil Horman return -EFAULT; 62820f3fffd8SIvan Skytte Jorgensen if (copy_to_user(optval, &adaptation, len)) 62831da177e4SLinus Torvalds return -EFAULT; 6284a1ab3582SIvan Skytte Jorgensen 62851da177e4SLinus Torvalds return 0; 62861da177e4SLinus Torvalds } 62871da177e4SLinus Torvalds 62881da177e4SLinus Torvalds /* 62891da177e4SLinus Torvalds * 62901da177e4SLinus Torvalds * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 62911da177e4SLinus Torvalds * 62921da177e4SLinus Torvalds * Applications that wish to use the sendto() system call may wish to 62931da177e4SLinus Torvalds * specify a default set of parameters that would normally be supplied 62941da177e4SLinus Torvalds * through the inclusion of ancillary data. This socket option allows 62951da177e4SLinus Torvalds * such an application to set the default sctp_sndrcvinfo structure. 62961da177e4SLinus Torvalds 62971da177e4SLinus Torvalds 62981da177e4SLinus Torvalds * The application that wishes to use this socket option simply passes 62991da177e4SLinus Torvalds * in to this call the sctp_sndrcvinfo structure defined in Section 63001da177e4SLinus Torvalds * 5.2.2) The input parameters accepted by this call include 63011da177e4SLinus Torvalds * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 63021da177e4SLinus Torvalds * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 63031da177e4SLinus Torvalds * to this call if the caller is using the UDP model. 63041da177e4SLinus Torvalds * 63051da177e4SLinus Torvalds * For getsockopt, it get the default sctp_sndrcvinfo structure. 63061da177e4SLinus Torvalds */ 63071da177e4SLinus Torvalds static int sctp_getsockopt_default_send_param(struct sock *sk, 63081da177e4SLinus Torvalds int len, char __user *optval, 63091da177e4SLinus Torvalds int __user *optlen) 63101da177e4SLinus Torvalds { 63111da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 63126b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 63136b3fd5f3SGeir Ola Vaagland struct sctp_sndrcvinfo info; 63141da177e4SLinus Torvalds 63156b3fd5f3SGeir Ola Vaagland if (len < sizeof(info)) 63161da177e4SLinus Torvalds return -EINVAL; 6317408f22e8SNeil Horman 63186b3fd5f3SGeir Ola Vaagland len = sizeof(info); 6319408f22e8SNeil Horman 6320408f22e8SNeil Horman if (copy_from_user(&info, optval, len)) 63211da177e4SLinus Torvalds return -EFAULT; 63221da177e4SLinus Torvalds 63231da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); 6324707e45b3SXin Long if (!asoc && info.sinfo_assoc_id != SCTP_FUTURE_ASSOC && 6325707e45b3SXin Long sctp_style(sk, UDP)) 63261da177e4SLinus Torvalds return -EINVAL; 6327707e45b3SXin Long 63281da177e4SLinus Torvalds if (asoc) { 63291da177e4SLinus Torvalds info.sinfo_stream = asoc->default_stream; 63301da177e4SLinus Torvalds info.sinfo_flags = asoc->default_flags; 63311da177e4SLinus Torvalds info.sinfo_ppid = asoc->default_ppid; 63321da177e4SLinus Torvalds info.sinfo_context = asoc->default_context; 63331da177e4SLinus Torvalds info.sinfo_timetolive = asoc->default_timetolive; 63341da177e4SLinus Torvalds } else { 63351da177e4SLinus Torvalds info.sinfo_stream = sp->default_stream; 63361da177e4SLinus Torvalds info.sinfo_flags = sp->default_flags; 63371da177e4SLinus Torvalds info.sinfo_ppid = sp->default_ppid; 63381da177e4SLinus Torvalds info.sinfo_context = sp->default_context; 63391da177e4SLinus Torvalds info.sinfo_timetolive = sp->default_timetolive; 63401da177e4SLinus Torvalds } 63411da177e4SLinus Torvalds 6342408f22e8SNeil Horman if (put_user(len, optlen)) 6343408f22e8SNeil Horman return -EFAULT; 6344408f22e8SNeil Horman if (copy_to_user(optval, &info, len)) 63451da177e4SLinus Torvalds return -EFAULT; 63461da177e4SLinus Torvalds 63471da177e4SLinus Torvalds return 0; 63481da177e4SLinus Torvalds } 63491da177e4SLinus Torvalds 63506b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters 63516b3fd5f3SGeir Ola Vaagland * (SCTP_DEFAULT_SNDINFO) 63526b3fd5f3SGeir Ola Vaagland */ 63536b3fd5f3SGeir Ola Vaagland static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len, 63546b3fd5f3SGeir Ola Vaagland char __user *optval, 63556b3fd5f3SGeir Ola Vaagland int __user *optlen) 63566b3fd5f3SGeir Ola Vaagland { 63576b3fd5f3SGeir Ola Vaagland struct sctp_sock *sp = sctp_sk(sk); 63586b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 63596b3fd5f3SGeir Ola Vaagland struct sctp_sndinfo info; 63606b3fd5f3SGeir Ola Vaagland 63616b3fd5f3SGeir Ola Vaagland if (len < sizeof(info)) 63626b3fd5f3SGeir Ola Vaagland return -EINVAL; 63636b3fd5f3SGeir Ola Vaagland 63646b3fd5f3SGeir Ola Vaagland len = sizeof(info); 63656b3fd5f3SGeir Ola Vaagland 63666b3fd5f3SGeir Ola Vaagland if (copy_from_user(&info, optval, len)) 63676b3fd5f3SGeir Ola Vaagland return -EFAULT; 63686b3fd5f3SGeir Ola Vaagland 63696b3fd5f3SGeir Ola Vaagland asoc = sctp_id2assoc(sk, info.snd_assoc_id); 637092fc3bd9SXin Long if (!asoc && info.snd_assoc_id != SCTP_FUTURE_ASSOC && 637192fc3bd9SXin Long sctp_style(sk, UDP)) 63726b3fd5f3SGeir Ola Vaagland return -EINVAL; 637392fc3bd9SXin Long 63746b3fd5f3SGeir Ola Vaagland if (asoc) { 63756b3fd5f3SGeir Ola Vaagland info.snd_sid = asoc->default_stream; 63766b3fd5f3SGeir Ola Vaagland info.snd_flags = asoc->default_flags; 63776b3fd5f3SGeir Ola Vaagland info.snd_ppid = asoc->default_ppid; 63786b3fd5f3SGeir Ola Vaagland info.snd_context = asoc->default_context; 63796b3fd5f3SGeir Ola Vaagland } else { 63806b3fd5f3SGeir Ola Vaagland info.snd_sid = sp->default_stream; 63816b3fd5f3SGeir Ola Vaagland info.snd_flags = sp->default_flags; 63826b3fd5f3SGeir Ola Vaagland info.snd_ppid = sp->default_ppid; 63836b3fd5f3SGeir Ola Vaagland info.snd_context = sp->default_context; 63846b3fd5f3SGeir Ola Vaagland } 63856b3fd5f3SGeir Ola Vaagland 63866b3fd5f3SGeir Ola Vaagland if (put_user(len, optlen)) 63876b3fd5f3SGeir Ola Vaagland return -EFAULT; 63886b3fd5f3SGeir Ola Vaagland if (copy_to_user(optval, &info, len)) 63896b3fd5f3SGeir Ola Vaagland return -EFAULT; 63906b3fd5f3SGeir Ola Vaagland 63916b3fd5f3SGeir Ola Vaagland return 0; 63926b3fd5f3SGeir Ola Vaagland } 63936b3fd5f3SGeir Ola Vaagland 63941da177e4SLinus Torvalds /* 63951da177e4SLinus Torvalds * 63961da177e4SLinus Torvalds * 7.1.5 SCTP_NODELAY 63971da177e4SLinus Torvalds * 63981da177e4SLinus Torvalds * Turn on/off any Nagle-like algorithm. This means that packets are 63991da177e4SLinus Torvalds * generally sent as soon as possible and no unnecessary delays are 64001da177e4SLinus Torvalds * introduced, at the cost of more packets in the network. Expects an 64011da177e4SLinus Torvalds * integer boolean flag. 64021da177e4SLinus Torvalds */ 64031da177e4SLinus Torvalds 64041da177e4SLinus Torvalds static int sctp_getsockopt_nodelay(struct sock *sk, int len, 64051da177e4SLinus Torvalds char __user *optval, int __user *optlen) 64061da177e4SLinus Torvalds { 64071da177e4SLinus Torvalds int val; 64081da177e4SLinus Torvalds 64091da177e4SLinus Torvalds if (len < sizeof(int)) 64101da177e4SLinus Torvalds return -EINVAL; 64111da177e4SLinus Torvalds 64121da177e4SLinus Torvalds len = sizeof(int); 64131da177e4SLinus Torvalds val = (sctp_sk(sk)->nodelay == 1); 64141da177e4SLinus Torvalds if (put_user(len, optlen)) 64151da177e4SLinus Torvalds return -EFAULT; 64161da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 64171da177e4SLinus Torvalds return -EFAULT; 64181da177e4SLinus Torvalds return 0; 64191da177e4SLinus Torvalds } 64201da177e4SLinus Torvalds 64211da177e4SLinus Torvalds /* 64221da177e4SLinus Torvalds * 64231da177e4SLinus Torvalds * 7.1.1 SCTP_RTOINFO 64241da177e4SLinus Torvalds * 64251da177e4SLinus Torvalds * The protocol parameters used to initialize and bound retransmission 64261da177e4SLinus Torvalds * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 64271da177e4SLinus Torvalds * and modify these parameters. 64281da177e4SLinus Torvalds * All parameters are time values, in milliseconds. A value of 0, when 64291da177e4SLinus Torvalds * modifying the parameters, indicates that the current value should not 64301da177e4SLinus Torvalds * be changed. 64311da177e4SLinus Torvalds * 64321da177e4SLinus Torvalds */ 64331da177e4SLinus Torvalds static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, 64341da177e4SLinus Torvalds char __user *optval, 64351da177e4SLinus Torvalds int __user *optlen) { 64361da177e4SLinus Torvalds struct sctp_rtoinfo rtoinfo; 64371da177e4SLinus Torvalds struct sctp_association *asoc; 64381da177e4SLinus Torvalds 6439408f22e8SNeil Horman if (len < sizeof (struct sctp_rtoinfo)) 64401da177e4SLinus Torvalds return -EINVAL; 64411da177e4SLinus Torvalds 6442408f22e8SNeil Horman len = sizeof(struct sctp_rtoinfo); 6443408f22e8SNeil Horman 6444408f22e8SNeil Horman if (copy_from_user(&rtoinfo, optval, len)) 64451da177e4SLinus Torvalds return -EFAULT; 64461da177e4SLinus Torvalds 64471da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); 64481da177e4SLinus Torvalds 64497adb5ed5SXin Long if (!asoc && rtoinfo.srto_assoc_id != SCTP_FUTURE_ASSOC && 64507adb5ed5SXin Long sctp_style(sk, UDP)) 64511da177e4SLinus Torvalds return -EINVAL; 64521da177e4SLinus Torvalds 64531da177e4SLinus Torvalds /* Values corresponding to the specific association. */ 64541da177e4SLinus Torvalds if (asoc) { 64551da177e4SLinus Torvalds rtoinfo.srto_initial = jiffies_to_msecs(asoc->rto_initial); 64561da177e4SLinus Torvalds rtoinfo.srto_max = jiffies_to_msecs(asoc->rto_max); 64571da177e4SLinus Torvalds rtoinfo.srto_min = jiffies_to_msecs(asoc->rto_min); 64581da177e4SLinus Torvalds } else { 64591da177e4SLinus Torvalds /* Values corresponding to the endpoint. */ 64601da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 64611da177e4SLinus Torvalds 64621da177e4SLinus Torvalds rtoinfo.srto_initial = sp->rtoinfo.srto_initial; 64631da177e4SLinus Torvalds rtoinfo.srto_max = sp->rtoinfo.srto_max; 64641da177e4SLinus Torvalds rtoinfo.srto_min = sp->rtoinfo.srto_min; 64651da177e4SLinus Torvalds } 64661da177e4SLinus Torvalds 64671da177e4SLinus Torvalds if (put_user(len, optlen)) 64681da177e4SLinus Torvalds return -EFAULT; 64691da177e4SLinus Torvalds 64701da177e4SLinus Torvalds if (copy_to_user(optval, &rtoinfo, len)) 64711da177e4SLinus Torvalds return -EFAULT; 64721da177e4SLinus Torvalds 64731da177e4SLinus Torvalds return 0; 64741da177e4SLinus Torvalds } 64751da177e4SLinus Torvalds 64761da177e4SLinus Torvalds /* 64771da177e4SLinus Torvalds * 64781da177e4SLinus Torvalds * 7.1.2 SCTP_ASSOCINFO 64791da177e4SLinus Torvalds * 648059c51591SMichael Opdenacker * This option is used to tune the maximum retransmission attempts 64811da177e4SLinus Torvalds * of the association. 64821da177e4SLinus Torvalds * Returns an error if the new association retransmission value is 64831da177e4SLinus Torvalds * greater than the sum of the retransmission value of the peer. 64841da177e4SLinus Torvalds * See [SCTP] for more information. 64851da177e4SLinus Torvalds * 64861da177e4SLinus Torvalds */ 64871da177e4SLinus Torvalds static int sctp_getsockopt_associnfo(struct sock *sk, int len, 64881da177e4SLinus Torvalds char __user *optval, 64891da177e4SLinus Torvalds int __user *optlen) 64901da177e4SLinus Torvalds { 64911da177e4SLinus Torvalds 64921da177e4SLinus Torvalds struct sctp_assocparams assocparams; 64931da177e4SLinus Torvalds struct sctp_association *asoc; 64941da177e4SLinus Torvalds struct list_head *pos; 64951da177e4SLinus Torvalds int cnt = 0; 64961da177e4SLinus Torvalds 6497408f22e8SNeil Horman if (len < sizeof (struct sctp_assocparams)) 64981da177e4SLinus Torvalds return -EINVAL; 64991da177e4SLinus Torvalds 6500408f22e8SNeil Horman len = sizeof(struct sctp_assocparams); 6501408f22e8SNeil Horman 6502408f22e8SNeil Horman if (copy_from_user(&assocparams, optval, len)) 65031da177e4SLinus Torvalds return -EFAULT; 65041da177e4SLinus Torvalds 65051da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); 65061da177e4SLinus Torvalds 65078889394dSXin Long if (!asoc && assocparams.sasoc_assoc_id != SCTP_FUTURE_ASSOC && 65088889394dSXin Long sctp_style(sk, UDP)) 65091da177e4SLinus Torvalds return -EINVAL; 65101da177e4SLinus Torvalds 65111da177e4SLinus Torvalds /* Values correspoinding to the specific association */ 651217337216SVladislav Yasevich if (asoc) { 65131da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt = asoc->max_retrans; 65141da177e4SLinus Torvalds assocparams.sasoc_peer_rwnd = asoc->peer.rwnd; 65151da177e4SLinus Torvalds assocparams.sasoc_local_rwnd = asoc->a_rwnd; 651652db882fSDaniel Borkmann assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life); 65171da177e4SLinus Torvalds 65181da177e4SLinus Torvalds list_for_each(pos, &asoc->peer.transport_addr_list) { 65191da177e4SLinus Torvalds cnt++; 65201da177e4SLinus Torvalds } 65211da177e4SLinus Torvalds 65221da177e4SLinus Torvalds assocparams.sasoc_number_peer_destinations = cnt; 65231da177e4SLinus Torvalds } else { 65241da177e4SLinus Torvalds /* Values corresponding to the endpoint */ 65251da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 65261da177e4SLinus Torvalds 65271da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt; 65281da177e4SLinus Torvalds assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd; 65291da177e4SLinus Torvalds assocparams.sasoc_local_rwnd = sp->assocparams.sasoc_local_rwnd; 65301da177e4SLinus Torvalds assocparams.sasoc_cookie_life = 65311da177e4SLinus Torvalds sp->assocparams.sasoc_cookie_life; 65321da177e4SLinus Torvalds assocparams.sasoc_number_peer_destinations = 65331da177e4SLinus Torvalds sp->assocparams. 65341da177e4SLinus Torvalds sasoc_number_peer_destinations; 65351da177e4SLinus Torvalds } 65361da177e4SLinus Torvalds 65371da177e4SLinus Torvalds if (put_user(len, optlen)) 65381da177e4SLinus Torvalds return -EFAULT; 65391da177e4SLinus Torvalds 65401da177e4SLinus Torvalds if (copy_to_user(optval, &assocparams, len)) 65411da177e4SLinus Torvalds return -EFAULT; 65421da177e4SLinus Torvalds 65431da177e4SLinus Torvalds return 0; 65441da177e4SLinus Torvalds } 65451da177e4SLinus Torvalds 65461da177e4SLinus Torvalds /* 65471da177e4SLinus Torvalds * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 65481da177e4SLinus Torvalds * 65491da177e4SLinus Torvalds * This socket option is a boolean flag which turns on or off mapped V4 65501da177e4SLinus Torvalds * addresses. If this option is turned on and the socket is type 65511da177e4SLinus Torvalds * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 65521da177e4SLinus Torvalds * If this option is turned off, then no mapping will be done of V4 65531da177e4SLinus Torvalds * addresses and a user will receive both PF_INET6 and PF_INET type 65541da177e4SLinus Torvalds * addresses on the socket. 65551da177e4SLinus Torvalds */ 65561da177e4SLinus Torvalds static int sctp_getsockopt_mappedv4(struct sock *sk, int len, 65571da177e4SLinus Torvalds char __user *optval, int __user *optlen) 65581da177e4SLinus Torvalds { 65591da177e4SLinus Torvalds int val; 65601da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 65611da177e4SLinus Torvalds 65621da177e4SLinus Torvalds if (len < sizeof(int)) 65631da177e4SLinus Torvalds return -EINVAL; 65641da177e4SLinus Torvalds 65651da177e4SLinus Torvalds len = sizeof(int); 65661da177e4SLinus Torvalds val = sp->v4mapped; 65671da177e4SLinus Torvalds if (put_user(len, optlen)) 65681da177e4SLinus Torvalds return -EFAULT; 65691da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 65701da177e4SLinus Torvalds return -EFAULT; 65711da177e4SLinus Torvalds 65721da177e4SLinus Torvalds return 0; 65731da177e4SLinus Torvalds } 65741da177e4SLinus Torvalds 65751da177e4SLinus Torvalds /* 65766ab792f5SIvan Skytte Jorgensen * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 65776ab792f5SIvan Skytte Jorgensen * (chapter and verse is quoted at sctp_setsockopt_context()) 65786ab792f5SIvan Skytte Jorgensen */ 65796ab792f5SIvan Skytte Jorgensen static int sctp_getsockopt_context(struct sock *sk, int len, 65806ab792f5SIvan Skytte Jorgensen char __user *optval, int __user *optlen) 65816ab792f5SIvan Skytte Jorgensen { 65826ab792f5SIvan Skytte Jorgensen struct sctp_assoc_value params; 65836ab792f5SIvan Skytte Jorgensen struct sctp_association *asoc; 65846ab792f5SIvan Skytte Jorgensen 6585408f22e8SNeil Horman if (len < sizeof(struct sctp_assoc_value)) 65866ab792f5SIvan Skytte Jorgensen return -EINVAL; 65876ab792f5SIvan Skytte Jorgensen 6588408f22e8SNeil Horman len = sizeof(struct sctp_assoc_value); 6589408f22e8SNeil Horman 65906ab792f5SIvan Skytte Jorgensen if (copy_from_user(¶ms, optval, len)) 65916ab792f5SIvan Skytte Jorgensen return -EFAULT; 65926ab792f5SIvan Skytte Jorgensen 65936ab792f5SIvan Skytte Jorgensen asoc = sctp_id2assoc(sk, params.assoc_id); 659449b037acSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 659549b037acSXin Long sctp_style(sk, UDP)) 65966ab792f5SIvan Skytte Jorgensen return -EINVAL; 659749b037acSXin Long 659849b037acSXin Long params.assoc_value = asoc ? asoc->default_rcv_context 659949b037acSXin Long : sctp_sk(sk)->default_rcv_context; 66006ab792f5SIvan Skytte Jorgensen 66016ab792f5SIvan Skytte Jorgensen if (put_user(len, optlen)) 66026ab792f5SIvan Skytte Jorgensen return -EFAULT; 66036ab792f5SIvan Skytte Jorgensen if (copy_to_user(optval, ¶ms, len)) 66046ab792f5SIvan Skytte Jorgensen return -EFAULT; 66056ab792f5SIvan Skytte Jorgensen 66066ab792f5SIvan Skytte Jorgensen return 0; 66076ab792f5SIvan Skytte Jorgensen } 66086ab792f5SIvan Skytte Jorgensen 66096ab792f5SIvan Skytte Jorgensen /* 6610e89c2095SWei Yongjun * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 6611e89c2095SWei Yongjun * This option will get or set the maximum size to put in any outgoing 6612e89c2095SWei Yongjun * SCTP DATA chunk. If a message is larger than this size it will be 66131da177e4SLinus Torvalds * fragmented by SCTP into the specified size. Note that the underlying 66141da177e4SLinus Torvalds * SCTP implementation may fragment into smaller sized chunks when the 66151da177e4SLinus Torvalds * PMTU of the underlying association is smaller than the value set by 6616e89c2095SWei Yongjun * the user. The default value for this option is '0' which indicates 6617e89c2095SWei Yongjun * the user is NOT limiting fragmentation and only the PMTU will effect 6618e89c2095SWei Yongjun * SCTP's choice of DATA chunk size. Note also that values set larger 6619e89c2095SWei Yongjun * than the maximum size of an IP datagram will effectively let SCTP 6620e89c2095SWei Yongjun * control fragmentation (i.e. the same as setting this option to 0). 6621e89c2095SWei Yongjun * 6622e89c2095SWei Yongjun * The following structure is used to access and modify this parameter: 6623e89c2095SWei Yongjun * 6624e89c2095SWei Yongjun * struct sctp_assoc_value { 6625e89c2095SWei Yongjun * sctp_assoc_t assoc_id; 6626e89c2095SWei Yongjun * uint32_t assoc_value; 6627e89c2095SWei Yongjun * }; 6628e89c2095SWei Yongjun * 6629e89c2095SWei Yongjun * assoc_id: This parameter is ignored for one-to-one style sockets. 6630e89c2095SWei Yongjun * For one-to-many style sockets this parameter indicates which 6631e89c2095SWei Yongjun * association the user is performing an action upon. Note that if 6632e89c2095SWei Yongjun * this field's value is zero then the endpoints default value is 6633e89c2095SWei Yongjun * changed (effecting future associations only). 6634e89c2095SWei Yongjun * assoc_value: This parameter specifies the maximum size in bytes. 66351da177e4SLinus Torvalds */ 66361da177e4SLinus Torvalds static int sctp_getsockopt_maxseg(struct sock *sk, int len, 66371da177e4SLinus Torvalds char __user *optval, int __user *optlen) 66381da177e4SLinus Torvalds { 6639e89c2095SWei Yongjun struct sctp_assoc_value params; 6640e89c2095SWei Yongjun struct sctp_association *asoc; 66411da177e4SLinus Torvalds 6642e89c2095SWei Yongjun if (len == sizeof(int)) { 664394f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 6644f916ec96SNeil Horman "%s (pid %d) " 664594f65193SNeil Horman "Use of int in maxseg socket option.\n" 6646f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 6647f916ec96SNeil Horman current->comm, task_pid_nr(current)); 66486fd769beSXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 6649e89c2095SWei Yongjun } else if (len >= sizeof(struct sctp_assoc_value)) { 6650e89c2095SWei Yongjun len = sizeof(struct sctp_assoc_value); 6651c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, len)) 6652e89c2095SWei Yongjun return -EFAULT; 6653e89c2095SWei Yongjun } else 66541da177e4SLinus Torvalds return -EINVAL; 66551da177e4SLinus Torvalds 6656e89c2095SWei Yongjun asoc = sctp_id2assoc(sk, params.assoc_id); 66576fd769beSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 66586fd769beSXin Long sctp_style(sk, UDP)) 6659e89c2095SWei Yongjun return -EINVAL; 66601da177e4SLinus Torvalds 6661e89c2095SWei Yongjun if (asoc) 6662e89c2095SWei Yongjun params.assoc_value = asoc->frag_point; 6663e89c2095SWei Yongjun else 6664e89c2095SWei Yongjun params.assoc_value = sctp_sk(sk)->user_frag; 6665e89c2095SWei Yongjun 66661da177e4SLinus Torvalds if (put_user(len, optlen)) 66671da177e4SLinus Torvalds return -EFAULT; 6668e89c2095SWei Yongjun if (len == sizeof(int)) { 6669e89c2095SWei Yongjun if (copy_to_user(optval, ¶ms.assoc_value, len)) 66701da177e4SLinus Torvalds return -EFAULT; 6671e89c2095SWei Yongjun } else { 6672e89c2095SWei Yongjun if (copy_to_user(optval, ¶ms, len)) 6673e89c2095SWei Yongjun return -EFAULT; 6674e89c2095SWei Yongjun } 66751da177e4SLinus Torvalds 66761da177e4SLinus Torvalds return 0; 66771da177e4SLinus Torvalds } 66781da177e4SLinus Torvalds 6679b6e1331fSVlad Yasevich /* 6680b6e1331fSVlad Yasevich * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 6681b6e1331fSVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_fragment_interleave()) 6682b6e1331fSVlad Yasevich */ 6683b6e1331fSVlad Yasevich static int sctp_getsockopt_fragment_interleave(struct sock *sk, int len, 6684b6e1331fSVlad Yasevich char __user *optval, int __user *optlen) 6685b6e1331fSVlad Yasevich { 6686b6e1331fSVlad Yasevich int val; 6687b6e1331fSVlad Yasevich 6688b6e1331fSVlad Yasevich if (len < sizeof(int)) 6689b6e1331fSVlad Yasevich return -EINVAL; 6690b6e1331fSVlad Yasevich 6691b6e1331fSVlad Yasevich len = sizeof(int); 6692b6e1331fSVlad Yasevich 6693b6e1331fSVlad Yasevich val = sctp_sk(sk)->frag_interleave; 6694b6e1331fSVlad Yasevich if (put_user(len, optlen)) 6695b6e1331fSVlad Yasevich return -EFAULT; 6696b6e1331fSVlad Yasevich if (copy_to_user(optval, &val, len)) 6697b6e1331fSVlad Yasevich return -EFAULT; 6698b6e1331fSVlad Yasevich 6699b6e1331fSVlad Yasevich return 0; 6700b6e1331fSVlad Yasevich } 6701b6e1331fSVlad Yasevich 6702d49d91d7SVlad Yasevich /* 6703d49d91d7SVlad Yasevich * 7.1.25. Set or Get the sctp partial delivery point 6704d49d91d7SVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_partial_delivery_point()) 6705d49d91d7SVlad Yasevich */ 6706d49d91d7SVlad Yasevich static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len, 6707d49d91d7SVlad Yasevich char __user *optval, 6708d49d91d7SVlad Yasevich int __user *optlen) 6709d49d91d7SVlad Yasevich { 6710d49d91d7SVlad Yasevich u32 val; 6711d49d91d7SVlad Yasevich 6712d49d91d7SVlad Yasevich if (len < sizeof(u32)) 6713d49d91d7SVlad Yasevich return -EINVAL; 6714d49d91d7SVlad Yasevich 6715d49d91d7SVlad Yasevich len = sizeof(u32); 6716d49d91d7SVlad Yasevich 6717d49d91d7SVlad Yasevich val = sctp_sk(sk)->pd_point; 6718d49d91d7SVlad Yasevich if (put_user(len, optlen)) 6719d49d91d7SVlad Yasevich return -EFAULT; 6720d49d91d7SVlad Yasevich if (copy_to_user(optval, &val, len)) 6721d49d91d7SVlad Yasevich return -EFAULT; 6722d49d91d7SVlad Yasevich 67237d743b7eSWei Yongjun return 0; 6724d49d91d7SVlad Yasevich } 6725d49d91d7SVlad Yasevich 672670331571SVlad Yasevich /* 672770331571SVlad Yasevich * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 672870331571SVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_maxburst()) 672970331571SVlad Yasevich */ 673070331571SVlad Yasevich static int sctp_getsockopt_maxburst(struct sock *sk, int len, 673170331571SVlad Yasevich char __user *optval, 673270331571SVlad Yasevich int __user *optlen) 673370331571SVlad Yasevich { 6734219b99a9SNeil Horman struct sctp_assoc_value params; 6735219b99a9SNeil Horman struct sctp_association *asoc; 673670331571SVlad Yasevich 6737219b99a9SNeil Horman if (len == sizeof(int)) { 673894f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 6739f916ec96SNeil Horman "%s (pid %d) " 674094f65193SNeil Horman "Use of int in max_burst socket option.\n" 6741f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 6742f916ec96SNeil Horman current->comm, task_pid_nr(current)); 6743e0651a0dSXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 6744c6db93a5SWei Yongjun } else if (len >= sizeof(struct sctp_assoc_value)) { 6745c6db93a5SWei Yongjun len = sizeof(struct sctp_assoc_value); 6746219b99a9SNeil Horman if (copy_from_user(¶ms, optval, len)) 674770331571SVlad Yasevich return -EFAULT; 6748219b99a9SNeil Horman } else 6749219b99a9SNeil Horman return -EINVAL; 675070331571SVlad Yasevich 6751219b99a9SNeil Horman asoc = sctp_id2assoc(sk, params.assoc_id); 6752e0651a0dSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 6753e0651a0dSXin Long sctp_style(sk, UDP)) 6754219b99a9SNeil Horman return -EINVAL; 6755e0651a0dSXin Long 6756e0651a0dSXin Long params.assoc_value = asoc ? asoc->max_burst : sctp_sk(sk)->max_burst; 6757219b99a9SNeil Horman 6758219b99a9SNeil Horman if (len == sizeof(int)) { 6759219b99a9SNeil Horman if (copy_to_user(optval, ¶ms.assoc_value, len)) 6760219b99a9SNeil Horman return -EFAULT; 6761219b99a9SNeil Horman } else { 6762219b99a9SNeil Horman if (copy_to_user(optval, ¶ms, len)) 6763219b99a9SNeil Horman return -EFAULT; 6764219b99a9SNeil Horman } 6765219b99a9SNeil Horman 6766219b99a9SNeil Horman return 0; 6767219b99a9SNeil Horman 676870331571SVlad Yasevich } 676970331571SVlad Yasevich 677065b07e5dSVlad Yasevich static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, 677165b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 677265b07e5dSVlad Yasevich { 6773b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 67745e739d17SVlad Yasevich struct sctp_hmacalgo __user *p = (void __user *)optval; 677565b07e5dSVlad Yasevich struct sctp_hmac_algo_param *hmacs; 67765e739d17SVlad Yasevich __u16 data_len = 0; 67775e739d17SVlad Yasevich u32 num_idents; 67787a84bd46SXin Long int i; 67795e739d17SVlad Yasevich 6780b14878ccSVlad Yasevich if (!ep->auth_enable) 67815e739d17SVlad Yasevich return -EACCES; 678265b07e5dSVlad Yasevich 6783b14878ccSVlad Yasevich hmacs = ep->auth_hmacs_list; 67843c918704SXin Long data_len = ntohs(hmacs->param_hdr.length) - 67853c918704SXin Long sizeof(struct sctp_paramhdr); 678665b07e5dSVlad Yasevich 67875e739d17SVlad Yasevich if (len < sizeof(struct sctp_hmacalgo) + data_len) 678865b07e5dSVlad Yasevich return -EINVAL; 67895e739d17SVlad Yasevich 67905e739d17SVlad Yasevich len = sizeof(struct sctp_hmacalgo) + data_len; 67915e739d17SVlad Yasevich num_idents = data_len / sizeof(u16); 67925e739d17SVlad Yasevich 679365b07e5dSVlad Yasevich if (put_user(len, optlen)) 679465b07e5dSVlad Yasevich return -EFAULT; 67955e739d17SVlad Yasevich if (put_user(num_idents, &p->shmac_num_idents)) 679665b07e5dSVlad Yasevich return -EFAULT; 67977a84bd46SXin Long for (i = 0; i < num_idents; i++) { 67987a84bd46SXin Long __u16 hmacid = ntohs(hmacs->hmac_ids[i]); 67997a84bd46SXin Long 68007a84bd46SXin Long if (copy_to_user(&p->shmac_idents[i], &hmacid, sizeof(__u16))) 68015e739d17SVlad Yasevich return -EFAULT; 68027a84bd46SXin Long } 680365b07e5dSVlad Yasevich return 0; 680465b07e5dSVlad Yasevich } 680565b07e5dSVlad Yasevich 680665b07e5dSVlad Yasevich static int sctp_getsockopt_active_key(struct sock *sk, int len, 680765b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 680865b07e5dSVlad Yasevich { 6809b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 681065b07e5dSVlad Yasevich struct sctp_authkeyid val; 681165b07e5dSVlad Yasevich struct sctp_association *asoc; 681265b07e5dSVlad Yasevich 681365b07e5dSVlad Yasevich if (len < sizeof(struct sctp_authkeyid)) 681465b07e5dSVlad Yasevich return -EINVAL; 6815c76f97c9SMarcelo Ricardo Leitner 6816c76f97c9SMarcelo Ricardo Leitner len = sizeof(struct sctp_authkeyid); 6817c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(&val, optval, len)) 681865b07e5dSVlad Yasevich return -EFAULT; 681965b07e5dSVlad Yasevich 682065b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 682165b07e5dSVlad Yasevich if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 682265b07e5dSVlad Yasevich return -EINVAL; 682365b07e5dSVlad Yasevich 6824219f9ea4SXin Long if (asoc) { 6825219f9ea4SXin Long if (!asoc->peer.auth_capable) 6826219f9ea4SXin Long return -EACCES; 682765b07e5dSVlad Yasevich val.scact_keynumber = asoc->active_key_id; 6828219f9ea4SXin Long } else { 6829219f9ea4SXin Long if (!ep->auth_enable) 6830219f9ea4SXin Long return -EACCES; 6831b14878ccSVlad Yasevich val.scact_keynumber = ep->active_key_id; 6832219f9ea4SXin Long } 683365b07e5dSVlad Yasevich 68345e739d17SVlad Yasevich if (put_user(len, optlen)) 68355e739d17SVlad Yasevich return -EFAULT; 68365e739d17SVlad Yasevich if (copy_to_user(optval, &val, len)) 68375e739d17SVlad Yasevich return -EFAULT; 68385e739d17SVlad Yasevich 683965b07e5dSVlad Yasevich return 0; 684065b07e5dSVlad Yasevich } 684165b07e5dSVlad Yasevich 684265b07e5dSVlad Yasevich static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, 684365b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 684465b07e5dSVlad Yasevich { 6845411223c0SAl Viro struct sctp_authchunks __user *p = (void __user *)optval; 684665b07e5dSVlad Yasevich struct sctp_authchunks val; 684765b07e5dSVlad Yasevich struct sctp_association *asoc; 684865b07e5dSVlad Yasevich struct sctp_chunks_param *ch; 68495e739d17SVlad Yasevich u32 num_chunks = 0; 685065b07e5dSVlad Yasevich char __user *to; 685165b07e5dSVlad Yasevich 68525e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks)) 685365b07e5dSVlad Yasevich return -EINVAL; 685465b07e5dSVlad Yasevich 6855c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(&val, optval, sizeof(val))) 685665b07e5dSVlad Yasevich return -EFAULT; 685765b07e5dSVlad Yasevich 6858411223c0SAl Viro to = p->gauth_chunks; 685965b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 686065b07e5dSVlad Yasevich if (!asoc) 686165b07e5dSVlad Yasevich return -EINVAL; 686265b07e5dSVlad Yasevich 6863219f9ea4SXin Long if (!asoc->peer.auth_capable) 6864219f9ea4SXin Long return -EACCES; 6865219f9ea4SXin Long 686665b07e5dSVlad Yasevich ch = asoc->peer.peer_chunks; 68675e739d17SVlad Yasevich if (!ch) 68685e739d17SVlad Yasevich goto num; 686965b07e5dSVlad Yasevich 687065b07e5dSVlad Yasevich /* See if the user provided enough room for all the data */ 68713c918704SXin Long num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); 6872b40db684SVlad Yasevich if (len < num_chunks) 687365b07e5dSVlad Yasevich return -EINVAL; 687465b07e5dSVlad Yasevich 68755e739d17SVlad Yasevich if (copy_to_user(to, ch->chunks, num_chunks)) 687665b07e5dSVlad Yasevich return -EFAULT; 68775e739d17SVlad Yasevich num: 68785e739d17SVlad Yasevich len = sizeof(struct sctp_authchunks) + num_chunks; 68798d72651dSwangweidong if (put_user(len, optlen)) 68808d72651dSwangweidong return -EFAULT; 68817e8616d8SVlad Yasevich if (put_user(num_chunks, &p->gauth_number_of_chunks)) 68827e8616d8SVlad Yasevich return -EFAULT; 688365b07e5dSVlad Yasevich return 0; 688465b07e5dSVlad Yasevich } 688565b07e5dSVlad Yasevich 688665b07e5dSVlad Yasevich static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, 688765b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 688865b07e5dSVlad Yasevich { 6889b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 6890411223c0SAl Viro struct sctp_authchunks __user *p = (void __user *)optval; 689165b07e5dSVlad Yasevich struct sctp_authchunks val; 689265b07e5dSVlad Yasevich struct sctp_association *asoc; 689365b07e5dSVlad Yasevich struct sctp_chunks_param *ch; 68945e739d17SVlad Yasevich u32 num_chunks = 0; 689565b07e5dSVlad Yasevich char __user *to; 689665b07e5dSVlad Yasevich 68975e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks)) 689865b07e5dSVlad Yasevich return -EINVAL; 689965b07e5dSVlad Yasevich 6900c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(&val, optval, sizeof(val))) 690165b07e5dSVlad Yasevich return -EFAULT; 690265b07e5dSVlad Yasevich 6903411223c0SAl Viro to = p->gauth_chunks; 690465b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 690548c07217SXin Long if (!asoc && val.gauth_assoc_id != SCTP_FUTURE_ASSOC && 690648c07217SXin Long sctp_style(sk, UDP)) 690765b07e5dSVlad Yasevich return -EINVAL; 690865b07e5dSVlad Yasevich 6909219f9ea4SXin Long if (asoc) { 6910219f9ea4SXin Long if (!asoc->peer.auth_capable) 6911219f9ea4SXin Long return -EACCES; 6912219f9ea4SXin Long ch = (struct sctp_chunks_param *)asoc->c.auth_chunks; 6913219f9ea4SXin Long } else { 6914219f9ea4SXin Long if (!ep->auth_enable) 6915219f9ea4SXin Long return -EACCES; 6916219f9ea4SXin Long ch = ep->auth_chunk_list; 6917219f9ea4SXin Long } 69185e739d17SVlad Yasevich if (!ch) 69195e739d17SVlad Yasevich goto num; 69205e739d17SVlad Yasevich 69213c918704SXin Long num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); 69225e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks) + num_chunks) 692365b07e5dSVlad Yasevich return -EINVAL; 692465b07e5dSVlad Yasevich 69255e739d17SVlad Yasevich if (copy_to_user(to, ch->chunks, num_chunks)) 69265e739d17SVlad Yasevich return -EFAULT; 69275e739d17SVlad Yasevich num: 69285e739d17SVlad Yasevich len = sizeof(struct sctp_authchunks) + num_chunks; 692965b07e5dSVlad Yasevich if (put_user(len, optlen)) 693065b07e5dSVlad Yasevich return -EFAULT; 69317e8616d8SVlad Yasevich if (put_user(num_chunks, &p->gauth_number_of_chunks)) 69327e8616d8SVlad Yasevich return -EFAULT; 693365b07e5dSVlad Yasevich 693465b07e5dSVlad Yasevich return 0; 693565b07e5dSVlad Yasevich } 693665b07e5dSVlad Yasevich 6937aea3c5c0SWei Yongjun /* 6938aea3c5c0SWei Yongjun * 8.2.5. Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER) 6939aea3c5c0SWei Yongjun * This option gets the current number of associations that are attached 6940aea3c5c0SWei Yongjun * to a one-to-many style socket. The option value is an uint32_t. 6941aea3c5c0SWei Yongjun */ 6942aea3c5c0SWei Yongjun static int sctp_getsockopt_assoc_number(struct sock *sk, int len, 6943aea3c5c0SWei Yongjun char __user *optval, int __user *optlen) 6944aea3c5c0SWei Yongjun { 6945aea3c5c0SWei Yongjun struct sctp_sock *sp = sctp_sk(sk); 6946aea3c5c0SWei Yongjun struct sctp_association *asoc; 6947aea3c5c0SWei Yongjun u32 val = 0; 6948aea3c5c0SWei Yongjun 6949aea3c5c0SWei Yongjun if (sctp_style(sk, TCP)) 6950aea3c5c0SWei Yongjun return -EOPNOTSUPP; 6951aea3c5c0SWei Yongjun 6952aea3c5c0SWei Yongjun if (len < sizeof(u32)) 6953aea3c5c0SWei Yongjun return -EINVAL; 6954aea3c5c0SWei Yongjun 6955aea3c5c0SWei Yongjun len = sizeof(u32); 6956aea3c5c0SWei Yongjun 6957aea3c5c0SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 6958aea3c5c0SWei Yongjun val++; 6959aea3c5c0SWei Yongjun } 6960aea3c5c0SWei Yongjun 6961aea3c5c0SWei Yongjun if (put_user(len, optlen)) 6962aea3c5c0SWei Yongjun return -EFAULT; 6963aea3c5c0SWei Yongjun if (copy_to_user(optval, &val, len)) 6964aea3c5c0SWei Yongjun return -EFAULT; 6965aea3c5c0SWei Yongjun 6966aea3c5c0SWei Yongjun return 0; 6967aea3c5c0SWei Yongjun } 6968aea3c5c0SWei Yongjun 6969209ba424SWei Yongjun /* 69707dc04d71SMichio Honda * 8.1.23 SCTP_AUTO_ASCONF 69717dc04d71SMichio Honda * See the corresponding setsockopt entry as description 69727dc04d71SMichio Honda */ 69737dc04d71SMichio Honda static int sctp_getsockopt_auto_asconf(struct sock *sk, int len, 69747dc04d71SMichio Honda char __user *optval, int __user *optlen) 69757dc04d71SMichio Honda { 69767dc04d71SMichio Honda int val = 0; 69777dc04d71SMichio Honda 69787dc04d71SMichio Honda if (len < sizeof(int)) 69797dc04d71SMichio Honda return -EINVAL; 69807dc04d71SMichio Honda 69817dc04d71SMichio Honda len = sizeof(int); 69827dc04d71SMichio Honda if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk)) 69837dc04d71SMichio Honda val = 1; 69847dc04d71SMichio Honda if (put_user(len, optlen)) 69857dc04d71SMichio Honda return -EFAULT; 69867dc04d71SMichio Honda if (copy_to_user(optval, &val, len)) 69877dc04d71SMichio Honda return -EFAULT; 69887dc04d71SMichio Honda return 0; 69897dc04d71SMichio Honda } 69907dc04d71SMichio Honda 69917dc04d71SMichio Honda /* 6992209ba424SWei Yongjun * 8.2.6. Get the Current Identifiers of Associations 6993209ba424SWei Yongjun * (SCTP_GET_ASSOC_ID_LIST) 6994209ba424SWei Yongjun * 6995209ba424SWei Yongjun * This option gets the current list of SCTP association identifiers of 6996209ba424SWei Yongjun * the SCTP associations handled by a one-to-many style socket. 6997209ba424SWei Yongjun */ 6998209ba424SWei Yongjun static int sctp_getsockopt_assoc_ids(struct sock *sk, int len, 6999209ba424SWei Yongjun char __user *optval, int __user *optlen) 7000209ba424SWei Yongjun { 7001209ba424SWei Yongjun struct sctp_sock *sp = sctp_sk(sk); 7002209ba424SWei Yongjun struct sctp_association *asoc; 7003209ba424SWei Yongjun struct sctp_assoc_ids *ids; 7004209ba424SWei Yongjun u32 num = 0; 7005209ba424SWei Yongjun 7006209ba424SWei Yongjun if (sctp_style(sk, TCP)) 7007209ba424SWei Yongjun return -EOPNOTSUPP; 7008209ba424SWei Yongjun 7009209ba424SWei Yongjun if (len < sizeof(struct sctp_assoc_ids)) 7010209ba424SWei Yongjun return -EINVAL; 7011209ba424SWei Yongjun 7012209ba424SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 7013209ba424SWei Yongjun num++; 7014209ba424SWei Yongjun } 7015209ba424SWei Yongjun 7016209ba424SWei Yongjun if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num) 7017209ba424SWei Yongjun return -EINVAL; 7018209ba424SWei Yongjun 7019209ba424SWei Yongjun len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num; 7020209ba424SWei Yongjun 70219ba0b963SMarcelo Ricardo Leitner ids = kmalloc(len, GFP_USER | __GFP_NOWARN); 7022209ba424SWei Yongjun if (unlikely(!ids)) 7023209ba424SWei Yongjun return -ENOMEM; 7024209ba424SWei Yongjun 7025209ba424SWei Yongjun ids->gaids_number_of_ids = num; 7026209ba424SWei Yongjun num = 0; 7027209ba424SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 7028209ba424SWei Yongjun ids->gaids_assoc_id[num++] = asoc->assoc_id; 7029209ba424SWei Yongjun } 7030209ba424SWei Yongjun 7031209ba424SWei Yongjun if (put_user(len, optlen) || copy_to_user(optval, ids, len)) { 7032209ba424SWei Yongjun kfree(ids); 7033209ba424SWei Yongjun return -EFAULT; 7034209ba424SWei Yongjun } 7035209ba424SWei Yongjun 7036209ba424SWei Yongjun kfree(ids); 7037209ba424SWei Yongjun return 0; 7038209ba424SWei Yongjun } 7039209ba424SWei Yongjun 70405aa93bcfSNeil Horman /* 70415aa93bcfSNeil Horman * SCTP_PEER_ADDR_THLDS 70425aa93bcfSNeil Horman * 70435aa93bcfSNeil Horman * This option allows us to fetch the partially failed threshold for one or all 70445aa93bcfSNeil Horman * transports in an association. See Section 6.1 of: 70455aa93bcfSNeil Horman * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 70465aa93bcfSNeil Horman */ 70475aa93bcfSNeil Horman static int sctp_getsockopt_paddr_thresholds(struct sock *sk, 7048d467ac0aSXin Long char __user *optval, int len, 7049d467ac0aSXin Long int __user *optlen, bool v2) 70505aa93bcfSNeil Horman { 7051d467ac0aSXin Long struct sctp_paddrthlds_v2 val; 70525aa93bcfSNeil Horman struct sctp_transport *trans; 70535aa93bcfSNeil Horman struct sctp_association *asoc; 7054d467ac0aSXin Long int min; 70555aa93bcfSNeil Horman 7056d467ac0aSXin Long min = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds); 7057d467ac0aSXin Long if (len < min) 70585aa93bcfSNeil Horman return -EINVAL; 7059d467ac0aSXin Long len = min; 7060d467ac0aSXin Long if (copy_from_user(&val, optval, len)) 70615aa93bcfSNeil Horman return -EFAULT; 70625aa93bcfSNeil Horman 70638add543eSXin Long if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { 70645aa93bcfSNeil Horman trans = sctp_addr_id2transport(sk, &val.spt_address, 70655aa93bcfSNeil Horman val.spt_assoc_id); 70665aa93bcfSNeil Horman if (!trans) 70675aa93bcfSNeil Horman return -ENOENT; 70685aa93bcfSNeil Horman 70695aa93bcfSNeil Horman val.spt_pathmaxrxt = trans->pathmaxrxt; 70705aa93bcfSNeil Horman val.spt_pathpfthld = trans->pf_retrans; 7071d467ac0aSXin Long val.spt_pathcpthld = trans->ps_retrans; 70728add543eSXin Long 7073f794dc23SXin Long goto out; 70748add543eSXin Long } 70758add543eSXin Long 70768add543eSXin Long asoc = sctp_id2assoc(sk, val.spt_assoc_id); 70778add543eSXin Long if (!asoc && val.spt_assoc_id != SCTP_FUTURE_ASSOC && 70788add543eSXin Long sctp_style(sk, UDP)) 70798add543eSXin Long return -EINVAL; 70808add543eSXin Long 70818add543eSXin Long if (asoc) { 70828add543eSXin Long val.spt_pathpfthld = asoc->pf_retrans; 70838add543eSXin Long val.spt_pathmaxrxt = asoc->pathmaxrxt; 7084d467ac0aSXin Long val.spt_pathcpthld = asoc->ps_retrans; 70858add543eSXin Long } else { 70868add543eSXin Long struct sctp_sock *sp = sctp_sk(sk); 70878add543eSXin Long 70888add543eSXin Long val.spt_pathpfthld = sp->pf_retrans; 70898add543eSXin Long val.spt_pathmaxrxt = sp->pathmaxrxt; 7090d467ac0aSXin Long val.spt_pathcpthld = sp->ps_retrans; 70915aa93bcfSNeil Horman } 70925aa93bcfSNeil Horman 7093f794dc23SXin Long out: 70945aa93bcfSNeil Horman if (put_user(len, optlen) || copy_to_user(optval, &val, len)) 70955aa93bcfSNeil Horman return -EFAULT; 70965aa93bcfSNeil Horman 70975aa93bcfSNeil Horman return 0; 70985aa93bcfSNeil Horman } 70995aa93bcfSNeil Horman 7100196d6759SMichele Baldessari /* 7101196d6759SMichele Baldessari * SCTP_GET_ASSOC_STATS 7102196d6759SMichele Baldessari * 7103196d6759SMichele Baldessari * This option retrieves local per endpoint statistics. It is modeled 7104196d6759SMichele Baldessari * after OpenSolaris' implementation 7105196d6759SMichele Baldessari */ 7106196d6759SMichele Baldessari static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, 7107196d6759SMichele Baldessari char __user *optval, 7108196d6759SMichele Baldessari int __user *optlen) 7109196d6759SMichele Baldessari { 7110196d6759SMichele Baldessari struct sctp_assoc_stats sas; 7111196d6759SMichele Baldessari struct sctp_association *asoc = NULL; 7112196d6759SMichele Baldessari 7113196d6759SMichele Baldessari /* User must provide at least the assoc id */ 7114196d6759SMichele Baldessari if (len < sizeof(sctp_assoc_t)) 7115196d6759SMichele Baldessari return -EINVAL; 7116196d6759SMichele Baldessari 7117726bc6b0SGuenter Roeck /* Allow the struct to grow and fill in as much as possible */ 7118726bc6b0SGuenter Roeck len = min_t(size_t, len, sizeof(sas)); 7119726bc6b0SGuenter Roeck 7120196d6759SMichele Baldessari if (copy_from_user(&sas, optval, len)) 7121196d6759SMichele Baldessari return -EFAULT; 7122196d6759SMichele Baldessari 7123196d6759SMichele Baldessari asoc = sctp_id2assoc(sk, sas.sas_assoc_id); 7124196d6759SMichele Baldessari if (!asoc) 7125196d6759SMichele Baldessari return -EINVAL; 7126196d6759SMichele Baldessari 7127196d6759SMichele Baldessari sas.sas_rtxchunks = asoc->stats.rtxchunks; 7128196d6759SMichele Baldessari sas.sas_gapcnt = asoc->stats.gapcnt; 7129196d6759SMichele Baldessari sas.sas_outofseqtsns = asoc->stats.outofseqtsns; 7130196d6759SMichele Baldessari sas.sas_osacks = asoc->stats.osacks; 7131196d6759SMichele Baldessari sas.sas_isacks = asoc->stats.isacks; 7132196d6759SMichele Baldessari sas.sas_octrlchunks = asoc->stats.octrlchunks; 7133196d6759SMichele Baldessari sas.sas_ictrlchunks = asoc->stats.ictrlchunks; 7134196d6759SMichele Baldessari sas.sas_oodchunks = asoc->stats.oodchunks; 7135196d6759SMichele Baldessari sas.sas_iodchunks = asoc->stats.iodchunks; 7136196d6759SMichele Baldessari sas.sas_ouodchunks = asoc->stats.ouodchunks; 7137196d6759SMichele Baldessari sas.sas_iuodchunks = asoc->stats.iuodchunks; 7138196d6759SMichele Baldessari sas.sas_idupchunks = asoc->stats.idupchunks; 7139196d6759SMichele Baldessari sas.sas_opackets = asoc->stats.opackets; 7140196d6759SMichele Baldessari sas.sas_ipackets = asoc->stats.ipackets; 7141196d6759SMichele Baldessari 7142196d6759SMichele Baldessari /* New high max rto observed, will return 0 if not a single 7143196d6759SMichele Baldessari * RTO update took place. obs_rto_ipaddr will be bogus 7144196d6759SMichele Baldessari * in such a case 7145196d6759SMichele Baldessari */ 7146196d6759SMichele Baldessari sas.sas_maxrto = asoc->stats.max_obs_rto; 7147196d6759SMichele Baldessari memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr, 7148196d6759SMichele Baldessari sizeof(struct sockaddr_storage)); 7149196d6759SMichele Baldessari 7150196d6759SMichele Baldessari /* Mark beginning of a new observation period */ 7151196d6759SMichele Baldessari asoc->stats.max_obs_rto = asoc->rto_min; 7152196d6759SMichele Baldessari 7153196d6759SMichele Baldessari if (put_user(len, optlen)) 7154196d6759SMichele Baldessari return -EFAULT; 7155196d6759SMichele Baldessari 7156bb33381dSDaniel Borkmann pr_debug("%s: len:%d, assoc_id:%d\n", __func__, len, sas.sas_assoc_id); 7157196d6759SMichele Baldessari 7158196d6759SMichele Baldessari if (copy_to_user(optval, &sas, len)) 7159196d6759SMichele Baldessari return -EFAULT; 7160196d6759SMichele Baldessari 7161196d6759SMichele Baldessari return 0; 7162196d6759SMichele Baldessari } 7163196d6759SMichele Baldessari 71640d3a421dSGeir Ola Vaagland static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, 71650d3a421dSGeir Ola Vaagland char __user *optval, 71660d3a421dSGeir Ola Vaagland int __user *optlen) 71670d3a421dSGeir Ola Vaagland { 71680d3a421dSGeir Ola Vaagland int val = 0; 71690d3a421dSGeir Ola Vaagland 71700d3a421dSGeir Ola Vaagland if (len < sizeof(int)) 71710d3a421dSGeir Ola Vaagland return -EINVAL; 71720d3a421dSGeir Ola Vaagland 71730d3a421dSGeir Ola Vaagland len = sizeof(int); 71740d3a421dSGeir Ola Vaagland if (sctp_sk(sk)->recvrcvinfo) 71750d3a421dSGeir Ola Vaagland val = 1; 71760d3a421dSGeir Ola Vaagland if (put_user(len, optlen)) 71770d3a421dSGeir Ola Vaagland return -EFAULT; 71780d3a421dSGeir Ola Vaagland if (copy_to_user(optval, &val, len)) 71790d3a421dSGeir Ola Vaagland return -EFAULT; 71800d3a421dSGeir Ola Vaagland 71810d3a421dSGeir Ola Vaagland return 0; 71820d3a421dSGeir Ola Vaagland } 71830d3a421dSGeir Ola Vaagland 71842347c80fSGeir Ola Vaagland static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len, 71852347c80fSGeir Ola Vaagland char __user *optval, 71862347c80fSGeir Ola Vaagland int __user *optlen) 71872347c80fSGeir Ola Vaagland { 71882347c80fSGeir Ola Vaagland int val = 0; 71892347c80fSGeir Ola Vaagland 71902347c80fSGeir Ola Vaagland if (len < sizeof(int)) 71912347c80fSGeir Ola Vaagland return -EINVAL; 71922347c80fSGeir Ola Vaagland 71932347c80fSGeir Ola Vaagland len = sizeof(int); 71942347c80fSGeir Ola Vaagland if (sctp_sk(sk)->recvnxtinfo) 71952347c80fSGeir Ola Vaagland val = 1; 71962347c80fSGeir Ola Vaagland if (put_user(len, optlen)) 71972347c80fSGeir Ola Vaagland return -EFAULT; 71982347c80fSGeir Ola Vaagland if (copy_to_user(optval, &val, len)) 71992347c80fSGeir Ola Vaagland return -EFAULT; 72002347c80fSGeir Ola Vaagland 72012347c80fSGeir Ola Vaagland return 0; 72022347c80fSGeir Ola Vaagland } 72032347c80fSGeir Ola Vaagland 720428aa4c26SXin Long static int sctp_getsockopt_pr_supported(struct sock *sk, int len, 720528aa4c26SXin Long char __user *optval, 720628aa4c26SXin Long int __user *optlen) 720728aa4c26SXin Long { 720828aa4c26SXin Long struct sctp_assoc_value params; 720928aa4c26SXin Long struct sctp_association *asoc; 721028aa4c26SXin Long int retval = -EFAULT; 721128aa4c26SXin Long 721228aa4c26SXin Long if (len < sizeof(params)) { 721328aa4c26SXin Long retval = -EINVAL; 721428aa4c26SXin Long goto out; 721528aa4c26SXin Long } 721628aa4c26SXin Long 721728aa4c26SXin Long len = sizeof(params); 721828aa4c26SXin Long if (copy_from_user(¶ms, optval, len)) 721928aa4c26SXin Long goto out; 722028aa4c26SXin Long 722128aa4c26SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7222fb195605SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 7223fb195605SXin Long sctp_style(sk, UDP)) { 722428aa4c26SXin Long retval = -EINVAL; 722528aa4c26SXin Long goto out; 722628aa4c26SXin Long } 722728aa4c26SXin Long 72281c134753SXin Long params.assoc_value = asoc ? asoc->peer.prsctp_capable 7229fb195605SXin Long : sctp_sk(sk)->ep->prsctp_enable; 7230fb195605SXin Long 723128aa4c26SXin Long if (put_user(len, optlen)) 723228aa4c26SXin Long goto out; 723328aa4c26SXin Long 723428aa4c26SXin Long if (copy_to_user(optval, ¶ms, len)) 723528aa4c26SXin Long goto out; 723628aa4c26SXin Long 723728aa4c26SXin Long retval = 0; 723828aa4c26SXin Long 723928aa4c26SXin Long out: 724028aa4c26SXin Long return retval; 724128aa4c26SXin Long } 724228aa4c26SXin Long 7243f959fb44SXin Long static int sctp_getsockopt_default_prinfo(struct sock *sk, int len, 7244f959fb44SXin Long char __user *optval, 7245f959fb44SXin Long int __user *optlen) 7246f959fb44SXin Long { 7247f959fb44SXin Long struct sctp_default_prinfo info; 7248f959fb44SXin Long struct sctp_association *asoc; 7249f959fb44SXin Long int retval = -EFAULT; 7250f959fb44SXin Long 7251f959fb44SXin Long if (len < sizeof(info)) { 7252f959fb44SXin Long retval = -EINVAL; 7253f959fb44SXin Long goto out; 7254f959fb44SXin Long } 7255f959fb44SXin Long 7256f959fb44SXin Long len = sizeof(info); 7257f959fb44SXin Long if (copy_from_user(&info, optval, len)) 7258f959fb44SXin Long goto out; 7259f959fb44SXin Long 7260f959fb44SXin Long asoc = sctp_id2assoc(sk, info.pr_assoc_id); 72613a583059SXin Long if (!asoc && info.pr_assoc_id != SCTP_FUTURE_ASSOC && 72623a583059SXin Long sctp_style(sk, UDP)) { 72633a583059SXin Long retval = -EINVAL; 72643a583059SXin Long goto out; 72653a583059SXin Long } 72663a583059SXin Long 7267f959fb44SXin Long if (asoc) { 7268f959fb44SXin Long info.pr_policy = SCTP_PR_POLICY(asoc->default_flags); 7269f959fb44SXin Long info.pr_value = asoc->default_timetolive; 72703a583059SXin Long } else { 7271f959fb44SXin Long struct sctp_sock *sp = sctp_sk(sk); 7272f959fb44SXin Long 7273f959fb44SXin Long info.pr_policy = SCTP_PR_POLICY(sp->default_flags); 7274f959fb44SXin Long info.pr_value = sp->default_timetolive; 7275f959fb44SXin Long } 7276f959fb44SXin Long 7277f959fb44SXin Long if (put_user(len, optlen)) 7278f959fb44SXin Long goto out; 7279f959fb44SXin Long 7280f959fb44SXin Long if (copy_to_user(optval, &info, len)) 7281f959fb44SXin Long goto out; 7282f959fb44SXin Long 7283f959fb44SXin Long retval = 0; 7284f959fb44SXin Long 7285f959fb44SXin Long out: 7286f959fb44SXin Long return retval; 7287f959fb44SXin Long } 7288f959fb44SXin Long 7289826d253dSXin Long static int sctp_getsockopt_pr_assocstatus(struct sock *sk, int len, 7290826d253dSXin Long char __user *optval, 7291826d253dSXin Long int __user *optlen) 7292826d253dSXin Long { 7293826d253dSXin Long struct sctp_prstatus params; 7294826d253dSXin Long struct sctp_association *asoc; 7295826d253dSXin Long int policy; 7296826d253dSXin Long int retval = -EINVAL; 7297826d253dSXin Long 7298826d253dSXin Long if (len < sizeof(params)) 7299826d253dSXin Long goto out; 7300826d253dSXin Long 7301826d253dSXin Long len = sizeof(params); 7302826d253dSXin Long if (copy_from_user(¶ms, optval, len)) { 7303826d253dSXin Long retval = -EFAULT; 7304826d253dSXin Long goto out; 7305826d253dSXin Long } 7306826d253dSXin Long 7307826d253dSXin Long policy = params.sprstat_policy; 730871335836SXin Long if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) || 730971335836SXin Long ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK))) 7310826d253dSXin Long goto out; 7311826d253dSXin Long 7312826d253dSXin Long asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); 7313826d253dSXin Long if (!asoc) 7314826d253dSXin Long goto out; 7315826d253dSXin Long 731671335836SXin Long if (policy == SCTP_PR_SCTP_ALL) { 7317826d253dSXin Long params.sprstat_abandoned_unsent = 0; 7318826d253dSXin Long params.sprstat_abandoned_sent = 0; 7319826d253dSXin Long for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { 7320826d253dSXin Long params.sprstat_abandoned_unsent += 7321826d253dSXin Long asoc->abandoned_unsent[policy]; 7322826d253dSXin Long params.sprstat_abandoned_sent += 7323826d253dSXin Long asoc->abandoned_sent[policy]; 7324826d253dSXin Long } 7325826d253dSXin Long } else { 7326826d253dSXin Long params.sprstat_abandoned_unsent = 7327826d253dSXin Long asoc->abandoned_unsent[__SCTP_PR_INDEX(policy)]; 7328826d253dSXin Long params.sprstat_abandoned_sent = 7329826d253dSXin Long asoc->abandoned_sent[__SCTP_PR_INDEX(policy)]; 7330826d253dSXin Long } 7331826d253dSXin Long 7332826d253dSXin Long if (put_user(len, optlen)) { 7333826d253dSXin Long retval = -EFAULT; 7334826d253dSXin Long goto out; 7335826d253dSXin Long } 7336826d253dSXin Long 7337826d253dSXin Long if (copy_to_user(optval, ¶ms, len)) { 7338826d253dSXin Long retval = -EFAULT; 7339826d253dSXin Long goto out; 7340826d253dSXin Long } 7341826d253dSXin Long 7342826d253dSXin Long retval = 0; 7343826d253dSXin Long 7344826d253dSXin Long out: 7345826d253dSXin Long return retval; 7346826d253dSXin Long } 7347826d253dSXin Long 7348d229d48dSXin Long static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len, 7349d229d48dSXin Long char __user *optval, 7350d229d48dSXin Long int __user *optlen) 7351d229d48dSXin Long { 7352f952be79SMarcelo Ricardo Leitner struct sctp_stream_out_ext *streamoute; 7353d229d48dSXin Long struct sctp_association *asoc; 7354d229d48dSXin Long struct sctp_prstatus params; 7355d229d48dSXin Long int retval = -EINVAL; 7356d229d48dSXin Long int policy; 7357d229d48dSXin Long 7358d229d48dSXin Long if (len < sizeof(params)) 7359d229d48dSXin Long goto out; 7360d229d48dSXin Long 7361d229d48dSXin Long len = sizeof(params); 7362d229d48dSXin Long if (copy_from_user(¶ms, optval, len)) { 7363d229d48dSXin Long retval = -EFAULT; 7364d229d48dSXin Long goto out; 7365d229d48dSXin Long } 7366d229d48dSXin Long 7367d229d48dSXin Long policy = params.sprstat_policy; 736871335836SXin Long if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) || 736971335836SXin Long ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK))) 7370d229d48dSXin Long goto out; 7371d229d48dSXin Long 7372d229d48dSXin Long asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); 7373cee360abSXin Long if (!asoc || params.sprstat_sid >= asoc->stream.outcnt) 7374d229d48dSXin Long goto out; 7375d229d48dSXin Long 737605364ca0SKonstantin Khorenko streamoute = SCTP_SO(&asoc->stream, params.sprstat_sid)->ext; 7377f952be79SMarcelo Ricardo Leitner if (!streamoute) { 7378f952be79SMarcelo Ricardo Leitner /* Not allocated yet, means all stats are 0 */ 7379f952be79SMarcelo Ricardo Leitner params.sprstat_abandoned_unsent = 0; 7380f952be79SMarcelo Ricardo Leitner params.sprstat_abandoned_sent = 0; 7381f952be79SMarcelo Ricardo Leitner retval = 0; 7382f952be79SMarcelo Ricardo Leitner goto out; 7383f952be79SMarcelo Ricardo Leitner } 7384f952be79SMarcelo Ricardo Leitner 73850ac1077eSXin Long if (policy == SCTP_PR_SCTP_ALL) { 7386d229d48dSXin Long params.sprstat_abandoned_unsent = 0; 7387d229d48dSXin Long params.sprstat_abandoned_sent = 0; 7388d229d48dSXin Long for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { 7389d229d48dSXin Long params.sprstat_abandoned_unsent += 7390f952be79SMarcelo Ricardo Leitner streamoute->abandoned_unsent[policy]; 7391d229d48dSXin Long params.sprstat_abandoned_sent += 7392f952be79SMarcelo Ricardo Leitner streamoute->abandoned_sent[policy]; 7393d229d48dSXin Long } 7394d229d48dSXin Long } else { 7395d229d48dSXin Long params.sprstat_abandoned_unsent = 7396f952be79SMarcelo Ricardo Leitner streamoute->abandoned_unsent[__SCTP_PR_INDEX(policy)]; 7397d229d48dSXin Long params.sprstat_abandoned_sent = 7398f952be79SMarcelo Ricardo Leitner streamoute->abandoned_sent[__SCTP_PR_INDEX(policy)]; 7399d229d48dSXin Long } 7400d229d48dSXin Long 7401d229d48dSXin Long if (put_user(len, optlen) || copy_to_user(optval, ¶ms, len)) { 7402d229d48dSXin Long retval = -EFAULT; 7403d229d48dSXin Long goto out; 7404d229d48dSXin Long } 7405d229d48dSXin Long 7406d229d48dSXin Long retval = 0; 7407d229d48dSXin Long 7408d229d48dSXin Long out: 7409d229d48dSXin Long return retval; 7410d229d48dSXin Long } 7411d229d48dSXin Long 7412c0d8bab6SXin Long static int sctp_getsockopt_reconfig_supported(struct sock *sk, int len, 7413c0d8bab6SXin Long char __user *optval, 7414c0d8bab6SXin Long int __user *optlen) 7415c0d8bab6SXin Long { 7416c0d8bab6SXin Long struct sctp_assoc_value params; 7417c0d8bab6SXin Long struct sctp_association *asoc; 7418c0d8bab6SXin Long int retval = -EFAULT; 7419c0d8bab6SXin Long 7420c0d8bab6SXin Long if (len < sizeof(params)) { 7421c0d8bab6SXin Long retval = -EINVAL; 7422c0d8bab6SXin Long goto out; 7423c0d8bab6SXin Long } 7424c0d8bab6SXin Long 7425c0d8bab6SXin Long len = sizeof(params); 7426c0d8bab6SXin Long if (copy_from_user(¶ms, optval, len)) 7427c0d8bab6SXin Long goto out; 7428c0d8bab6SXin Long 7429c0d8bab6SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7430acce7f3bSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 7431acce7f3bSXin Long sctp_style(sk, UDP)) { 7432c0d8bab6SXin Long retval = -EINVAL; 7433c0d8bab6SXin Long goto out; 7434c0d8bab6SXin Long } 7435c0d8bab6SXin Long 7436a96701fbSXin Long params.assoc_value = asoc ? asoc->peer.reconf_capable 7437acce7f3bSXin Long : sctp_sk(sk)->ep->reconf_enable; 7438acce7f3bSXin Long 7439c0d8bab6SXin Long if (put_user(len, optlen)) 7440c0d8bab6SXin Long goto out; 7441c0d8bab6SXin Long 7442c0d8bab6SXin Long if (copy_to_user(optval, ¶ms, len)) 7443c0d8bab6SXin Long goto out; 7444c0d8bab6SXin Long 7445c0d8bab6SXin Long retval = 0; 7446c0d8bab6SXin Long 7447c0d8bab6SXin Long out: 7448c0d8bab6SXin Long return retval; 7449c0d8bab6SXin Long } 7450c0d8bab6SXin Long 74519fb657aeSXin Long static int sctp_getsockopt_enable_strreset(struct sock *sk, int len, 74529fb657aeSXin Long char __user *optval, 74539fb657aeSXin Long int __user *optlen) 74549fb657aeSXin Long { 74559fb657aeSXin Long struct sctp_assoc_value params; 74569fb657aeSXin Long struct sctp_association *asoc; 74579fb657aeSXin Long int retval = -EFAULT; 74589fb657aeSXin Long 74599fb657aeSXin Long if (len < sizeof(params)) { 74609fb657aeSXin Long retval = -EINVAL; 74619fb657aeSXin Long goto out; 74629fb657aeSXin Long } 74639fb657aeSXin Long 74649fb657aeSXin Long len = sizeof(params); 74659fb657aeSXin Long if (copy_from_user(¶ms, optval, len)) 74669fb657aeSXin Long goto out; 74679fb657aeSXin Long 74689fb657aeSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 746999a62135SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 747099a62135SXin Long sctp_style(sk, UDP)) { 74719fb657aeSXin Long retval = -EINVAL; 74729fb657aeSXin Long goto out; 74739fb657aeSXin Long } 74749fb657aeSXin Long 747599a62135SXin Long params.assoc_value = asoc ? asoc->strreset_enable 747699a62135SXin Long : sctp_sk(sk)->ep->strreset_enable; 747799a62135SXin Long 74789fb657aeSXin Long if (put_user(len, optlen)) 74799fb657aeSXin Long goto out; 74809fb657aeSXin Long 74819fb657aeSXin Long if (copy_to_user(optval, ¶ms, len)) 74829fb657aeSXin Long goto out; 74839fb657aeSXin Long 74849fb657aeSXin Long retval = 0; 74859fb657aeSXin Long 74869fb657aeSXin Long out: 74879fb657aeSXin Long return retval; 74889fb657aeSXin Long } 74899fb657aeSXin Long 749013aa8770SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler(struct sock *sk, int len, 749113aa8770SMarcelo Ricardo Leitner char __user *optval, 749213aa8770SMarcelo Ricardo Leitner int __user *optlen) 749313aa8770SMarcelo Ricardo Leitner { 749413aa8770SMarcelo Ricardo Leitner struct sctp_assoc_value params; 749513aa8770SMarcelo Ricardo Leitner struct sctp_association *asoc; 749613aa8770SMarcelo Ricardo Leitner int retval = -EFAULT; 749713aa8770SMarcelo Ricardo Leitner 749813aa8770SMarcelo Ricardo Leitner if (len < sizeof(params)) { 749913aa8770SMarcelo Ricardo Leitner retval = -EINVAL; 750013aa8770SMarcelo Ricardo Leitner goto out; 750113aa8770SMarcelo Ricardo Leitner } 750213aa8770SMarcelo Ricardo Leitner 750313aa8770SMarcelo Ricardo Leitner len = sizeof(params); 750413aa8770SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, len)) 750513aa8770SMarcelo Ricardo Leitner goto out; 750613aa8770SMarcelo Ricardo Leitner 750713aa8770SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 75087efba10dSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 75097efba10dSXin Long sctp_style(sk, UDP)) { 751013aa8770SMarcelo Ricardo Leitner retval = -EINVAL; 751113aa8770SMarcelo Ricardo Leitner goto out; 751213aa8770SMarcelo Ricardo Leitner } 751313aa8770SMarcelo Ricardo Leitner 75147efba10dSXin Long params.assoc_value = asoc ? sctp_sched_get_sched(asoc) 75157efba10dSXin Long : sctp_sk(sk)->default_ss; 751613aa8770SMarcelo Ricardo Leitner 751713aa8770SMarcelo Ricardo Leitner if (put_user(len, optlen)) 751813aa8770SMarcelo Ricardo Leitner goto out; 751913aa8770SMarcelo Ricardo Leitner 752013aa8770SMarcelo Ricardo Leitner if (copy_to_user(optval, ¶ms, len)) 752113aa8770SMarcelo Ricardo Leitner goto out; 752213aa8770SMarcelo Ricardo Leitner 752313aa8770SMarcelo Ricardo Leitner retval = 0; 752413aa8770SMarcelo Ricardo Leitner 752513aa8770SMarcelo Ricardo Leitner out: 752613aa8770SMarcelo Ricardo Leitner return retval; 752713aa8770SMarcelo Ricardo Leitner } 752813aa8770SMarcelo Ricardo Leitner 75290ccdf3c7SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler_value(struct sock *sk, int len, 75300ccdf3c7SMarcelo Ricardo Leitner char __user *optval, 75310ccdf3c7SMarcelo Ricardo Leitner int __user *optlen) 75320ccdf3c7SMarcelo Ricardo Leitner { 75330ccdf3c7SMarcelo Ricardo Leitner struct sctp_stream_value params; 75340ccdf3c7SMarcelo Ricardo Leitner struct sctp_association *asoc; 75350ccdf3c7SMarcelo Ricardo Leitner int retval = -EFAULT; 75360ccdf3c7SMarcelo Ricardo Leitner 75370ccdf3c7SMarcelo Ricardo Leitner if (len < sizeof(params)) { 75380ccdf3c7SMarcelo Ricardo Leitner retval = -EINVAL; 75390ccdf3c7SMarcelo Ricardo Leitner goto out; 75400ccdf3c7SMarcelo Ricardo Leitner } 75410ccdf3c7SMarcelo Ricardo Leitner 75420ccdf3c7SMarcelo Ricardo Leitner len = sizeof(params); 75430ccdf3c7SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, len)) 75440ccdf3c7SMarcelo Ricardo Leitner goto out; 75450ccdf3c7SMarcelo Ricardo Leitner 75460ccdf3c7SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 75470ccdf3c7SMarcelo Ricardo Leitner if (!asoc) { 75480ccdf3c7SMarcelo Ricardo Leitner retval = -EINVAL; 75490ccdf3c7SMarcelo Ricardo Leitner goto out; 75500ccdf3c7SMarcelo Ricardo Leitner } 75510ccdf3c7SMarcelo Ricardo Leitner 75520ccdf3c7SMarcelo Ricardo Leitner retval = sctp_sched_get_value(asoc, params.stream_id, 75530ccdf3c7SMarcelo Ricardo Leitner ¶ms.stream_value); 75540ccdf3c7SMarcelo Ricardo Leitner if (retval) 75550ccdf3c7SMarcelo Ricardo Leitner goto out; 75560ccdf3c7SMarcelo Ricardo Leitner 75570ccdf3c7SMarcelo Ricardo Leitner if (put_user(len, optlen)) { 75580ccdf3c7SMarcelo Ricardo Leitner retval = -EFAULT; 75590ccdf3c7SMarcelo Ricardo Leitner goto out; 75600ccdf3c7SMarcelo Ricardo Leitner } 75610ccdf3c7SMarcelo Ricardo Leitner 75620ccdf3c7SMarcelo Ricardo Leitner if (copy_to_user(optval, ¶ms, len)) { 75630ccdf3c7SMarcelo Ricardo Leitner retval = -EFAULT; 75640ccdf3c7SMarcelo Ricardo Leitner goto out; 75650ccdf3c7SMarcelo Ricardo Leitner } 75660ccdf3c7SMarcelo Ricardo Leitner 75670ccdf3c7SMarcelo Ricardo Leitner out: 75680ccdf3c7SMarcelo Ricardo Leitner return retval; 75690ccdf3c7SMarcelo Ricardo Leitner } 75700ccdf3c7SMarcelo Ricardo Leitner 7571772a5869SXin Long static int sctp_getsockopt_interleaving_supported(struct sock *sk, int len, 7572772a5869SXin Long char __user *optval, 7573772a5869SXin Long int __user *optlen) 7574772a5869SXin Long { 7575772a5869SXin Long struct sctp_assoc_value params; 7576772a5869SXin Long struct sctp_association *asoc; 7577772a5869SXin Long int retval = -EFAULT; 7578772a5869SXin Long 7579772a5869SXin Long if (len < sizeof(params)) { 7580772a5869SXin Long retval = -EINVAL; 7581772a5869SXin Long goto out; 7582772a5869SXin Long } 7583772a5869SXin Long 7584772a5869SXin Long len = sizeof(params); 7585772a5869SXin Long if (copy_from_user(¶ms, optval, len)) 7586772a5869SXin Long goto out; 7587772a5869SXin Long 7588772a5869SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 75892e7709d1SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 75902e7709d1SXin Long sctp_style(sk, UDP)) { 7591772a5869SXin Long retval = -EINVAL; 7592772a5869SXin Long goto out; 7593772a5869SXin Long } 7594772a5869SXin Long 7595da1f6d4dSXin Long params.assoc_value = asoc ? asoc->peer.intl_capable 7596e55f4b8bSXin Long : sctp_sk(sk)->ep->intl_enable; 75972e7709d1SXin Long 7598772a5869SXin Long if (put_user(len, optlen)) 7599772a5869SXin Long goto out; 7600772a5869SXin Long 7601772a5869SXin Long if (copy_to_user(optval, ¶ms, len)) 7602772a5869SXin Long goto out; 7603772a5869SXin Long 7604772a5869SXin Long retval = 0; 7605772a5869SXin Long 7606772a5869SXin Long out: 7607772a5869SXin Long return retval; 7608772a5869SXin Long } 7609772a5869SXin Long 7610b0e9a2feSXin Long static int sctp_getsockopt_reuse_port(struct sock *sk, int len, 7611b0e9a2feSXin Long char __user *optval, 7612b0e9a2feSXin Long int __user *optlen) 7613b0e9a2feSXin Long { 7614b0e9a2feSXin Long int val; 7615b0e9a2feSXin Long 7616b0e9a2feSXin Long if (len < sizeof(int)) 7617b0e9a2feSXin Long return -EINVAL; 7618b0e9a2feSXin Long 7619b0e9a2feSXin Long len = sizeof(int); 7620b0e9a2feSXin Long val = sctp_sk(sk)->reuse; 7621b0e9a2feSXin Long if (put_user(len, optlen)) 7622b0e9a2feSXin Long return -EFAULT; 7623b0e9a2feSXin Long 7624b0e9a2feSXin Long if (copy_to_user(optval, &val, len)) 7625b0e9a2feSXin Long return -EFAULT; 7626b0e9a2feSXin Long 7627b0e9a2feSXin Long return 0; 7628b0e9a2feSXin Long } 7629b0e9a2feSXin Long 7630480ba9c1SXin Long static int sctp_getsockopt_event(struct sock *sk, int len, char __user *optval, 7631480ba9c1SXin Long int __user *optlen) 7632480ba9c1SXin Long { 7633480ba9c1SXin Long struct sctp_association *asoc; 7634480ba9c1SXin Long struct sctp_event param; 7635480ba9c1SXin Long __u16 subscribe; 7636480ba9c1SXin Long 7637480ba9c1SXin Long if (len < sizeof(param)) 7638480ba9c1SXin Long return -EINVAL; 7639480ba9c1SXin Long 7640480ba9c1SXin Long len = sizeof(param); 7641480ba9c1SXin Long if (copy_from_user(¶m, optval, len)) 7642480ba9c1SXin Long return -EFAULT; 7643480ba9c1SXin Long 7644480ba9c1SXin Long if (param.se_type < SCTP_SN_TYPE_BASE || 7645480ba9c1SXin Long param.se_type > SCTP_SN_TYPE_MAX) 7646480ba9c1SXin Long return -EINVAL; 7647480ba9c1SXin Long 7648480ba9c1SXin Long asoc = sctp_id2assoc(sk, param.se_assoc_id); 7649d251f05eSXin Long if (!asoc && param.se_assoc_id != SCTP_FUTURE_ASSOC && 7650d251f05eSXin Long sctp_style(sk, UDP)) 7651d251f05eSXin Long return -EINVAL; 7652d251f05eSXin Long 7653480ba9c1SXin Long subscribe = asoc ? asoc->subscribe : sctp_sk(sk)->subscribe; 7654480ba9c1SXin Long param.se_on = sctp_ulpevent_type_enabled(subscribe, param.se_type); 7655480ba9c1SXin Long 7656480ba9c1SXin Long if (put_user(len, optlen)) 7657480ba9c1SXin Long return -EFAULT; 7658480ba9c1SXin Long 7659480ba9c1SXin Long if (copy_to_user(optval, ¶m, len)) 7660480ba9c1SXin Long return -EFAULT; 7661480ba9c1SXin Long 7662480ba9c1SXin Long return 0; 7663480ba9c1SXin Long } 7664480ba9c1SXin Long 7665df2c71ffSXin Long static int sctp_getsockopt_asconf_supported(struct sock *sk, int len, 7666df2c71ffSXin Long char __user *optval, 7667df2c71ffSXin Long int __user *optlen) 7668df2c71ffSXin Long { 7669df2c71ffSXin Long struct sctp_assoc_value params; 7670df2c71ffSXin Long struct sctp_association *asoc; 7671df2c71ffSXin Long int retval = -EFAULT; 7672df2c71ffSXin Long 7673df2c71ffSXin Long if (len < sizeof(params)) { 7674df2c71ffSXin Long retval = -EINVAL; 7675df2c71ffSXin Long goto out; 7676df2c71ffSXin Long } 7677df2c71ffSXin Long 7678df2c71ffSXin Long len = sizeof(params); 7679df2c71ffSXin Long if (copy_from_user(¶ms, optval, len)) 7680df2c71ffSXin Long goto out; 7681df2c71ffSXin Long 7682df2c71ffSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7683df2c71ffSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 7684df2c71ffSXin Long sctp_style(sk, UDP)) { 7685df2c71ffSXin Long retval = -EINVAL; 7686df2c71ffSXin Long goto out; 7687df2c71ffSXin Long } 7688df2c71ffSXin Long 7689df2c71ffSXin Long params.assoc_value = asoc ? asoc->peer.asconf_capable 7690df2c71ffSXin Long : sctp_sk(sk)->ep->asconf_enable; 7691df2c71ffSXin Long 7692df2c71ffSXin Long if (put_user(len, optlen)) 7693df2c71ffSXin Long goto out; 7694df2c71ffSXin Long 7695df2c71ffSXin Long if (copy_to_user(optval, ¶ms, len)) 7696df2c71ffSXin Long goto out; 7697df2c71ffSXin Long 7698df2c71ffSXin Long retval = 0; 7699df2c71ffSXin Long 7700df2c71ffSXin Long out: 7701df2c71ffSXin Long return retval; 7702df2c71ffSXin Long } 7703df2c71ffSXin Long 770456dd525aSXin Long static int sctp_getsockopt_auth_supported(struct sock *sk, int len, 770556dd525aSXin Long char __user *optval, 770656dd525aSXin Long int __user *optlen) 770756dd525aSXin Long { 770856dd525aSXin Long struct sctp_assoc_value params; 770956dd525aSXin Long struct sctp_association *asoc; 771056dd525aSXin Long int retval = -EFAULT; 771156dd525aSXin Long 771256dd525aSXin Long if (len < sizeof(params)) { 771356dd525aSXin Long retval = -EINVAL; 771456dd525aSXin Long goto out; 771556dd525aSXin Long } 771656dd525aSXin Long 771756dd525aSXin Long len = sizeof(params); 771856dd525aSXin Long if (copy_from_user(¶ms, optval, len)) 771956dd525aSXin Long goto out; 772056dd525aSXin Long 772156dd525aSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 772256dd525aSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 772356dd525aSXin Long sctp_style(sk, UDP)) { 772456dd525aSXin Long retval = -EINVAL; 772556dd525aSXin Long goto out; 772656dd525aSXin Long } 772756dd525aSXin Long 772856dd525aSXin Long params.assoc_value = asoc ? asoc->peer.auth_capable 772956dd525aSXin Long : sctp_sk(sk)->ep->auth_enable; 773056dd525aSXin Long 773156dd525aSXin Long if (put_user(len, optlen)) 773256dd525aSXin Long goto out; 773356dd525aSXin Long 773456dd525aSXin Long if (copy_to_user(optval, ¶ms, len)) 773556dd525aSXin Long goto out; 773656dd525aSXin Long 773756dd525aSXin Long retval = 0; 773856dd525aSXin Long 773956dd525aSXin Long out: 774056dd525aSXin Long return retval; 774156dd525aSXin Long } 774256dd525aSXin Long 7743d5886b91SXin Long static int sctp_getsockopt_ecn_supported(struct sock *sk, int len, 7744d5886b91SXin Long char __user *optval, 7745d5886b91SXin Long int __user *optlen) 7746d5886b91SXin Long { 7747d5886b91SXin Long struct sctp_assoc_value params; 7748d5886b91SXin Long struct sctp_association *asoc; 7749d5886b91SXin Long int retval = -EFAULT; 7750d5886b91SXin Long 7751d5886b91SXin Long if (len < sizeof(params)) { 7752d5886b91SXin Long retval = -EINVAL; 7753d5886b91SXin Long goto out; 7754d5886b91SXin Long } 7755d5886b91SXin Long 7756d5886b91SXin Long len = sizeof(params); 7757d5886b91SXin Long if (copy_from_user(¶ms, optval, len)) 7758d5886b91SXin Long goto out; 7759d5886b91SXin Long 7760d5886b91SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7761d5886b91SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 7762d5886b91SXin Long sctp_style(sk, UDP)) { 7763d5886b91SXin Long retval = -EINVAL; 7764d5886b91SXin Long goto out; 7765d5886b91SXin Long } 7766d5886b91SXin Long 7767d5886b91SXin Long params.assoc_value = asoc ? asoc->peer.ecn_capable 7768d5886b91SXin Long : sctp_sk(sk)->ep->ecn_enable; 7769d5886b91SXin Long 7770d5886b91SXin Long if (put_user(len, optlen)) 7771d5886b91SXin Long goto out; 7772d5886b91SXin Long 7773d5886b91SXin Long if (copy_to_user(optval, ¶ms, len)) 7774d5886b91SXin Long goto out; 7775d5886b91SXin Long 7776d5886b91SXin Long retval = 0; 7777d5886b91SXin Long 7778d5886b91SXin Long out: 7779d5886b91SXin Long return retval; 7780d5886b91SXin Long } 7781d5886b91SXin Long 77828d2a6935SXin Long static int sctp_getsockopt_pf_expose(struct sock *sk, int len, 77838d2a6935SXin Long char __user *optval, 77848d2a6935SXin Long int __user *optlen) 77858d2a6935SXin Long { 77868d2a6935SXin Long struct sctp_assoc_value params; 77878d2a6935SXin Long struct sctp_association *asoc; 77888d2a6935SXin Long int retval = -EFAULT; 77898d2a6935SXin Long 77908d2a6935SXin Long if (len < sizeof(params)) { 77918d2a6935SXin Long retval = -EINVAL; 77928d2a6935SXin Long goto out; 77938d2a6935SXin Long } 77948d2a6935SXin Long 77958d2a6935SXin Long len = sizeof(params); 77968d2a6935SXin Long if (copy_from_user(¶ms, optval, len)) 77978d2a6935SXin Long goto out; 77988d2a6935SXin Long 77998d2a6935SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 78008d2a6935SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 78018d2a6935SXin Long sctp_style(sk, UDP)) { 78028d2a6935SXin Long retval = -EINVAL; 78038d2a6935SXin Long goto out; 78048d2a6935SXin Long } 78058d2a6935SXin Long 78068d2a6935SXin Long params.assoc_value = asoc ? asoc->pf_expose 78078d2a6935SXin Long : sctp_sk(sk)->pf_expose; 78088d2a6935SXin Long 78098d2a6935SXin Long if (put_user(len, optlen)) 78108d2a6935SXin Long goto out; 78118d2a6935SXin Long 78128d2a6935SXin Long if (copy_to_user(optval, ¶ms, len)) 78138d2a6935SXin Long goto out; 78148d2a6935SXin Long 78158d2a6935SXin Long retval = 0; 78168d2a6935SXin Long 78178d2a6935SXin Long out: 78188d2a6935SXin Long return retval; 78198d2a6935SXin Long } 78208d2a6935SXin Long 7821dda91928SDaniel Borkmann static int sctp_getsockopt(struct sock *sk, int level, int optname, 78221da177e4SLinus Torvalds char __user *optval, int __user *optlen) 78231da177e4SLinus Torvalds { 78241da177e4SLinus Torvalds int retval = 0; 78251da177e4SLinus Torvalds int len; 78261da177e4SLinus Torvalds 7827bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 78281da177e4SLinus Torvalds 78291da177e4SLinus Torvalds /* I can hardly begin to describe how wrong this is. This is 78301da177e4SLinus Torvalds * so broken as to be worse than useless. The API draft 78311da177e4SLinus Torvalds * REALLY is NOT helpful here... I am not convinced that the 78321da177e4SLinus Torvalds * semantics of getsockopt() with a level OTHER THAN SOL_SCTP 78331da177e4SLinus Torvalds * are at all well-founded. 78341da177e4SLinus Torvalds */ 78351da177e4SLinus Torvalds if (level != SOL_SCTP) { 78361da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 78371da177e4SLinus Torvalds 78381da177e4SLinus Torvalds retval = af->getsockopt(sk, level, optname, optval, optlen); 78391da177e4SLinus Torvalds return retval; 78401da177e4SLinus Torvalds } 78411da177e4SLinus Torvalds 78421da177e4SLinus Torvalds if (get_user(len, optlen)) 78431da177e4SLinus Torvalds return -EFAULT; 78441da177e4SLinus Torvalds 7845a4b8e71bSJiri Slaby if (len < 0) 7846a4b8e71bSJiri Slaby return -EINVAL; 7847a4b8e71bSJiri Slaby 7848048ed4b6Swangweidong lock_sock(sk); 78491da177e4SLinus Torvalds 78501da177e4SLinus Torvalds switch (optname) { 78511da177e4SLinus Torvalds case SCTP_STATUS: 78521da177e4SLinus Torvalds retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); 78531da177e4SLinus Torvalds break; 78541da177e4SLinus Torvalds case SCTP_DISABLE_FRAGMENTS: 78551da177e4SLinus Torvalds retval = sctp_getsockopt_disable_fragments(sk, len, optval, 78561da177e4SLinus Torvalds optlen); 78571da177e4SLinus Torvalds break; 78581da177e4SLinus Torvalds case SCTP_EVENTS: 78591da177e4SLinus Torvalds retval = sctp_getsockopt_events(sk, len, optval, optlen); 78601da177e4SLinus Torvalds break; 78611da177e4SLinus Torvalds case SCTP_AUTOCLOSE: 78621da177e4SLinus Torvalds retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); 78631da177e4SLinus Torvalds break; 78641da177e4SLinus Torvalds case SCTP_SOCKOPT_PEELOFF: 78651da177e4SLinus Torvalds retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); 78661da177e4SLinus Torvalds break; 78672cb5c8e3SNeil Horman case SCTP_SOCKOPT_PEELOFF_FLAGS: 78682cb5c8e3SNeil Horman retval = sctp_getsockopt_peeloff_flags(sk, len, optval, optlen); 78692cb5c8e3SNeil Horman break; 78701da177e4SLinus Torvalds case SCTP_PEER_ADDR_PARAMS: 78711da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addr_params(sk, len, optval, 78721da177e4SLinus Torvalds optlen); 78731da177e4SLinus Torvalds break; 78744580ccc0SShan Wei case SCTP_DELAYED_SACK: 7875d364d927SWei Yongjun retval = sctp_getsockopt_delayed_ack(sk, len, optval, 78767708610bSFrank Filz optlen); 78777708610bSFrank Filz break; 78781da177e4SLinus Torvalds case SCTP_INITMSG: 78791da177e4SLinus Torvalds retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); 78801da177e4SLinus Torvalds break; 78811da177e4SLinus Torvalds case SCTP_GET_PEER_ADDRS: 78821da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addrs(sk, len, optval, 78831da177e4SLinus Torvalds optlen); 78841da177e4SLinus Torvalds break; 78851da177e4SLinus Torvalds case SCTP_GET_LOCAL_ADDRS: 78861da177e4SLinus Torvalds retval = sctp_getsockopt_local_addrs(sk, len, optval, 78871da177e4SLinus Torvalds optlen); 78881da177e4SLinus Torvalds break; 7889c6ba68a2SVlad Yasevich case SCTP_SOCKOPT_CONNECTX3: 7890c6ba68a2SVlad Yasevich retval = sctp_getsockopt_connectx3(sk, len, optval, optlen); 7891c6ba68a2SVlad Yasevich break; 78921da177e4SLinus Torvalds case SCTP_DEFAULT_SEND_PARAM: 78931da177e4SLinus Torvalds retval = sctp_getsockopt_default_send_param(sk, len, 78941da177e4SLinus Torvalds optval, optlen); 78951da177e4SLinus Torvalds break; 78966b3fd5f3SGeir Ola Vaagland case SCTP_DEFAULT_SNDINFO: 78976b3fd5f3SGeir Ola Vaagland retval = sctp_getsockopt_default_sndinfo(sk, len, 78986b3fd5f3SGeir Ola Vaagland optval, optlen); 78996b3fd5f3SGeir Ola Vaagland break; 79001da177e4SLinus Torvalds case SCTP_PRIMARY_ADDR: 79011da177e4SLinus Torvalds retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); 79021da177e4SLinus Torvalds break; 79031da177e4SLinus Torvalds case SCTP_NODELAY: 79041da177e4SLinus Torvalds retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); 79051da177e4SLinus Torvalds break; 79061da177e4SLinus Torvalds case SCTP_RTOINFO: 79071da177e4SLinus Torvalds retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen); 79081da177e4SLinus Torvalds break; 79091da177e4SLinus Torvalds case SCTP_ASSOCINFO: 79101da177e4SLinus Torvalds retval = sctp_getsockopt_associnfo(sk, len, optval, optlen); 79111da177e4SLinus Torvalds break; 79121da177e4SLinus Torvalds case SCTP_I_WANT_MAPPED_V4_ADDR: 79131da177e4SLinus Torvalds retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); 79141da177e4SLinus Torvalds break; 79151da177e4SLinus Torvalds case SCTP_MAXSEG: 79161da177e4SLinus Torvalds retval = sctp_getsockopt_maxseg(sk, len, optval, optlen); 79171da177e4SLinus Torvalds break; 79181da177e4SLinus Torvalds case SCTP_GET_PEER_ADDR_INFO: 79191da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addr_info(sk, len, optval, 79201da177e4SLinus Torvalds optlen); 79211da177e4SLinus Torvalds break; 79220f3fffd8SIvan Skytte Jorgensen case SCTP_ADAPTATION_LAYER: 79230f3fffd8SIvan Skytte Jorgensen retval = sctp_getsockopt_adaptation_layer(sk, len, optval, 79241da177e4SLinus Torvalds optlen); 79251da177e4SLinus Torvalds break; 79266ab792f5SIvan Skytte Jorgensen case SCTP_CONTEXT: 79276ab792f5SIvan Skytte Jorgensen retval = sctp_getsockopt_context(sk, len, optval, optlen); 79286ab792f5SIvan Skytte Jorgensen break; 7929b6e1331fSVlad Yasevich case SCTP_FRAGMENT_INTERLEAVE: 7930b6e1331fSVlad Yasevich retval = sctp_getsockopt_fragment_interleave(sk, len, optval, 7931b6e1331fSVlad Yasevich optlen); 7932b6e1331fSVlad Yasevich break; 7933d49d91d7SVlad Yasevich case SCTP_PARTIAL_DELIVERY_POINT: 7934d49d91d7SVlad Yasevich retval = sctp_getsockopt_partial_delivery_point(sk, len, optval, 7935d49d91d7SVlad Yasevich optlen); 7936d49d91d7SVlad Yasevich break; 793770331571SVlad Yasevich case SCTP_MAX_BURST: 793870331571SVlad Yasevich retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); 793970331571SVlad Yasevich break; 794065b07e5dSVlad Yasevich case SCTP_AUTH_KEY: 794165b07e5dSVlad Yasevich case SCTP_AUTH_CHUNK: 794265b07e5dSVlad Yasevich case SCTP_AUTH_DELETE_KEY: 7943601590ecSXin Long case SCTP_AUTH_DEACTIVATE_KEY: 794465b07e5dSVlad Yasevich retval = -EOPNOTSUPP; 794565b07e5dSVlad Yasevich break; 794665b07e5dSVlad Yasevich case SCTP_HMAC_IDENT: 794765b07e5dSVlad Yasevich retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen); 794865b07e5dSVlad Yasevich break; 794965b07e5dSVlad Yasevich case SCTP_AUTH_ACTIVE_KEY: 795065b07e5dSVlad Yasevich retval = sctp_getsockopt_active_key(sk, len, optval, optlen); 795165b07e5dSVlad Yasevich break; 795265b07e5dSVlad Yasevich case SCTP_PEER_AUTH_CHUNKS: 795365b07e5dSVlad Yasevich retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval, 795465b07e5dSVlad Yasevich optlen); 795565b07e5dSVlad Yasevich break; 795665b07e5dSVlad Yasevich case SCTP_LOCAL_AUTH_CHUNKS: 795765b07e5dSVlad Yasevich retval = sctp_getsockopt_local_auth_chunks(sk, len, optval, 795865b07e5dSVlad Yasevich optlen); 795965b07e5dSVlad Yasevich break; 7960aea3c5c0SWei Yongjun case SCTP_GET_ASSOC_NUMBER: 7961aea3c5c0SWei Yongjun retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); 7962aea3c5c0SWei Yongjun break; 7963209ba424SWei Yongjun case SCTP_GET_ASSOC_ID_LIST: 7964209ba424SWei Yongjun retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); 7965209ba424SWei Yongjun break; 79667dc04d71SMichio Honda case SCTP_AUTO_ASCONF: 79677dc04d71SMichio Honda retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); 79687dc04d71SMichio Honda break; 79695aa93bcfSNeil Horman case SCTP_PEER_ADDR_THLDS: 7970d467ac0aSXin Long retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, 7971d467ac0aSXin Long optlen, false); 7972d467ac0aSXin Long break; 7973d467ac0aSXin Long case SCTP_PEER_ADDR_THLDS_V2: 7974d467ac0aSXin Long retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, 7975d467ac0aSXin Long optlen, true); 79765aa93bcfSNeil Horman break; 7977196d6759SMichele Baldessari case SCTP_GET_ASSOC_STATS: 7978196d6759SMichele Baldessari retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); 7979196d6759SMichele Baldessari break; 79800d3a421dSGeir Ola Vaagland case SCTP_RECVRCVINFO: 79810d3a421dSGeir Ola Vaagland retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); 79820d3a421dSGeir Ola Vaagland break; 79832347c80fSGeir Ola Vaagland case SCTP_RECVNXTINFO: 79842347c80fSGeir Ola Vaagland retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen); 79852347c80fSGeir Ola Vaagland break; 798628aa4c26SXin Long case SCTP_PR_SUPPORTED: 798728aa4c26SXin Long retval = sctp_getsockopt_pr_supported(sk, len, optval, optlen); 798828aa4c26SXin Long break; 7989f959fb44SXin Long case SCTP_DEFAULT_PRINFO: 7990f959fb44SXin Long retval = sctp_getsockopt_default_prinfo(sk, len, optval, 7991f959fb44SXin Long optlen); 7992f959fb44SXin Long break; 7993826d253dSXin Long case SCTP_PR_ASSOC_STATUS: 7994826d253dSXin Long retval = sctp_getsockopt_pr_assocstatus(sk, len, optval, 7995826d253dSXin Long optlen); 7996826d253dSXin Long break; 7997d229d48dSXin Long case SCTP_PR_STREAM_STATUS: 7998d229d48dSXin Long retval = sctp_getsockopt_pr_streamstatus(sk, len, optval, 7999d229d48dSXin Long optlen); 8000d229d48dSXin Long break; 8001c0d8bab6SXin Long case SCTP_RECONFIG_SUPPORTED: 8002c0d8bab6SXin Long retval = sctp_getsockopt_reconfig_supported(sk, len, optval, 8003c0d8bab6SXin Long optlen); 8004c0d8bab6SXin Long break; 80059fb657aeSXin Long case SCTP_ENABLE_STREAM_RESET: 80069fb657aeSXin Long retval = sctp_getsockopt_enable_strreset(sk, len, optval, 80079fb657aeSXin Long optlen); 80089fb657aeSXin Long break; 800913aa8770SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER: 801013aa8770SMarcelo Ricardo Leitner retval = sctp_getsockopt_scheduler(sk, len, optval, 801113aa8770SMarcelo Ricardo Leitner optlen); 801213aa8770SMarcelo Ricardo Leitner break; 80130ccdf3c7SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER_VALUE: 80140ccdf3c7SMarcelo Ricardo Leitner retval = sctp_getsockopt_scheduler_value(sk, len, optval, 80150ccdf3c7SMarcelo Ricardo Leitner optlen); 80160ccdf3c7SMarcelo Ricardo Leitner break; 8017772a5869SXin Long case SCTP_INTERLEAVING_SUPPORTED: 8018772a5869SXin Long retval = sctp_getsockopt_interleaving_supported(sk, len, optval, 8019772a5869SXin Long optlen); 8020772a5869SXin Long break; 8021b0e9a2feSXin Long case SCTP_REUSE_PORT: 8022b0e9a2feSXin Long retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen); 8023b0e9a2feSXin Long break; 8024480ba9c1SXin Long case SCTP_EVENT: 8025480ba9c1SXin Long retval = sctp_getsockopt_event(sk, len, optval, optlen); 8026480ba9c1SXin Long break; 8027df2c71ffSXin Long case SCTP_ASCONF_SUPPORTED: 8028df2c71ffSXin Long retval = sctp_getsockopt_asconf_supported(sk, len, optval, 8029df2c71ffSXin Long optlen); 8030df2c71ffSXin Long break; 803156dd525aSXin Long case SCTP_AUTH_SUPPORTED: 803256dd525aSXin Long retval = sctp_getsockopt_auth_supported(sk, len, optval, 803356dd525aSXin Long optlen); 803456dd525aSXin Long break; 8035d5886b91SXin Long case SCTP_ECN_SUPPORTED: 8036d5886b91SXin Long retval = sctp_getsockopt_ecn_supported(sk, len, optval, optlen); 8037d5886b91SXin Long break; 80388d2a6935SXin Long case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: 80398d2a6935SXin Long retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen); 80408d2a6935SXin Long break; 80411da177e4SLinus Torvalds default: 80421da177e4SLinus Torvalds retval = -ENOPROTOOPT; 80431da177e4SLinus Torvalds break; 80443ff50b79SStephen Hemminger } 80451da177e4SLinus Torvalds 8046048ed4b6Swangweidong release_sock(sk); 80471da177e4SLinus Torvalds return retval; 80481da177e4SLinus Torvalds } 80491da177e4SLinus Torvalds 8050086c653fSCraig Gallek static int sctp_hash(struct sock *sk) 80511da177e4SLinus Torvalds { 80521da177e4SLinus Torvalds /* STUB */ 8053086c653fSCraig Gallek return 0; 80541da177e4SLinus Torvalds } 80551da177e4SLinus Torvalds 80561da177e4SLinus Torvalds static void sctp_unhash(struct sock *sk) 80571da177e4SLinus Torvalds { 80581da177e4SLinus Torvalds /* STUB */ 80591da177e4SLinus Torvalds } 80601da177e4SLinus Torvalds 80611da177e4SLinus Torvalds /* Check if port is acceptable. Possibly find first available port. 80621da177e4SLinus Torvalds * 80631da177e4SLinus Torvalds * The port hash table (contained in the 'global' SCTP protocol storage 80641da177e4SLinus Torvalds * returned by struct sctp_protocol *sctp_get_protocol()). The hash 80651da177e4SLinus Torvalds * table is an array of 4096 lists (sctp_bind_hashbucket). Each 80661da177e4SLinus Torvalds * list (the list number is the port number hashed out, so as you 80671da177e4SLinus Torvalds * would expect from a hash function, all the ports in a given list have 80681da177e4SLinus Torvalds * such a number that hashes out to the same list number; you were 80691da177e4SLinus Torvalds * expecting that, right?); so each list has a set of ports, with a 80701da177e4SLinus Torvalds * link to the socket (struct sock) that uses it, the port number and 80711da177e4SLinus Torvalds * a fastreuse flag (FIXME: NPI ipg). 80721da177e4SLinus Torvalds */ 80731da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create( 8074f1f43763SEric W. Biederman struct sctp_bind_hashbucket *head, struct net *, unsigned short snum); 80751da177e4SLinus Torvalds 80768e2ef6abSMao Wenan static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr) 80771da177e4SLinus Torvalds { 80786ba84574SXin Long struct sctp_sock *sp = sctp_sk(sk); 80796ba84574SXin Long bool reuse = (sk->sk_reuse || sp->reuse); 80801da177e4SLinus Torvalds struct sctp_bind_hashbucket *head; /* hash list */ 8081fb822388SMaciej Żenczykowski struct net *net = sock_net(sk); 80826ba84574SXin Long kuid_t uid = sock_i_uid(sk); 8083b67bfe0dSSasha Levin struct sctp_bind_bucket *pp; 80841da177e4SLinus Torvalds unsigned short snum; 80851da177e4SLinus Torvalds int ret; 80861da177e4SLinus Torvalds 808704afd8b2SAl Viro snum = ntohs(addr->v4.sin_port); 80881da177e4SLinus Torvalds 8089bb33381dSDaniel Borkmann pr_debug("%s: begins, snum:%d\n", __func__, snum); 8090bb33381dSDaniel Borkmann 809179b91130Swangweidong local_bh_disable(); 80921da177e4SLinus Torvalds 80931da177e4SLinus Torvalds if (snum == 0) { 809406393009SStephen Hemminger /* Search for an available port. */ 8095227b60f5SStephen Hemminger int low, high, remaining, index; 8096227b60f5SStephen Hemminger unsigned int rover; 8097227b60f5SStephen Hemminger 8098122ff243SWANG Cong inet_get_local_port_range(net, &low, &high); 8099227b60f5SStephen Hemminger remaining = (high - low) + 1; 810063862b5bSAruna-Hewapathirane rover = prandom_u32() % remaining + low; 81011da177e4SLinus Torvalds 81021da177e4SLinus Torvalds do { 81031da177e4SLinus Torvalds rover++; 81041da177e4SLinus Torvalds if ((rover < low) || (rover > high)) 81051da177e4SLinus Torvalds rover = low; 8106122ff243SWANG Cong if (inet_is_local_reserved_port(net, rover)) 8107e3826f1eSAmerigo Wang continue; 8108fb822388SMaciej Żenczykowski index = sctp_phashfn(net, rover); 81091da177e4SLinus Torvalds head = &sctp_port_hashtable[index]; 81103c8e43baSwangweidong spin_lock(&head->lock); 8111b67bfe0dSSasha Levin sctp_for_each_hentry(pp, &head->chain) 8112f1f43763SEric W. Biederman if ((pp->port == rover) && 8113fb822388SMaciej Żenczykowski net_eq(net, pp->net)) 81141da177e4SLinus Torvalds goto next; 81151da177e4SLinus Torvalds break; 81161da177e4SLinus Torvalds next: 81173c8e43baSwangweidong spin_unlock(&head->lock); 81181da177e4SLinus Torvalds } while (--remaining > 0); 81191da177e4SLinus Torvalds 81201da177e4SLinus Torvalds /* Exhausted local port range during search? */ 81211da177e4SLinus Torvalds ret = 1; 81221da177e4SLinus Torvalds if (remaining <= 0) 81231da177e4SLinus Torvalds goto fail; 81241da177e4SLinus Torvalds 81251da177e4SLinus Torvalds /* OK, here is the one we will use. HEAD (the port 81261da177e4SLinus Torvalds * hash table list entry) is non-NULL and we hold it's 81271da177e4SLinus Torvalds * mutex. 81281da177e4SLinus Torvalds */ 81291da177e4SLinus Torvalds snum = rover; 81301da177e4SLinus Torvalds } else { 81311da177e4SLinus Torvalds /* We are given an specific port number; we verify 81321da177e4SLinus Torvalds * that it is not being used. If it is used, we will 81331da177e4SLinus Torvalds * exahust the search in the hash list corresponding 81341da177e4SLinus Torvalds * to the port number (snum) - we detect that with the 81351da177e4SLinus Torvalds * port iterator, pp being NULL. 81361da177e4SLinus Torvalds */ 8137fb822388SMaciej Żenczykowski head = &sctp_port_hashtable[sctp_phashfn(net, snum)]; 81383c8e43baSwangweidong spin_lock(&head->lock); 8139b67bfe0dSSasha Levin sctp_for_each_hentry(pp, &head->chain) { 8140fb822388SMaciej Żenczykowski if ((pp->port == snum) && net_eq(pp->net, net)) 81411da177e4SLinus Torvalds goto pp_found; 81421da177e4SLinus Torvalds } 81431da177e4SLinus Torvalds } 81441da177e4SLinus Torvalds pp = NULL; 81451da177e4SLinus Torvalds goto pp_not_found; 81461da177e4SLinus Torvalds pp_found: 81471da177e4SLinus Torvalds if (!hlist_empty(&pp->owner)) { 81481da177e4SLinus Torvalds /* We had a port hash table hit - there is an 81491da177e4SLinus Torvalds * available port (pp != NULL) and it is being 81501da177e4SLinus Torvalds * used by other socket (pp->owner not empty); that other 81511da177e4SLinus Torvalds * socket is going to be sk2. 81521da177e4SLinus Torvalds */ 81531da177e4SLinus Torvalds struct sock *sk2; 81541da177e4SLinus Torvalds 8155bb33381dSDaniel Borkmann pr_debug("%s: found a possible match\n", __func__); 8156bb33381dSDaniel Borkmann 81576ba84574SXin Long if ((pp->fastreuse && reuse && 81586ba84574SXin Long sk->sk_state != SCTP_SS_LISTENING) || 81596ba84574SXin Long (pp->fastreuseport && sk->sk_reuseport && 81606ba84574SXin Long uid_eq(pp->fastuid, uid))) 81611da177e4SLinus Torvalds goto success; 81621da177e4SLinus Torvalds 81631da177e4SLinus Torvalds /* Run through the list of sockets bound to the port 81641da177e4SLinus Torvalds * (pp->port) [via the pointers bind_next and 81651da177e4SLinus Torvalds * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one, 81661da177e4SLinus Torvalds * we get the endpoint they describe and run through 81671da177e4SLinus Torvalds * the endpoint's list of IP (v4 or v6) addresses, 81681da177e4SLinus Torvalds * comparing each of the addresses with the address of 81691da177e4SLinus Torvalds * the socket sk. If we find a match, then that means 81701da177e4SLinus Torvalds * that this port/socket (sk) combination are already 81711da177e4SLinus Torvalds * in an endpoint. 81721da177e4SLinus Torvalds */ 8173b67bfe0dSSasha Levin sk_for_each_bound(sk2, &pp->owner) { 81746ba84574SXin Long struct sctp_sock *sp2 = sctp_sk(sk2); 81756ba84574SXin Long struct sctp_endpoint *ep2 = sp2->ep; 81761da177e4SLinus Torvalds 81774e54064eSVlad Yasevich if (sk == sk2 || 81786ba84574SXin Long (reuse && (sk2->sk_reuse || sp2->reuse) && 81796ba84574SXin Long sk2->sk_state != SCTP_SS_LISTENING) || 81806ba84574SXin Long (sk->sk_reuseport && sk2->sk_reuseport && 81816ba84574SXin Long uid_eq(uid, sock_i_uid(sk2)))) 81821da177e4SLinus Torvalds continue; 81831da177e4SLinus Torvalds 81846ba84574SXin Long if (sctp_bind_addr_conflict(&ep2->base.bind_addr, 81856ba84574SXin Long addr, sp2, sp)) { 81868e2ef6abSMao Wenan ret = 1; 81871da177e4SLinus Torvalds goto fail_unlock; 81881da177e4SLinus Torvalds } 81891da177e4SLinus Torvalds } 8190bb33381dSDaniel Borkmann 8191bb33381dSDaniel Borkmann pr_debug("%s: found a match\n", __func__); 81921da177e4SLinus Torvalds } 81931da177e4SLinus Torvalds pp_not_found: 81941da177e4SLinus Torvalds /* If there was a hash table miss, create a new port. */ 81951da177e4SLinus Torvalds ret = 1; 8196fb822388SMaciej Żenczykowski if (!pp && !(pp = sctp_bucket_create(head, net, snum))) 81971da177e4SLinus Torvalds goto fail_unlock; 81981da177e4SLinus Torvalds 81991da177e4SLinus Torvalds /* In either case (hit or miss), make sure fastreuse is 1 only 82001da177e4SLinus Torvalds * if sk->sk_reuse is too (that is, if the caller requested 82011da177e4SLinus Torvalds * SO_REUSEADDR on this socket -sk-). 82021da177e4SLinus Torvalds */ 8203ce5325c1SVlad Yasevich if (hlist_empty(&pp->owner)) { 8204b0e9a2feSXin Long if (reuse && sk->sk_state != SCTP_SS_LISTENING) 8205ce5325c1SVlad Yasevich pp->fastreuse = 1; 8206ce5325c1SVlad Yasevich else 8207ce5325c1SVlad Yasevich pp->fastreuse = 0; 82086ba84574SXin Long 82096ba84574SXin Long if (sk->sk_reuseport) { 82106ba84574SXin Long pp->fastreuseport = 1; 82116ba84574SXin Long pp->fastuid = uid; 82126ba84574SXin Long } else { 82136ba84574SXin Long pp->fastreuseport = 0; 82146ba84574SXin Long } 82156ba84574SXin Long } else { 82166ba84574SXin Long if (pp->fastreuse && 8217b0e9a2feSXin Long (!reuse || sk->sk_state == SCTP_SS_LISTENING)) 82181da177e4SLinus Torvalds pp->fastreuse = 0; 82191da177e4SLinus Torvalds 82206ba84574SXin Long if (pp->fastreuseport && 82216ba84574SXin Long (!sk->sk_reuseport || !uid_eq(pp->fastuid, uid))) 82226ba84574SXin Long pp->fastreuseport = 0; 82236ba84574SXin Long } 82246ba84574SXin Long 82251da177e4SLinus Torvalds /* We are set, so fill up all the data in the hash table 82261da177e4SLinus Torvalds * entry, tie the socket list information with the rest of the 82271da177e4SLinus Torvalds * sockets FIXME: Blurry, NPI (ipg). 82281da177e4SLinus Torvalds */ 82291da177e4SLinus Torvalds success: 82306ba84574SXin Long if (!sp->bind_hash) { 8231c720c7e8SEric Dumazet inet_sk(sk)->inet_num = snum; 82321da177e4SLinus Torvalds sk_add_bind_node(sk, &pp->owner); 82336ba84574SXin Long sp->bind_hash = pp; 82341da177e4SLinus Torvalds } 82351da177e4SLinus Torvalds ret = 0; 82361da177e4SLinus Torvalds 82371da177e4SLinus Torvalds fail_unlock: 82383c8e43baSwangweidong spin_unlock(&head->lock); 82391da177e4SLinus Torvalds 82401da177e4SLinus Torvalds fail: 824179b91130Swangweidong local_bh_enable(); 82421da177e4SLinus Torvalds return ret; 82431da177e4SLinus Torvalds } 82441da177e4SLinus Torvalds 82451da177e4SLinus Torvalds /* Assign a 'snum' port to the socket. If snum == 0, an ephemeral 82461da177e4SLinus Torvalds * port is requested. 82471da177e4SLinus Torvalds */ 82481da177e4SLinus Torvalds static int sctp_get_port(struct sock *sk, unsigned short snum) 82491da177e4SLinus Torvalds { 82501da177e4SLinus Torvalds union sctp_addr addr; 82511da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 82521da177e4SLinus Torvalds 82531da177e4SLinus Torvalds /* Set up a dummy address struct from the sk. */ 82541da177e4SLinus Torvalds af->from_sk(&addr, sk); 82551da177e4SLinus Torvalds addr.v4.sin_port = htons(snum); 82561da177e4SLinus Torvalds 82571da177e4SLinus Torvalds /* Note: sk->sk_num gets filled in if ephemeral port request. */ 82588e2ef6abSMao Wenan return sctp_get_port_local(sk, &addr); 82591da177e4SLinus Torvalds } 82601da177e4SLinus Torvalds 82611da177e4SLinus Torvalds /* 82621da177e4SLinus Torvalds * Move a socket to LISTENING state. 82631da177e4SLinus Torvalds */ 8264dda91928SDaniel Borkmann static int sctp_listen_start(struct sock *sk, int backlog) 82651da177e4SLinus Torvalds { 82665e8f3f70SVlad Yasevich struct sctp_sock *sp = sctp_sk(sk); 82675e8f3f70SVlad Yasevich struct sctp_endpoint *ep = sp->ep; 82685821c769SHerbert Xu struct crypto_shash *tfm = NULL; 82693c68198eSNeil Horman char alg[32]; 82701da177e4SLinus Torvalds 82711da177e4SLinus Torvalds /* Allocate HMAC for generating cookie. */ 82723c68198eSNeil Horman if (!sp->hmac && sp->sctp_hmac_alg) { 82733c68198eSNeil Horman sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg); 82745821c769SHerbert Xu tfm = crypto_alloc_shash(alg, 0, 0); 82758dc4984aSVlad Yasevich if (IS_ERR(tfm)) { 8276e87cc472SJoe Perches net_info_ratelimited("failed to load transform for %s: %ld\n", 82773c68198eSNeil Horman sp->sctp_hmac_alg, PTR_ERR(tfm)); 82785e8f3f70SVlad Yasevich return -ENOSYS; 82795e8f3f70SVlad Yasevich } 82805e8f3f70SVlad Yasevich sctp_sk(sk)->hmac = tfm; 82815e8f3f70SVlad Yasevich } 82825e8f3f70SVlad Yasevich 82835e8f3f70SVlad Yasevich /* 82845e8f3f70SVlad Yasevich * If a bind() or sctp_bindx() is not called prior to a listen() 82855e8f3f70SVlad Yasevich * call that allows new associations to be accepted, the system 82865e8f3f70SVlad Yasevich * picks an ephemeral port and will choose an address set equivalent 82875e8f3f70SVlad Yasevich * to binding with a wildcard address. 82885e8f3f70SVlad Yasevich * 82895e8f3f70SVlad Yasevich * This is not currently spelled out in the SCTP sockets 82905e8f3f70SVlad Yasevich * extensions draft, but follows the practice as seen in TCP 82915e8f3f70SVlad Yasevich * sockets. 82925e8f3f70SVlad Yasevich * 82935e8f3f70SVlad Yasevich */ 8294cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_LISTENING); 82955e8f3f70SVlad Yasevich if (!ep->base.bind_addr.port) { 82965e8f3f70SVlad Yasevich if (sctp_autobind(sk)) 82975e8f3f70SVlad Yasevich return -EAGAIN; 82985e8f3f70SVlad Yasevich } else { 8299c720c7e8SEric Dumazet if (sctp_get_port(sk, inet_sk(sk)->inet_num)) { 8300cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_CLOSED); 83015e8f3f70SVlad Yasevich return -EADDRINUSE; 83025e8f3f70SVlad Yasevich } 83035e8f3f70SVlad Yasevich } 83045e8f3f70SVlad Yasevich 8305099ecf59SEric Dumazet WRITE_ONCE(sk->sk_max_ack_backlog, backlog); 830676c6d988SXin Long return sctp_hash_endpoint(ep); 83075e8f3f70SVlad Yasevich } 83085e8f3f70SVlad Yasevich 83095e8f3f70SVlad Yasevich /* 83105e8f3f70SVlad Yasevich * 4.1.3 / 5.1.3 listen() 83115e8f3f70SVlad Yasevich * 83125e8f3f70SVlad Yasevich * By default, new associations are not accepted for UDP style sockets. 83135e8f3f70SVlad Yasevich * An application uses listen() to mark a socket as being able to 83145e8f3f70SVlad Yasevich * accept new associations. 83155e8f3f70SVlad Yasevich * 83165e8f3f70SVlad Yasevich * On TCP style sockets, applications use listen() to ready the SCTP 83175e8f3f70SVlad Yasevich * endpoint for accepting inbound associations. 83185e8f3f70SVlad Yasevich * 83195e8f3f70SVlad Yasevich * On both types of endpoints a backlog of '0' disables listening. 83205e8f3f70SVlad Yasevich * 83215e8f3f70SVlad Yasevich * Move a socket to LISTENING state. 83225e8f3f70SVlad Yasevich */ 83235e8f3f70SVlad Yasevich int sctp_inet_listen(struct socket *sock, int backlog) 83245e8f3f70SVlad Yasevich { 83255e8f3f70SVlad Yasevich struct sock *sk = sock->sk; 83265e8f3f70SVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 83275e8f3f70SVlad Yasevich int err = -EINVAL; 83285e8f3f70SVlad Yasevich 83295e8f3f70SVlad Yasevich if (unlikely(backlog < 0)) 83305e8f3f70SVlad Yasevich return err; 83315e8f3f70SVlad Yasevich 8332048ed4b6Swangweidong lock_sock(sk); 83335e8f3f70SVlad Yasevich 83345e8f3f70SVlad Yasevich /* Peeled-off sockets are not allowed to listen(). */ 83355e8f3f70SVlad Yasevich if (sctp_style(sk, UDP_HIGH_BANDWIDTH)) 83365e8f3f70SVlad Yasevich goto out; 83375e8f3f70SVlad Yasevich 83385e8f3f70SVlad Yasevich if (sock->state != SS_UNCONNECTED) 83395e8f3f70SVlad Yasevich goto out; 83405e8f3f70SVlad Yasevich 834134b2789fSXin Long if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED)) 834234b2789fSXin Long goto out; 834334b2789fSXin Long 83445e8f3f70SVlad Yasevich /* If backlog is zero, disable listening. */ 83455e8f3f70SVlad Yasevich if (!backlog) { 83465e8f3f70SVlad Yasevich if (sctp_sstate(sk, CLOSED)) 83475e8f3f70SVlad Yasevich goto out; 83485e8f3f70SVlad Yasevich 83495e8f3f70SVlad Yasevich err = 0; 83505e8f3f70SVlad Yasevich sctp_unhash_endpoint(ep); 83515e8f3f70SVlad Yasevich sk->sk_state = SCTP_SS_CLOSED; 8352b0e9a2feSXin Long if (sk->sk_reuse || sctp_sk(sk)->reuse) 83535e8f3f70SVlad Yasevich sctp_sk(sk)->bind_hash->fastreuse = 1; 83541da177e4SLinus Torvalds goto out; 83551da177e4SLinus Torvalds } 83561da177e4SLinus Torvalds 83575e8f3f70SVlad Yasevich /* If we are already listening, just update the backlog */ 83585e8f3f70SVlad Yasevich if (sctp_sstate(sk, LISTENING)) 8359099ecf59SEric Dumazet WRITE_ONCE(sk->sk_max_ack_backlog, backlog); 83605e8f3f70SVlad Yasevich else { 83615e8f3f70SVlad Yasevich err = sctp_listen_start(sk, backlog); 83621da177e4SLinus Torvalds if (err) 83635e8f3f70SVlad Yasevich goto out; 83645e8f3f70SVlad Yasevich } 83651da177e4SLinus Torvalds 83665e8f3f70SVlad Yasevich err = 0; 83671da177e4SLinus Torvalds out: 8368048ed4b6Swangweidong release_sock(sk); 83691da177e4SLinus Torvalds return err; 83701da177e4SLinus Torvalds } 83711da177e4SLinus Torvalds 83721da177e4SLinus Torvalds /* 83731da177e4SLinus Torvalds * This function is done by modeling the current datagram_poll() and the 83741da177e4SLinus Torvalds * tcp_poll(). Note that, based on these implementations, we don't 83751da177e4SLinus Torvalds * lock the socket in this function, even though it seems that, 83761da177e4SLinus Torvalds * ideally, locking or some other mechanisms can be used to ensure 83779bffc4acSNeil Horman * the integrity of the counters (sndbuf and wmem_alloc) used 83781da177e4SLinus Torvalds * in this place. We assume that we don't need locks either until proven 83791da177e4SLinus Torvalds * otherwise. 83801da177e4SLinus Torvalds * 83811da177e4SLinus Torvalds * Another thing to note is that we include the Async I/O support 83821da177e4SLinus Torvalds * here, again, by modeling the current TCP/UDP code. We don't have 83831da177e4SLinus Torvalds * a good way to test with it yet. 83841da177e4SLinus Torvalds */ 8385a11e1d43SLinus Torvalds __poll_t sctp_poll(struct file *file, struct socket *sock, poll_table *wait) 83861da177e4SLinus Torvalds { 83871da177e4SLinus Torvalds struct sock *sk = sock->sk; 83881da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 8389ade994f4SAl Viro __poll_t mask; 83901da177e4SLinus Torvalds 8391a11e1d43SLinus Torvalds poll_wait(file, sk_sleep(sk), wait); 8392a11e1d43SLinus Torvalds 8393486bdee0SMarcelo Ricardo Leitner sock_rps_record_flow(sk); 8394486bdee0SMarcelo Ricardo Leitner 83951da177e4SLinus Torvalds /* A TCP-style listening socket becomes readable when the accept queue 83961da177e4SLinus Torvalds * is not empty. 83971da177e4SLinus Torvalds */ 83981da177e4SLinus Torvalds if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 83991da177e4SLinus Torvalds return (!list_empty(&sp->ep->asocs)) ? 8400a9a08845SLinus Torvalds (EPOLLIN | EPOLLRDNORM) : 0; 84011da177e4SLinus Torvalds 84021da177e4SLinus Torvalds mask = 0; 84031da177e4SLinus Torvalds 84041da177e4SLinus Torvalds /* Is there any exceptional events? */ 84053ef7cf57SEric Dumazet if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue)) 8406a9a08845SLinus Torvalds mask |= EPOLLERR | 8407a9a08845SLinus Torvalds (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0); 8408f348d70aSDavide Libenzi if (sk->sk_shutdown & RCV_SHUTDOWN) 8409a9a08845SLinus Torvalds mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; 84101da177e4SLinus Torvalds if (sk->sk_shutdown == SHUTDOWN_MASK) 8411a9a08845SLinus Torvalds mask |= EPOLLHUP; 84121da177e4SLinus Torvalds 84131da177e4SLinus Torvalds /* Is it readable? Reconsider this code with TCP-style support. */ 84143ef7cf57SEric Dumazet if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 8415a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 84161da177e4SLinus Torvalds 84171da177e4SLinus Torvalds /* The association is either gone or not ready. */ 84181da177e4SLinus Torvalds if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED)) 84191da177e4SLinus Torvalds return mask; 84201da177e4SLinus Torvalds 84211da177e4SLinus Torvalds /* Is it writable? */ 84221da177e4SLinus Torvalds if (sctp_writeable(sk)) { 8423a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 84241da177e4SLinus Torvalds } else { 84259cd3e072SEric Dumazet sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 84261da177e4SLinus Torvalds /* 84271da177e4SLinus Torvalds * Since the socket is not locked, the buffer 84281da177e4SLinus Torvalds * might be made available after the writeable check and 84291da177e4SLinus Torvalds * before the bit is set. This could cause a lost I/O 84301da177e4SLinus Torvalds * signal. tcp_poll() has a race breaker for this race 84311da177e4SLinus Torvalds * condition. Based on their implementation, we put 84321da177e4SLinus Torvalds * in the following code to cover it as well. 84331da177e4SLinus Torvalds */ 84341da177e4SLinus Torvalds if (sctp_writeable(sk)) 8435a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 84361da177e4SLinus Torvalds } 84371da177e4SLinus Torvalds return mask; 84381da177e4SLinus Torvalds } 84391da177e4SLinus Torvalds 84401da177e4SLinus Torvalds /******************************************************************** 84411da177e4SLinus Torvalds * 2nd Level Abstractions 84421da177e4SLinus Torvalds ********************************************************************/ 84431da177e4SLinus Torvalds 84441da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create( 8445f1f43763SEric W. Biederman struct sctp_bind_hashbucket *head, struct net *net, unsigned short snum) 84461da177e4SLinus Torvalds { 84471da177e4SLinus Torvalds struct sctp_bind_bucket *pp; 84481da177e4SLinus Torvalds 844954e6ecb2SChristoph Lameter pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC); 84501da177e4SLinus Torvalds if (pp) { 8451935a7f6eSLi Zefan SCTP_DBG_OBJCNT_INC(bind_bucket); 84521da177e4SLinus Torvalds pp->port = snum; 84531da177e4SLinus Torvalds pp->fastreuse = 0; 84541da177e4SLinus Torvalds INIT_HLIST_HEAD(&pp->owner); 8455f1f43763SEric W. Biederman pp->net = net; 8456d970dbf8SVlad Yasevich hlist_add_head(&pp->node, &head->chain); 84571da177e4SLinus Torvalds } 84581da177e4SLinus Torvalds return pp; 84591da177e4SLinus Torvalds } 84601da177e4SLinus Torvalds 84611da177e4SLinus Torvalds /* Caller must hold hashbucket lock for this tb with local BH disabled */ 84621da177e4SLinus Torvalds static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) 84631da177e4SLinus Torvalds { 846437fa6878SSridhar Samudrala if (pp && hlist_empty(&pp->owner)) { 8465d970dbf8SVlad Yasevich __hlist_del(&pp->node); 84661da177e4SLinus Torvalds kmem_cache_free(sctp_bucket_cachep, pp); 84671da177e4SLinus Torvalds SCTP_DBG_OBJCNT_DEC(bind_bucket); 84681da177e4SLinus Torvalds } 84691da177e4SLinus Torvalds } 84701da177e4SLinus Torvalds 84711da177e4SLinus Torvalds /* Release this socket's reference to a local port. */ 84721da177e4SLinus Torvalds static inline void __sctp_put_port(struct sock *sk) 84731da177e4SLinus Torvalds { 84741da177e4SLinus Torvalds struct sctp_bind_hashbucket *head = 8475f1f43763SEric W. Biederman &sctp_port_hashtable[sctp_phashfn(sock_net(sk), 8476f1f43763SEric W. Biederman inet_sk(sk)->inet_num)]; 84771da177e4SLinus Torvalds struct sctp_bind_bucket *pp; 84781da177e4SLinus Torvalds 84793c8e43baSwangweidong spin_lock(&head->lock); 84801da177e4SLinus Torvalds pp = sctp_sk(sk)->bind_hash; 84811da177e4SLinus Torvalds __sk_del_bind_node(sk); 84821da177e4SLinus Torvalds sctp_sk(sk)->bind_hash = NULL; 8483c720c7e8SEric Dumazet inet_sk(sk)->inet_num = 0; 84841da177e4SLinus Torvalds sctp_bucket_destroy(pp); 84853c8e43baSwangweidong spin_unlock(&head->lock); 84861da177e4SLinus Torvalds } 84871da177e4SLinus Torvalds 84881da177e4SLinus Torvalds void sctp_put_port(struct sock *sk) 84891da177e4SLinus Torvalds { 849079b91130Swangweidong local_bh_disable(); 84911da177e4SLinus Torvalds __sctp_put_port(sk); 849279b91130Swangweidong local_bh_enable(); 84931da177e4SLinus Torvalds } 84941da177e4SLinus Torvalds 84951da177e4SLinus Torvalds /* 84961da177e4SLinus Torvalds * The system picks an ephemeral port and choose an address set equivalent 84971da177e4SLinus Torvalds * to binding with a wildcard address. 84981da177e4SLinus Torvalds * One of those addresses will be the primary address for the association. 84991da177e4SLinus Torvalds * This automatically enables the multihoming capability of SCTP. 85001da177e4SLinus Torvalds */ 85011da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk) 85021da177e4SLinus Torvalds { 85031da177e4SLinus Torvalds union sctp_addr autoaddr; 85041da177e4SLinus Torvalds struct sctp_af *af; 85056fbfa9f9SAl Viro __be16 port; 85061da177e4SLinus Torvalds 85071da177e4SLinus Torvalds /* Initialize a local sockaddr structure to INADDR_ANY. */ 85081da177e4SLinus Torvalds af = sctp_sk(sk)->pf->af; 85091da177e4SLinus Torvalds 8510c720c7e8SEric Dumazet port = htons(inet_sk(sk)->inet_num); 85111da177e4SLinus Torvalds af->inaddr_any(&autoaddr, port); 85121da177e4SLinus Torvalds 85131da177e4SLinus Torvalds return sctp_do_bind(sk, &autoaddr, af->sockaddr_len); 85141da177e4SLinus Torvalds } 85151da177e4SLinus Torvalds 85161da177e4SLinus Torvalds /* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. 85171da177e4SLinus Torvalds * 85181da177e4SLinus Torvalds * From RFC 2292 85191da177e4SLinus Torvalds * 4.2 The cmsghdr Structure * 85201da177e4SLinus Torvalds * 85211da177e4SLinus Torvalds * When ancillary data is sent or received, any number of ancillary data 85221da177e4SLinus Torvalds * objects can be specified by the msg_control and msg_controllen members of 85231da177e4SLinus Torvalds * the msghdr structure, because each object is preceded by 85241da177e4SLinus Torvalds * a cmsghdr structure defining the object's length (the cmsg_len member). 85251da177e4SLinus Torvalds * Historically Berkeley-derived implementations have passed only one object 85261da177e4SLinus Torvalds * at a time, but this API allows multiple objects to be 85271da177e4SLinus Torvalds * passed in a single call to sendmsg() or recvmsg(). The following example 85281da177e4SLinus Torvalds * shows two ancillary data objects in a control buffer. 85291da177e4SLinus Torvalds * 85301da177e4SLinus Torvalds * |<--------------------------- msg_controllen -------------------------->| 85311da177e4SLinus Torvalds * | | 85321da177e4SLinus Torvalds * 85331da177e4SLinus Torvalds * |<----- ancillary data object ----->|<----- ancillary data object ----->| 85341da177e4SLinus Torvalds * 85351da177e4SLinus Torvalds * |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->| 85361da177e4SLinus Torvalds * | | | 85371da177e4SLinus Torvalds * 85381da177e4SLinus Torvalds * |<---------- cmsg_len ---------->| |<--------- cmsg_len ----------->| | 85391da177e4SLinus Torvalds * 85401da177e4SLinus Torvalds * |<--------- CMSG_LEN() --------->| |<-------- CMSG_LEN() ---------->| | 85411da177e4SLinus Torvalds * | | | | | 85421da177e4SLinus Torvalds * 85431da177e4SLinus Torvalds * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 85441da177e4SLinus Torvalds * |cmsg_|cmsg_|cmsg_|XX| |XX|cmsg_|cmsg_|cmsg_|XX| |XX| 85451da177e4SLinus Torvalds * 85461da177e4SLinus Torvalds * |len |level|type |XX|cmsg_data[]|XX|len |level|type |XX|cmsg_data[]|XX| 85471da177e4SLinus Torvalds * 85481da177e4SLinus Torvalds * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 85491da177e4SLinus Torvalds * ^ 85501da177e4SLinus Torvalds * | 85511da177e4SLinus Torvalds * 85521da177e4SLinus Torvalds * msg_control 85531da177e4SLinus Torvalds * points here 85541da177e4SLinus Torvalds */ 8555a05437acSXin Long static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs) 85561da177e4SLinus Torvalds { 8557ab38fb04SVlad Yasevich struct msghdr *my_msg = (struct msghdr *)msg; 8558a05437acSXin Long struct cmsghdr *cmsg; 85591da177e4SLinus Torvalds 8560f95b414eSGu Zheng for_each_cmsghdr(cmsg, my_msg) { 8561ab38fb04SVlad Yasevich if (!CMSG_OK(my_msg, cmsg)) 85621da177e4SLinus Torvalds return -EINVAL; 85631da177e4SLinus Torvalds 85641da177e4SLinus Torvalds /* Should we parse this header or ignore? */ 85651da177e4SLinus Torvalds if (cmsg->cmsg_level != IPPROTO_SCTP) 85661da177e4SLinus Torvalds continue; 85671da177e4SLinus Torvalds 85681da177e4SLinus Torvalds /* Strictly check lengths following example in SCM code. */ 85691da177e4SLinus Torvalds switch (cmsg->cmsg_type) { 85701da177e4SLinus Torvalds case SCTP_INIT: 85711da177e4SLinus Torvalds /* SCTP Socket API Extension 857263b94938SGeir Ola Vaagland * 5.3.1 SCTP Initiation Structure (SCTP_INIT) 85731da177e4SLinus Torvalds * 85741da177e4SLinus Torvalds * This cmsghdr structure provides information for 85751da177e4SLinus Torvalds * initializing new SCTP associations with sendmsg(). 85761da177e4SLinus Torvalds * The SCTP_INITMSG socket option uses this same data 85771da177e4SLinus Torvalds * structure. This structure is not used for 85781da177e4SLinus Torvalds * recvmsg(). 85791da177e4SLinus Torvalds * 85801da177e4SLinus Torvalds * cmsg_level cmsg_type cmsg_data[] 85811da177e4SLinus Torvalds * ------------ ------------ ---------------------- 85821da177e4SLinus Torvalds * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg 85831da177e4SLinus Torvalds */ 858463b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg))) 85851da177e4SLinus Torvalds return -EINVAL; 858663b94938SGeir Ola Vaagland 858763b94938SGeir Ola Vaagland cmsgs->init = CMSG_DATA(cmsg); 85881da177e4SLinus Torvalds break; 85891da177e4SLinus Torvalds 85901da177e4SLinus Torvalds case SCTP_SNDRCV: 85911da177e4SLinus Torvalds /* SCTP Socket API Extension 859263b94938SGeir Ola Vaagland * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV) 85931da177e4SLinus Torvalds * 85941da177e4SLinus Torvalds * This cmsghdr structure specifies SCTP options for 85951da177e4SLinus Torvalds * sendmsg() and describes SCTP header information 85961da177e4SLinus Torvalds * about a received message through recvmsg(). 85971da177e4SLinus Torvalds * 85981da177e4SLinus Torvalds * cmsg_level cmsg_type cmsg_data[] 85991da177e4SLinus Torvalds * ------------ ------------ ---------------------- 86001da177e4SLinus Torvalds * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo 86011da177e4SLinus Torvalds */ 860263b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) 86031da177e4SLinus Torvalds return -EINVAL; 86041da177e4SLinus Torvalds 860563b94938SGeir Ola Vaagland cmsgs->srinfo = CMSG_DATA(cmsg); 86061da177e4SLinus Torvalds 860763b94938SGeir Ola Vaagland if (cmsgs->srinfo->sinfo_flags & 8608eaa5c54dSIvan Skytte Jorgensen ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 860949102805SXin Long SCTP_SACK_IMMEDIATELY | SCTP_SENDALL | 861049102805SXin Long SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF)) 86111da177e4SLinus Torvalds return -EINVAL; 86121da177e4SLinus Torvalds break; 86131da177e4SLinus Torvalds 861463b94938SGeir Ola Vaagland case SCTP_SNDINFO: 861563b94938SGeir Ola Vaagland /* SCTP Socket API Extension 861663b94938SGeir Ola Vaagland * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) 861763b94938SGeir Ola Vaagland * 861863b94938SGeir Ola Vaagland * This cmsghdr structure specifies SCTP options for 861963b94938SGeir Ola Vaagland * sendmsg(). This structure and SCTP_RCVINFO replaces 862063b94938SGeir Ola Vaagland * SCTP_SNDRCV which has been deprecated. 862163b94938SGeir Ola Vaagland * 862263b94938SGeir Ola Vaagland * cmsg_level cmsg_type cmsg_data[] 862363b94938SGeir Ola Vaagland * ------------ ------------ --------------------- 862463b94938SGeir Ola Vaagland * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo 862563b94938SGeir Ola Vaagland */ 862663b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo))) 862763b94938SGeir Ola Vaagland return -EINVAL; 862863b94938SGeir Ola Vaagland 862963b94938SGeir Ola Vaagland cmsgs->sinfo = CMSG_DATA(cmsg); 863063b94938SGeir Ola Vaagland 863163b94938SGeir Ola Vaagland if (cmsgs->sinfo->snd_flags & 863263b94938SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 863349102805SXin Long SCTP_SACK_IMMEDIATELY | SCTP_SENDALL | 863449102805SXin Long SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF)) 863563b94938SGeir Ola Vaagland return -EINVAL; 863663b94938SGeir Ola Vaagland break; 8637ed63afb8SXin Long case SCTP_PRINFO: 8638ed63afb8SXin Long /* SCTP Socket API Extension 8639ed63afb8SXin Long * 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO) 8640ed63afb8SXin Long * 8641ed63afb8SXin Long * This cmsghdr structure specifies SCTP options for sendmsg(). 8642ed63afb8SXin Long * 8643ed63afb8SXin Long * cmsg_level cmsg_type cmsg_data[] 8644ed63afb8SXin Long * ------------ ------------ --------------------- 8645ed63afb8SXin Long * IPPROTO_SCTP SCTP_PRINFO struct sctp_prinfo 8646ed63afb8SXin Long */ 8647ed63afb8SXin Long if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_prinfo))) 8648ed63afb8SXin Long return -EINVAL; 8649ed63afb8SXin Long 8650ed63afb8SXin Long cmsgs->prinfo = CMSG_DATA(cmsg); 8651ed63afb8SXin Long if (cmsgs->prinfo->pr_policy & ~SCTP_PR_SCTP_MASK) 8652ed63afb8SXin Long return -EINVAL; 8653ed63afb8SXin Long 8654ed63afb8SXin Long if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE) 8655ed63afb8SXin Long cmsgs->prinfo->pr_value = 0; 8656ed63afb8SXin Long break; 86573ff547c0SXin Long case SCTP_AUTHINFO: 86583ff547c0SXin Long /* SCTP Socket API Extension 86593ff547c0SXin Long * 5.3.8 SCTP AUTH Information Structure (SCTP_AUTHINFO) 86603ff547c0SXin Long * 86613ff547c0SXin Long * This cmsghdr structure specifies SCTP options for sendmsg(). 86623ff547c0SXin Long * 86633ff547c0SXin Long * cmsg_level cmsg_type cmsg_data[] 86643ff547c0SXin Long * ------------ ------------ --------------------- 86653ff547c0SXin Long * IPPROTO_SCTP SCTP_AUTHINFO struct sctp_authinfo 86663ff547c0SXin Long */ 86673ff547c0SXin Long if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_authinfo))) 86683ff547c0SXin Long return -EINVAL; 86693ff547c0SXin Long 86703ff547c0SXin Long cmsgs->authinfo = CMSG_DATA(cmsg); 86713ff547c0SXin Long break; 86722c0dbaa0SXin Long case SCTP_DSTADDRV4: 86732c0dbaa0SXin Long case SCTP_DSTADDRV6: 86742c0dbaa0SXin Long /* SCTP Socket API Extension 86752c0dbaa0SXin Long * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6) 86762c0dbaa0SXin Long * 86772c0dbaa0SXin Long * This cmsghdr structure specifies SCTP options for sendmsg(). 86782c0dbaa0SXin Long * 86792c0dbaa0SXin Long * cmsg_level cmsg_type cmsg_data[] 86802c0dbaa0SXin Long * ------------ ------------ --------------------- 86812c0dbaa0SXin Long * IPPROTO_SCTP SCTP_DSTADDRV4 struct in_addr 86822c0dbaa0SXin Long * ------------ ------------ --------------------- 86832c0dbaa0SXin Long * IPPROTO_SCTP SCTP_DSTADDRV6 struct in6_addr 86842c0dbaa0SXin Long */ 86852c0dbaa0SXin Long cmsgs->addrs_msg = my_msg; 86862c0dbaa0SXin Long break; 86871da177e4SLinus Torvalds default: 86881da177e4SLinus Torvalds return -EINVAL; 86893ff50b79SStephen Hemminger } 86901da177e4SLinus Torvalds } 869163b94938SGeir Ola Vaagland 86921da177e4SLinus Torvalds return 0; 86931da177e4SLinus Torvalds } 86941da177e4SLinus Torvalds 86951da177e4SLinus Torvalds /* 86961da177e4SLinus Torvalds * Wait for a packet.. 86971da177e4SLinus Torvalds * Note: This function is the same function as in core/datagram.c 86981da177e4SLinus Torvalds * with a few modifications to make lksctp work. 86991da177e4SLinus Torvalds */ 87001da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p) 87011da177e4SLinus Torvalds { 87021da177e4SLinus Torvalds int error; 87031da177e4SLinus Torvalds DEFINE_WAIT(wait); 87041da177e4SLinus Torvalds 8705aa395145SEric Dumazet prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 87061da177e4SLinus Torvalds 87071da177e4SLinus Torvalds /* Socket errors? */ 87081da177e4SLinus Torvalds error = sock_error(sk); 87091da177e4SLinus Torvalds if (error) 87101da177e4SLinus Torvalds goto out; 87111da177e4SLinus Torvalds 87121da177e4SLinus Torvalds if (!skb_queue_empty(&sk->sk_receive_queue)) 87131da177e4SLinus Torvalds goto ready; 87141da177e4SLinus Torvalds 87151da177e4SLinus Torvalds /* Socket shut down? */ 87161da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 87171da177e4SLinus Torvalds goto out; 87181da177e4SLinus Torvalds 87191da177e4SLinus Torvalds /* Sequenced packets can come disconnected. If so we report the 87201da177e4SLinus Torvalds * problem. 87211da177e4SLinus Torvalds */ 87221da177e4SLinus Torvalds error = -ENOTCONN; 87231da177e4SLinus Torvalds 87241da177e4SLinus Torvalds /* Is there a good reason to think that we may receive some data? */ 87251da177e4SLinus Torvalds if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING)) 87261da177e4SLinus Torvalds goto out; 87271da177e4SLinus Torvalds 87281da177e4SLinus Torvalds /* Handle signals. */ 87291da177e4SLinus Torvalds if (signal_pending(current)) 87301da177e4SLinus Torvalds goto interrupted; 87311da177e4SLinus Torvalds 87321da177e4SLinus Torvalds /* Let another process have a go. Since we are going to sleep 87331da177e4SLinus Torvalds * anyway. Note: This may cause odd behaviors if the message 87341da177e4SLinus Torvalds * does not fit in the user's buffer, but this seems to be the 87351da177e4SLinus Torvalds * only way to honor MSG_DONTWAIT realistically. 87361da177e4SLinus Torvalds */ 8737048ed4b6Swangweidong release_sock(sk); 87381da177e4SLinus Torvalds *timeo_p = schedule_timeout(*timeo_p); 8739048ed4b6Swangweidong lock_sock(sk); 87401da177e4SLinus Torvalds 87411da177e4SLinus Torvalds ready: 8742aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 87431da177e4SLinus Torvalds return 0; 87441da177e4SLinus Torvalds 87451da177e4SLinus Torvalds interrupted: 87461da177e4SLinus Torvalds error = sock_intr_errno(*timeo_p); 87471da177e4SLinus Torvalds 87481da177e4SLinus Torvalds out: 8749aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 87501da177e4SLinus Torvalds *err = error; 87511da177e4SLinus Torvalds return error; 87521da177e4SLinus Torvalds } 87531da177e4SLinus Torvalds 87541da177e4SLinus Torvalds /* Receive a datagram. 87551da177e4SLinus Torvalds * Note: This is pretty much the same routine as in core/datagram.c 87561da177e4SLinus Torvalds * with a few changes to make lksctp work. 87571da177e4SLinus Torvalds */ 87582347c80fSGeir Ola Vaagland struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, 87591da177e4SLinus Torvalds int noblock, int *err) 87601da177e4SLinus Torvalds { 87611da177e4SLinus Torvalds int error; 87621da177e4SLinus Torvalds struct sk_buff *skb; 87631da177e4SLinus Torvalds long timeo; 87641da177e4SLinus Torvalds 87651da177e4SLinus Torvalds timeo = sock_rcvtimeo(sk, noblock); 87661da177e4SLinus Torvalds 8767bb33381dSDaniel Borkmann pr_debug("%s: timeo:%ld, max:%ld\n", __func__, timeo, 8768bb33381dSDaniel Borkmann MAX_SCHEDULE_TIMEOUT); 87691da177e4SLinus Torvalds 87701da177e4SLinus Torvalds do { 87711da177e4SLinus Torvalds /* Again only user level code calls this function, 87721da177e4SLinus Torvalds * so nothing interrupt level 87731da177e4SLinus Torvalds * will suddenly eat the receive_queue. 87741da177e4SLinus Torvalds * 87751da177e4SLinus Torvalds * Look at current nfs client by the way... 87768917a3c0SDavid Shwatrz * However, this function was correct in any case. 8) 87771da177e4SLinus Torvalds */ 87781da177e4SLinus Torvalds if (flags & MSG_PEEK) { 87791da177e4SLinus Torvalds skb = skb_peek(&sk->sk_receive_queue); 87801da177e4SLinus Torvalds if (skb) 878163354797SReshetova, Elena refcount_inc(&skb->users); 87821da177e4SLinus Torvalds } else { 8783311b2177SMarcelo Ricardo Leitner skb = __skb_dequeue(&sk->sk_receive_queue); 87841da177e4SLinus Torvalds } 87851da177e4SLinus Torvalds 87861da177e4SLinus Torvalds if (skb) 87871da177e4SLinus Torvalds return skb; 87881da177e4SLinus Torvalds 87896736dc35SNeil Horman /* Caller is allowed not to check sk->sk_err before calling. */ 87906736dc35SNeil Horman error = sock_error(sk); 87916736dc35SNeil Horman if (error) 87926736dc35SNeil Horman goto no_packet; 87936736dc35SNeil Horman 87941da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 87951da177e4SLinus Torvalds break; 87961da177e4SLinus Torvalds 87972b5cd0dfSAlexander Duyck if (sk_can_busy_loop(sk)) { 87982b5cd0dfSAlexander Duyck sk_busy_loop(sk, noblock); 87992b5cd0dfSAlexander Duyck 88003f926af3SEric Dumazet if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 88018465a5fcSNeil Horman continue; 88022b5cd0dfSAlexander Duyck } 88038465a5fcSNeil Horman 88041da177e4SLinus Torvalds /* User doesn't want to wait. */ 88051da177e4SLinus Torvalds error = -EAGAIN; 88061da177e4SLinus Torvalds if (!timeo) 88071da177e4SLinus Torvalds goto no_packet; 88081da177e4SLinus Torvalds } while (sctp_wait_for_packet(sk, err, &timeo) == 0); 88091da177e4SLinus Torvalds 88101da177e4SLinus Torvalds return NULL; 88111da177e4SLinus Torvalds 88121da177e4SLinus Torvalds no_packet: 88131da177e4SLinus Torvalds *err = error; 88141da177e4SLinus Torvalds return NULL; 88151da177e4SLinus Torvalds } 88161da177e4SLinus Torvalds 88171da177e4SLinus Torvalds /* If sndbuf has changed, wake up per association sndbuf waiters. */ 88181da177e4SLinus Torvalds static void __sctp_write_space(struct sctp_association *asoc) 88191da177e4SLinus Torvalds { 88201da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 88211da177e4SLinus Torvalds 8822ceb5d58bSEric Dumazet if (sctp_wspace(asoc) <= 0) 8823ceb5d58bSEric Dumazet return; 8824ceb5d58bSEric Dumazet 88251da177e4SLinus Torvalds if (waitqueue_active(&asoc->wait)) 88261da177e4SLinus Torvalds wake_up_interruptible(&asoc->wait); 88271da177e4SLinus Torvalds 88281da177e4SLinus Torvalds if (sctp_writeable(sk)) { 8829ceb5d58bSEric Dumazet struct socket_wq *wq; 8830eaefd110SEric Dumazet 8831ceb5d58bSEric Dumazet rcu_read_lock(); 8832ceb5d58bSEric Dumazet wq = rcu_dereference(sk->sk_wq); 8833ceb5d58bSEric Dumazet if (wq) { 8834ceb5d58bSEric Dumazet if (waitqueue_active(&wq->wait)) 8835ceb5d58bSEric Dumazet wake_up_interruptible(&wq->wait); 88361da177e4SLinus Torvalds 88371da177e4SLinus Torvalds /* Note that we try to include the Async I/O support 88381da177e4SLinus Torvalds * here by modeling from the current TCP/UDP code. 88391da177e4SLinus Torvalds * We have not tested with it yet. 88401da177e4SLinus Torvalds */ 8841eaefd110SEric Dumazet if (!(sk->sk_shutdown & SEND_SHUTDOWN)) 8842ceb5d58bSEric Dumazet sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT); 88431da177e4SLinus Torvalds } 8844ceb5d58bSEric Dumazet rcu_read_unlock(); 88451da177e4SLinus Torvalds } 88461da177e4SLinus Torvalds } 88471da177e4SLinus Torvalds 884852c35befSDaniel Borkmann static void sctp_wake_up_waiters(struct sock *sk, 884952c35befSDaniel Borkmann struct sctp_association *asoc) 885052c35befSDaniel Borkmann { 885152c35befSDaniel Borkmann struct sctp_association *tmp = asoc; 885252c35befSDaniel Borkmann 885352c35befSDaniel Borkmann /* We do accounting for the sndbuf space per association, 885452c35befSDaniel Borkmann * so we only need to wake our own association. 885552c35befSDaniel Borkmann */ 885652c35befSDaniel Borkmann if (asoc->ep->sndbuf_policy) 885752c35befSDaniel Borkmann return __sctp_write_space(asoc); 885852c35befSDaniel Borkmann 88591e1cdf8aSDaniel Borkmann /* If association goes down and is just flushing its 88601e1cdf8aSDaniel Borkmann * outq, then just normally notify others. 88611e1cdf8aSDaniel Borkmann */ 88621e1cdf8aSDaniel Borkmann if (asoc->base.dead) 88631e1cdf8aSDaniel Borkmann return sctp_write_space(sk); 88641e1cdf8aSDaniel Borkmann 886552c35befSDaniel Borkmann /* Accounting for the sndbuf space is per socket, so we 886652c35befSDaniel Borkmann * need to wake up others, try to be fair and in case of 886752c35befSDaniel Borkmann * other associations, let them have a go first instead 886852c35befSDaniel Borkmann * of just doing a sctp_write_space() call. 886952c35befSDaniel Borkmann * 887052c35befSDaniel Borkmann * Note that we reach sctp_wake_up_waiters() only when 887152c35befSDaniel Borkmann * associations free up queued chunks, thus we are under 887252c35befSDaniel Borkmann * lock and the list of associations on a socket is 887352c35befSDaniel Borkmann * guaranteed not to change. 887452c35befSDaniel Borkmann */ 887552c35befSDaniel Borkmann for (tmp = list_next_entry(tmp, asocs); 1; 887652c35befSDaniel Borkmann tmp = list_next_entry(tmp, asocs)) { 887752c35befSDaniel Borkmann /* Manually skip the head element. */ 887852c35befSDaniel Borkmann if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs)) 887952c35befSDaniel Borkmann continue; 888052c35befSDaniel Borkmann /* Wake up association. */ 888152c35befSDaniel Borkmann __sctp_write_space(tmp); 888252c35befSDaniel Borkmann /* We've reached the end. */ 888352c35befSDaniel Borkmann if (tmp == asoc) 888452c35befSDaniel Borkmann break; 888552c35befSDaniel Borkmann } 888652c35befSDaniel Borkmann } 888752c35befSDaniel Borkmann 88881da177e4SLinus Torvalds /* Do accounting for the sndbuf space. 88891da177e4SLinus Torvalds * Decrement the used sndbuf space of the corresponding association by the 88901da177e4SLinus Torvalds * data size which was just transmitted(freed). 88911da177e4SLinus Torvalds */ 88921da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb) 88931da177e4SLinus Torvalds { 8894f869c912SDaniel Borkmann struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg; 8895f869c912SDaniel Borkmann struct sctp_association *asoc = chunk->asoc; 8896f869c912SDaniel Borkmann struct sock *sk = asoc->base.sk; 88971da177e4SLinus Torvalds 88983ab224beSHideo Aoki sk_mem_uncharge(sk, skb->truesize); 8899605c0ac1SXin Long sk->sk_wmem_queued -= skb->truesize + sizeof(struct sctp_chunk); 8900605c0ac1SXin Long asoc->sndbuf_used -= skb->truesize + sizeof(struct sctp_chunk); 8901605c0ac1SXin Long WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), 8902605c0ac1SXin Long &sk->sk_wmem_alloc)); 89034d93df0aSNeil Horman 8904ec2e506cSXin Long if (chunk->shkey) { 8905ec2e506cSXin Long struct sctp_shared_key *shkey = chunk->shkey; 8906ec2e506cSXin Long 8907ec2e506cSXin Long /* refcnt == 2 and !list_empty mean after this release, it's 8908ec2e506cSXin Long * not being used anywhere, and it's time to notify userland 8909ec2e506cSXin Long * that this shkey can be freed if it's been deactivated. 8910ec2e506cSXin Long */ 8911ec2e506cSXin Long if (shkey->deactivated && !list_empty(&shkey->key_list) && 8912ec2e506cSXin Long refcount_read(&shkey->refcnt) == 2) { 8913ec2e506cSXin Long struct sctp_ulpevent *ev; 8914ec2e506cSXin Long 8915ec2e506cSXin Long ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id, 8916ec2e506cSXin Long SCTP_AUTH_FREE_KEY, 8917ec2e506cSXin Long GFP_KERNEL); 8918ec2e506cSXin Long if (ev) 8919ec2e506cSXin Long asoc->stream.si->enqueue_event(&asoc->ulpq, ev); 8920ec2e506cSXin Long } 89211b1e0bc9SXin Long sctp_auth_shkey_release(chunk->shkey); 8922ec2e506cSXin Long } 89231b1e0bc9SXin Long 89244eb701dfSNeil Horman sock_wfree(skb); 892552c35befSDaniel Borkmann sctp_wake_up_waiters(sk, asoc); 89261da177e4SLinus Torvalds 89271da177e4SLinus Torvalds sctp_association_put(asoc); 89281da177e4SLinus Torvalds } 89291da177e4SLinus Torvalds 8930331c4ee7SVlad Yasevich /* Do accounting for the receive space on the socket. 8931331c4ee7SVlad Yasevich * Accounting for the association is done in ulpevent.c 8932331c4ee7SVlad Yasevich * We set this as a destructor for the cloned data skbs so that 8933331c4ee7SVlad Yasevich * accounting is done at the correct time. 8934331c4ee7SVlad Yasevich */ 8935331c4ee7SVlad Yasevich void sctp_sock_rfree(struct sk_buff *skb) 8936331c4ee7SVlad Yasevich { 8937331c4ee7SVlad Yasevich struct sock *sk = skb->sk; 8938331c4ee7SVlad Yasevich struct sctp_ulpevent *event = sctp_skb2event(skb); 8939331c4ee7SVlad Yasevich 8940331c4ee7SVlad Yasevich atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); 89414d93df0aSNeil Horman 89424d93df0aSNeil Horman /* 89433ab224beSHideo Aoki * Mimic the behavior of sock_rfree 89444d93df0aSNeil Horman */ 89453ab224beSHideo Aoki sk_mem_uncharge(sk, event->rmem_len); 8946331c4ee7SVlad Yasevich } 8947331c4ee7SVlad Yasevich 8948331c4ee7SVlad Yasevich 89491da177e4SLinus Torvalds /* Helper function to wait for space in the sndbuf. */ 89501da177e4SLinus Torvalds static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 8951a0ff6600SXin Long size_t msg_len) 89521da177e4SLinus Torvalds { 89531da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 89541da177e4SLinus Torvalds long current_timeo = *timeo_p; 89551da177e4SLinus Torvalds DEFINE_WAIT(wait); 8956a0ff6600SXin Long int err = 0; 89571da177e4SLinus Torvalds 8958bb33381dSDaniel Borkmann pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc, 8959bb33381dSDaniel Borkmann *timeo_p, msg_len); 89601da177e4SLinus Torvalds 89611da177e4SLinus Torvalds /* Increment the association's refcnt. */ 89621da177e4SLinus Torvalds sctp_association_hold(asoc); 89631da177e4SLinus Torvalds 89641da177e4SLinus Torvalds /* Wait on the association specific sndbuf space. */ 89651da177e4SLinus Torvalds for (;;) { 89661da177e4SLinus Torvalds prepare_to_wait_exclusive(&asoc->wait, &wait, 89671da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 8968ca3af4ddSXin Long if (asoc->base.dead) 8969ca3af4ddSXin Long goto do_dead; 89701da177e4SLinus Torvalds if (!*timeo_p) 89711da177e4SLinus Torvalds goto do_nonblock; 8972ca3af4ddSXin Long if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING) 89731da177e4SLinus Torvalds goto do_error; 89741da177e4SLinus Torvalds if (signal_pending(current)) 89751da177e4SLinus Torvalds goto do_interrupted; 89761033990aSXin Long if (sk_under_memory_pressure(sk)) 89771033990aSXin Long sk_mem_reclaim(sk); 89781033990aSXin Long if ((int)msg_len <= sctp_wspace(asoc) && 89791033990aSXin Long sk_wmem_schedule(sk, msg_len)) 89801da177e4SLinus Torvalds break; 89811da177e4SLinus Torvalds 89821da177e4SLinus Torvalds /* Let another process have a go. Since we are going 89831da177e4SLinus Torvalds * to sleep anyway. 89841da177e4SLinus Torvalds */ 8985048ed4b6Swangweidong release_sock(sk); 89861da177e4SLinus Torvalds current_timeo = schedule_timeout(current_timeo); 8987048ed4b6Swangweidong lock_sock(sk); 8988a0ff6600SXin Long if (sk != asoc->base.sk) 8989a0ff6600SXin Long goto do_error; 89901da177e4SLinus Torvalds 89911da177e4SLinus Torvalds *timeo_p = current_timeo; 89921da177e4SLinus Torvalds } 89931da177e4SLinus Torvalds 89941da177e4SLinus Torvalds out: 89951da177e4SLinus Torvalds finish_wait(&asoc->wait, &wait); 89961da177e4SLinus Torvalds 89971da177e4SLinus Torvalds /* Release the association's refcnt. */ 89981da177e4SLinus Torvalds sctp_association_put(asoc); 89991da177e4SLinus Torvalds 90001da177e4SLinus Torvalds return err; 90011da177e4SLinus Torvalds 9002ca3af4ddSXin Long do_dead: 9003ca3af4ddSXin Long err = -ESRCH; 9004ca3af4ddSXin Long goto out; 9005ca3af4ddSXin Long 90061da177e4SLinus Torvalds do_error: 90071da177e4SLinus Torvalds err = -EPIPE; 90081da177e4SLinus Torvalds goto out; 90091da177e4SLinus Torvalds 90101da177e4SLinus Torvalds do_interrupted: 90111da177e4SLinus Torvalds err = sock_intr_errno(*timeo_p); 90121da177e4SLinus Torvalds goto out; 90131da177e4SLinus Torvalds 90141da177e4SLinus Torvalds do_nonblock: 90151da177e4SLinus Torvalds err = -EAGAIN; 90161da177e4SLinus Torvalds goto out; 90171da177e4SLinus Torvalds } 90181da177e4SLinus Torvalds 9019676d2369SDavid S. Miller void sctp_data_ready(struct sock *sk) 9020561b1733SWei Yongjun { 90217ef52737SDavid S. Miller struct socket_wq *wq; 90227ef52737SDavid S. Miller 90237ef52737SDavid S. Miller rcu_read_lock(); 90247ef52737SDavid S. Miller wq = rcu_dereference(sk->sk_wq); 90251ce0bf50SHerbert Xu if (skwq_has_sleeper(wq)) 9026a9a08845SLinus Torvalds wake_up_interruptible_sync_poll(&wq->wait, EPOLLIN | 9027a9a08845SLinus Torvalds EPOLLRDNORM | EPOLLRDBAND); 9028561b1733SWei Yongjun sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); 90297ef52737SDavid S. Miller rcu_read_unlock(); 9030561b1733SWei Yongjun } 9031561b1733SWei Yongjun 90321da177e4SLinus Torvalds /* If socket sndbuf has changed, wake up all per association waiters. */ 90331da177e4SLinus Torvalds void sctp_write_space(struct sock *sk) 90341da177e4SLinus Torvalds { 90351da177e4SLinus Torvalds struct sctp_association *asoc; 90361da177e4SLinus Torvalds 90371da177e4SLinus Torvalds /* Wake up the tasks in each wait queue. */ 90389dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) { 90391da177e4SLinus Torvalds __sctp_write_space(asoc); 90401da177e4SLinus Torvalds } 90411da177e4SLinus Torvalds } 90421da177e4SLinus Torvalds 90431da177e4SLinus Torvalds /* Is there any sndbuf space available on the socket? 90441da177e4SLinus Torvalds * 90459bffc4acSNeil Horman * Note that sk_wmem_alloc is the sum of the send buffers on all of the 90461da177e4SLinus Torvalds * associations on the same socket. For a UDP-style socket with 90471da177e4SLinus Torvalds * multiple associations, it is possible for it to be "unwriteable" 90481da177e4SLinus Torvalds * prematurely. I assume that this is acceptable because 90491da177e4SLinus Torvalds * a premature "unwriteable" is better than an accidental "writeable" which 90501da177e4SLinus Torvalds * would cause an unwanted block under certain circumstances. For the 1-1 90511da177e4SLinus Torvalds * UDP-style sockets or TCP-style sockets, this code should work. 90521da177e4SLinus Torvalds * - Daisy 90531da177e4SLinus Torvalds */ 9054cd305c74SXin Long static bool sctp_writeable(struct sock *sk) 90551da177e4SLinus Torvalds { 9056cd305c74SXin Long return sk->sk_sndbuf > sk->sk_wmem_queued; 90571da177e4SLinus Torvalds } 90581da177e4SLinus Torvalds 90591da177e4SLinus Torvalds /* Wait for an association to go into ESTABLISHED state. If timeout is 0, 90601da177e4SLinus Torvalds * returns immediately with EINPROGRESS. 90611da177e4SLinus Torvalds */ 90621da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) 90631da177e4SLinus Torvalds { 90641da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 90651da177e4SLinus Torvalds int err = 0; 90661da177e4SLinus Torvalds long current_timeo = *timeo_p; 90671da177e4SLinus Torvalds DEFINE_WAIT(wait); 90681da177e4SLinus Torvalds 9069bb33381dSDaniel Borkmann pr_debug("%s: asoc:%p, timeo:%ld\n", __func__, asoc, *timeo_p); 90701da177e4SLinus Torvalds 90711da177e4SLinus Torvalds /* Increment the association's refcnt. */ 90721da177e4SLinus Torvalds sctp_association_hold(asoc); 90731da177e4SLinus Torvalds 90741da177e4SLinus Torvalds for (;;) { 90751da177e4SLinus Torvalds prepare_to_wait_exclusive(&asoc->wait, &wait, 90761da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 90771da177e4SLinus Torvalds if (!*timeo_p) 90781da177e4SLinus Torvalds goto do_nonblock; 90791da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 90801da177e4SLinus Torvalds break; 90811da177e4SLinus Torvalds if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || 90821da177e4SLinus Torvalds asoc->base.dead) 90831da177e4SLinus Torvalds goto do_error; 90841da177e4SLinus Torvalds if (signal_pending(current)) 90851da177e4SLinus Torvalds goto do_interrupted; 90861da177e4SLinus Torvalds 90871da177e4SLinus Torvalds if (sctp_state(asoc, ESTABLISHED)) 90881da177e4SLinus Torvalds break; 90891da177e4SLinus Torvalds 90901da177e4SLinus Torvalds /* Let another process have a go. Since we are going 90911da177e4SLinus Torvalds * to sleep anyway. 90921da177e4SLinus Torvalds */ 9093048ed4b6Swangweidong release_sock(sk); 90941da177e4SLinus Torvalds current_timeo = schedule_timeout(current_timeo); 9095048ed4b6Swangweidong lock_sock(sk); 90961da177e4SLinus Torvalds 90971da177e4SLinus Torvalds *timeo_p = current_timeo; 90981da177e4SLinus Torvalds } 90991da177e4SLinus Torvalds 91001da177e4SLinus Torvalds out: 91011da177e4SLinus Torvalds finish_wait(&asoc->wait, &wait); 91021da177e4SLinus Torvalds 91031da177e4SLinus Torvalds /* Release the association's refcnt. */ 91041da177e4SLinus Torvalds sctp_association_put(asoc); 91051da177e4SLinus Torvalds 91061da177e4SLinus Torvalds return err; 91071da177e4SLinus Torvalds 91081da177e4SLinus Torvalds do_error: 910981845c21SVlad Yasevich if (asoc->init_err_counter + 1 > asoc->max_init_attempts) 91101da177e4SLinus Torvalds err = -ETIMEDOUT; 91111da177e4SLinus Torvalds else 91121da177e4SLinus Torvalds err = -ECONNREFUSED; 91131da177e4SLinus Torvalds goto out; 91141da177e4SLinus Torvalds 91151da177e4SLinus Torvalds do_interrupted: 91161da177e4SLinus Torvalds err = sock_intr_errno(*timeo_p); 91171da177e4SLinus Torvalds goto out; 91181da177e4SLinus Torvalds 91191da177e4SLinus Torvalds do_nonblock: 91201da177e4SLinus Torvalds err = -EINPROGRESS; 91211da177e4SLinus Torvalds goto out; 91221da177e4SLinus Torvalds } 91231da177e4SLinus Torvalds 91241da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo) 91251da177e4SLinus Torvalds { 91261da177e4SLinus Torvalds struct sctp_endpoint *ep; 91271da177e4SLinus Torvalds int err = 0; 91281da177e4SLinus Torvalds DEFINE_WAIT(wait); 91291da177e4SLinus Torvalds 91301da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 91311da177e4SLinus Torvalds 91321da177e4SLinus Torvalds 91331da177e4SLinus Torvalds for (;;) { 9134aa395145SEric Dumazet prepare_to_wait_exclusive(sk_sleep(sk), &wait, 91351da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 91361da177e4SLinus Torvalds 91371da177e4SLinus Torvalds if (list_empty(&ep->asocs)) { 9138048ed4b6Swangweidong release_sock(sk); 91391da177e4SLinus Torvalds timeo = schedule_timeout(timeo); 9140048ed4b6Swangweidong lock_sock(sk); 91411da177e4SLinus Torvalds } 91421da177e4SLinus Torvalds 91431da177e4SLinus Torvalds err = -EINVAL; 91441da177e4SLinus Torvalds if (!sctp_sstate(sk, LISTENING)) 91451da177e4SLinus Torvalds break; 91461da177e4SLinus Torvalds 91471da177e4SLinus Torvalds err = 0; 91481da177e4SLinus Torvalds if (!list_empty(&ep->asocs)) 91491da177e4SLinus Torvalds break; 91501da177e4SLinus Torvalds 91511da177e4SLinus Torvalds err = sock_intr_errno(timeo); 91521da177e4SLinus Torvalds if (signal_pending(current)) 91531da177e4SLinus Torvalds break; 91541da177e4SLinus Torvalds 91551da177e4SLinus Torvalds err = -EAGAIN; 91561da177e4SLinus Torvalds if (!timeo) 91571da177e4SLinus Torvalds break; 91581da177e4SLinus Torvalds } 91591da177e4SLinus Torvalds 9160aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 91611da177e4SLinus Torvalds 91621da177e4SLinus Torvalds return err; 91631da177e4SLinus Torvalds } 91641da177e4SLinus Torvalds 916504675210Ssebastian@breakpoint.cc static void sctp_wait_for_close(struct sock *sk, long timeout) 91661da177e4SLinus Torvalds { 91671da177e4SLinus Torvalds DEFINE_WAIT(wait); 91681da177e4SLinus Torvalds 91691da177e4SLinus Torvalds do { 9170aa395145SEric Dumazet prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 91711da177e4SLinus Torvalds if (list_empty(&sctp_sk(sk)->ep->asocs)) 91721da177e4SLinus Torvalds break; 9173048ed4b6Swangweidong release_sock(sk); 91741da177e4SLinus Torvalds timeout = schedule_timeout(timeout); 9175048ed4b6Swangweidong lock_sock(sk); 91761da177e4SLinus Torvalds } while (!signal_pending(current) && timeout); 91771da177e4SLinus Torvalds 9178aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 91791da177e4SLinus Torvalds } 91801da177e4SLinus Torvalds 9181ea2bc483STsutomu Fujii static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) 9182ea2bc483STsutomu Fujii { 9183ea2bc483STsutomu Fujii struct sk_buff *frag; 9184ea2bc483STsutomu Fujii 9185ea2bc483STsutomu Fujii if (!skb->data_len) 9186ea2bc483STsutomu Fujii goto done; 9187ea2bc483STsutomu Fujii 9188ea2bc483STsutomu Fujii /* Don't forget the fragments. */ 91891b003be3SDavid S. Miller skb_walk_frags(skb, frag) 9190ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(frag, sk); 9191ea2bc483STsutomu Fujii 9192ea2bc483STsutomu Fujii done: 9193ea2bc483STsutomu Fujii sctp_skb_set_owner_r(skb, sk); 9194ea2bc483STsutomu Fujii } 9195ea2bc483STsutomu Fujii 9196914e1c8bSVlad Yasevich void sctp_copy_sock(struct sock *newsk, struct sock *sk, 9197914e1c8bSVlad Yasevich struct sctp_association *asoc) 9198914e1c8bSVlad Yasevich { 9199914e1c8bSVlad Yasevich struct inet_sock *inet = inet_sk(sk); 920009cb47a2SJulia Lawall struct inet_sock *newinet; 92012277c7cdSRichard Haines struct sctp_sock *sp = sctp_sk(sk); 92022277c7cdSRichard Haines struct sctp_endpoint *ep = sp->ep; 9203914e1c8bSVlad Yasevich 9204914e1c8bSVlad Yasevich newsk->sk_type = sk->sk_type; 9205914e1c8bSVlad Yasevich newsk->sk_bound_dev_if = sk->sk_bound_dev_if; 9206914e1c8bSVlad Yasevich newsk->sk_flags = sk->sk_flags; 920750a5ffb1SMarcelo Ricardo Leitner newsk->sk_tsflags = sk->sk_tsflags; 920828448b80STom Herbert newsk->sk_no_check_tx = sk->sk_no_check_tx; 920928448b80STom Herbert newsk->sk_no_check_rx = sk->sk_no_check_rx; 9210914e1c8bSVlad Yasevich newsk->sk_reuse = sk->sk_reuse; 9211b0e9a2feSXin Long sctp_sk(newsk)->reuse = sp->reuse; 9212914e1c8bSVlad Yasevich 9213914e1c8bSVlad Yasevich newsk->sk_shutdown = sk->sk_shutdown; 92140a2fbac1SDaniel Borkmann newsk->sk_destruct = sctp_destruct_sock; 9215914e1c8bSVlad Yasevich newsk->sk_family = sk->sk_family; 9216914e1c8bSVlad Yasevich newsk->sk_protocol = IPPROTO_SCTP; 9217914e1c8bSVlad Yasevich newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; 9218914e1c8bSVlad Yasevich newsk->sk_sndbuf = sk->sk_sndbuf; 9219914e1c8bSVlad Yasevich newsk->sk_rcvbuf = sk->sk_rcvbuf; 9220914e1c8bSVlad Yasevich newsk->sk_lingertime = sk->sk_lingertime; 9221914e1c8bSVlad Yasevich newsk->sk_rcvtimeo = sk->sk_rcvtimeo; 9222914e1c8bSVlad Yasevich newsk->sk_sndtimeo = sk->sk_sndtimeo; 9223486bdee0SMarcelo Ricardo Leitner newsk->sk_rxhash = sk->sk_rxhash; 9224914e1c8bSVlad Yasevich 9225914e1c8bSVlad Yasevich newinet = inet_sk(newsk); 9226914e1c8bSVlad Yasevich 9227914e1c8bSVlad Yasevich /* Initialize sk's sport, dport, rcv_saddr and daddr for 9228914e1c8bSVlad Yasevich * getsockname() and getpeername() 9229914e1c8bSVlad Yasevich */ 9230c720c7e8SEric Dumazet newinet->inet_sport = inet->inet_sport; 9231c720c7e8SEric Dumazet newinet->inet_saddr = inet->inet_saddr; 9232c720c7e8SEric Dumazet newinet->inet_rcv_saddr = inet->inet_rcv_saddr; 9233c720c7e8SEric Dumazet newinet->inet_dport = htons(asoc->peer.port); 9234914e1c8bSVlad Yasevich newinet->pmtudisc = inet->pmtudisc; 9235a904a069SEric Dumazet newinet->inet_id = prandom_u32(); 9236914e1c8bSVlad Yasevich 9237914e1c8bSVlad Yasevich newinet->uc_ttl = inet->uc_ttl; 9238914e1c8bSVlad Yasevich newinet->mc_loop = 1; 9239914e1c8bSVlad Yasevich newinet->mc_ttl = 1; 9240914e1c8bSVlad Yasevich newinet->mc_index = 0; 9241914e1c8bSVlad Yasevich newinet->mc_list = NULL; 924201ce63c9SMarcelo Ricardo Leitner 924301ce63c9SMarcelo Ricardo Leitner if (newsk->sk_flags & SK_FLAGS_TIMESTAMP) 924401ce63c9SMarcelo Ricardo Leitner net_enable_timestamp(); 92453538a5c8SMarcelo Ricardo Leitner 92462277c7cdSRichard Haines /* Set newsk security attributes from orginal sk and connection 92472277c7cdSRichard Haines * security attribute from ep. 92482277c7cdSRichard Haines */ 92492277c7cdSRichard Haines security_sctp_sk_clone(ep, sk, newsk); 9250914e1c8bSVlad Yasevich } 9251914e1c8bSVlad Yasevich 92522d45a02dSMarcelo Ricardo Leitner static inline void sctp_copy_descendant(struct sock *sk_to, 92532d45a02dSMarcelo Ricardo Leitner const struct sock *sk_from) 92542d45a02dSMarcelo Ricardo Leitner { 92552d45a02dSMarcelo Ricardo Leitner int ancestor_size = sizeof(struct inet_sock) + 92562d45a02dSMarcelo Ricardo Leitner sizeof(struct sctp_sock) - 9257636d25d5SXin Long offsetof(struct sctp_sock, pd_lobby); 92582d45a02dSMarcelo Ricardo Leitner 92592d45a02dSMarcelo Ricardo Leitner if (sk_from->sk_family == PF_INET6) 92602d45a02dSMarcelo Ricardo Leitner ancestor_size += sizeof(struct ipv6_pinfo); 92612d45a02dSMarcelo Ricardo Leitner 92622d45a02dSMarcelo Ricardo Leitner __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); 92632d45a02dSMarcelo Ricardo Leitner } 92642d45a02dSMarcelo Ricardo Leitner 92651da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the assoc 92661da177e4SLinus Torvalds * and its messages to the newsk. 92671da177e4SLinus Torvalds */ 926889664c62SXin Long static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, 92691da177e4SLinus Torvalds struct sctp_association *assoc, 9270b7ef2618SXin Long enum sctp_socket_type type) 92711da177e4SLinus Torvalds { 92721da177e4SLinus Torvalds struct sctp_sock *oldsp = sctp_sk(oldsk); 92731da177e4SLinus Torvalds struct sctp_sock *newsp = sctp_sk(newsk); 92741da177e4SLinus Torvalds struct sctp_bind_bucket *pp; /* hash list port iterator */ 92751da177e4SLinus Torvalds struct sctp_endpoint *newep = newsp->ep; 92761da177e4SLinus Torvalds struct sk_buff *skb, *tmp; 92771da177e4SLinus Torvalds struct sctp_ulpevent *event; 9278f26f7c48SVlad Yasevich struct sctp_bind_hashbucket *head; 927989664c62SXin Long int err; 92801da177e4SLinus Torvalds 92811da177e4SLinus Torvalds /* Migrate socket buffer sizes and all the socket level options to the 92821da177e4SLinus Torvalds * new socket. 92831da177e4SLinus Torvalds */ 92841da177e4SLinus Torvalds newsk->sk_sndbuf = oldsk->sk_sndbuf; 92851da177e4SLinus Torvalds newsk->sk_rcvbuf = oldsk->sk_rcvbuf; 92861da177e4SLinus Torvalds /* Brute force copy old sctp opt. */ 92872d45a02dSMarcelo Ricardo Leitner sctp_copy_descendant(newsk, oldsk); 92881da177e4SLinus Torvalds 92891da177e4SLinus Torvalds /* Restore the ep value that was overwritten with the above structure 92901da177e4SLinus Torvalds * copy. 92911da177e4SLinus Torvalds */ 92921da177e4SLinus Torvalds newsp->ep = newep; 92931da177e4SLinus Torvalds newsp->hmac = NULL; 92941da177e4SLinus Torvalds 92951da177e4SLinus Torvalds /* Hook this new socket in to the bind_hash list. */ 9296f1f43763SEric W. Biederman head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk), 9297f1f43763SEric W. Biederman inet_sk(oldsk)->inet_num)]; 9298489ce5f4SNicholas Mc Guire spin_lock_bh(&head->lock); 92991da177e4SLinus Torvalds pp = sctp_sk(oldsk)->bind_hash; 93001da177e4SLinus Torvalds sk_add_bind_node(newsk, &pp->owner); 93011da177e4SLinus Torvalds sctp_sk(newsk)->bind_hash = pp; 9302c720c7e8SEric Dumazet inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num; 9303489ce5f4SNicholas Mc Guire spin_unlock_bh(&head->lock); 93041da177e4SLinus Torvalds 93054243cac1SVladislav Yasevich /* Copy the bind_addr list from the original endpoint to the new 93064243cac1SVladislav Yasevich * endpoint so that we can handle restarts properly 93074243cac1SVladislav Yasevich */ 930889664c62SXin Long err = sctp_bind_addr_dup(&newsp->ep->base.bind_addr, 93098e71a11cSVlad Yasevich &oldsp->ep->base.bind_addr, GFP_KERNEL); 931089664c62SXin Long if (err) 931189664c62SXin Long return err; 93124243cac1SVladislav Yasevich 9313c6f33e05SXin Long /* New ep's auth_hmacs should be set if old ep's is set, in case 9314c6f33e05SXin Long * that net->sctp.auth_enable has been changed to 0 by users and 9315c6f33e05SXin Long * new ep's auth_hmacs couldn't be set in sctp_endpoint_init(). 9316c6f33e05SXin Long */ 9317c6f33e05SXin Long if (oldsp->ep->auth_hmacs) { 9318c6f33e05SXin Long err = sctp_auth_init_hmacs(newsp->ep, GFP_KERNEL); 9319c6f33e05SXin Long if (err) 9320c6f33e05SXin Long return err; 9321c6f33e05SXin Long } 9322c6f33e05SXin Long 93231da177e4SLinus Torvalds /* Move any messages in the old socket's receive queue that are for the 93241da177e4SLinus Torvalds * peeled off association to the new socket's receive queue. 93251da177e4SLinus Torvalds */ 93261da177e4SLinus Torvalds sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { 93271da177e4SLinus Torvalds event = sctp_skb2event(skb); 93281da177e4SLinus Torvalds if (event->asoc == assoc) { 93298728b834SDavid S. Miller __skb_unlink(skb, &oldsk->sk_receive_queue); 93301da177e4SLinus Torvalds __skb_queue_tail(&newsk->sk_receive_queue, skb); 9331ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 93321da177e4SLinus Torvalds } 93331da177e4SLinus Torvalds } 93341da177e4SLinus Torvalds 93351da177e4SLinus Torvalds /* Clean up any messages pending delivery due to partial 93361da177e4SLinus Torvalds * delivery. Three cases: 93371da177e4SLinus Torvalds * 1) No partial deliver; no work. 93381da177e4SLinus Torvalds * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby. 93391da177e4SLinus Torvalds * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue. 93401da177e4SLinus Torvalds */ 9341b6e1331fSVlad Yasevich atomic_set(&sctp_sk(newsk)->pd_mode, assoc->ulpq.pd_mode); 93421da177e4SLinus Torvalds 9343b6e1331fSVlad Yasevich if (atomic_read(&sctp_sk(oldsk)->pd_mode)) { 93441da177e4SLinus Torvalds struct sk_buff_head *queue; 93451da177e4SLinus Torvalds 93461da177e4SLinus Torvalds /* Decide which queue to move pd_lobby skbs to. */ 93471da177e4SLinus Torvalds if (assoc->ulpq.pd_mode) { 93481da177e4SLinus Torvalds queue = &newsp->pd_lobby; 93491da177e4SLinus Torvalds } else 93501da177e4SLinus Torvalds queue = &newsk->sk_receive_queue; 93511da177e4SLinus Torvalds 93521da177e4SLinus Torvalds /* Walk through the pd_lobby, looking for skbs that 93531da177e4SLinus Torvalds * need moved to the new socket. 93541da177e4SLinus Torvalds */ 93551da177e4SLinus Torvalds sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { 93561da177e4SLinus Torvalds event = sctp_skb2event(skb); 93571da177e4SLinus Torvalds if (event->asoc == assoc) { 93588728b834SDavid S. Miller __skb_unlink(skb, &oldsp->pd_lobby); 93591da177e4SLinus Torvalds __skb_queue_tail(queue, skb); 9360ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 93611da177e4SLinus Torvalds } 93621da177e4SLinus Torvalds } 93631da177e4SLinus Torvalds 93641da177e4SLinus Torvalds /* Clear up any skbs waiting for the partial 93651da177e4SLinus Torvalds * delivery to finish. 93661da177e4SLinus Torvalds */ 93671da177e4SLinus Torvalds if (assoc->ulpq.pd_mode) 9368b6e1331fSVlad Yasevich sctp_clear_pd(oldsk, NULL); 93691da177e4SLinus Torvalds 93701da177e4SLinus Torvalds } 93711da177e4SLinus Torvalds 937213228238SXin Long sctp_for_each_rx_skb(assoc, newsk, sctp_skb_set_owner_r_frag); 9373ea2bc483STsutomu Fujii 93741da177e4SLinus Torvalds /* Set the type of socket to indicate that it is peeled off from the 93751da177e4SLinus Torvalds * original UDP-style socket or created with the accept() call on a 93761da177e4SLinus Torvalds * TCP-style socket.. 93771da177e4SLinus Torvalds */ 93781da177e4SLinus Torvalds newsp->type = type; 93791da177e4SLinus Torvalds 938061c9fed4SVladislav Yasevich /* Mark the new socket "in-use" by the user so that any packets 938161c9fed4SVladislav Yasevich * that may arrive on the association after we've moved it are 938261c9fed4SVladislav Yasevich * queued to the backlog. This prevents a potential race between 938361c9fed4SVladislav Yasevich * backlog processing on the old socket and new-packet processing 938461c9fed4SVladislav Yasevich * on the new socket. 93855131a184SZach Brown * 93865131a184SZach Brown * The caller has just allocated newsk so we can guarantee that other 93875131a184SZach Brown * paths won't try to lock it and then oldsk. 938861c9fed4SVladislav Yasevich */ 93895131a184SZach Brown lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); 93905c3e82feSQiujun Huang sctp_for_each_tx_datachunk(assoc, true, sctp_clear_owner_w); 93911da177e4SLinus Torvalds sctp_assoc_migrate(assoc, newsk); 93925c3e82feSQiujun Huang sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w); 93931da177e4SLinus Torvalds 93941da177e4SLinus Torvalds /* If the association on the newsk is already closed before accept() 93951da177e4SLinus Torvalds * is called, set RCV_SHUTDOWN flag. 93961da177e4SLinus Torvalds */ 9397d46e416cSXin Long if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) { 9398cbabf463SYafang Shao inet_sk_set_state(newsk, SCTP_SS_CLOSED); 93991da177e4SLinus Torvalds newsk->sk_shutdown |= RCV_SHUTDOWN; 9400d46e416cSXin Long } else { 9401cbabf463SYafang Shao inet_sk_set_state(newsk, SCTP_SS_ESTABLISHED); 9402d46e416cSXin Long } 9403d46e416cSXin Long 9404048ed4b6Swangweidong release_sock(newsk); 940589664c62SXin Long 940689664c62SXin Long return 0; 94071da177e4SLinus Torvalds } 94081da177e4SLinus Torvalds 94094d93df0aSNeil Horman 94101da177e4SLinus Torvalds /* This proto struct describes the ULP interface for SCTP. */ 94111da177e4SLinus Torvalds struct proto sctp_prot = { 94121da177e4SLinus Torvalds .name = "SCTP", 94131da177e4SLinus Torvalds .owner = THIS_MODULE, 94141da177e4SLinus Torvalds .close = sctp_close, 94151da177e4SLinus Torvalds .disconnect = sctp_disconnect, 94161da177e4SLinus Torvalds .accept = sctp_accept, 94171da177e4SLinus Torvalds .ioctl = sctp_ioctl, 94181da177e4SLinus Torvalds .init = sctp_init_sock, 94191da177e4SLinus Torvalds .destroy = sctp_destroy_sock, 94201da177e4SLinus Torvalds .shutdown = sctp_shutdown, 94211da177e4SLinus Torvalds .setsockopt = sctp_setsockopt, 94221da177e4SLinus Torvalds .getsockopt = sctp_getsockopt, 94231da177e4SLinus Torvalds .sendmsg = sctp_sendmsg, 94241da177e4SLinus Torvalds .recvmsg = sctp_recvmsg, 94251da177e4SLinus Torvalds .bind = sctp_bind, 9426c0425a42SChristoph Hellwig .bind_add = sctp_bind_add, 94271da177e4SLinus Torvalds .backlog_rcv = sctp_backlog_rcv, 94281da177e4SLinus Torvalds .hash = sctp_hash, 94291da177e4SLinus Torvalds .unhash = sctp_unhash, 943063dfb793SXin Long .no_autobind = true, 94311da177e4SLinus Torvalds .obj_size = sizeof(struct sctp_sock), 9432ab9ee8e3SDavid Windsor .useroffset = offsetof(struct sctp_sock, subscribe), 9433ab9ee8e3SDavid Windsor .usersize = offsetof(struct sctp_sock, initmsg) - 9434ab9ee8e3SDavid Windsor offsetof(struct sctp_sock, subscribe) + 9435ab9ee8e3SDavid Windsor sizeof_field(struct sctp_sock, initmsg), 94364d93df0aSNeil Horman .sysctl_mem = sysctl_sctp_mem, 94374d93df0aSNeil Horman .sysctl_rmem = sysctl_sctp_rmem, 94384d93df0aSNeil Horman .sysctl_wmem = sysctl_sctp_wmem, 94394d93df0aSNeil Horman .memory_pressure = &sctp_memory_pressure, 94404d93df0aSNeil Horman .enter_memory_pressure = sctp_enter_memory_pressure, 94414d93df0aSNeil Horman .memory_allocated = &sctp_memory_allocated, 94425f31886fSPavel Emelyanov .sockets_allocated = &sctp_sockets_allocated, 94431da177e4SLinus Torvalds }; 94441da177e4SLinus Torvalds 9445dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 94468295b6d9SEric Dumazet 9447602dd62dSEric Dumazet #include <net/transp_v6.h> 9448602dd62dSEric Dumazet static void sctp_v6_destroy_sock(struct sock *sk) 9449602dd62dSEric Dumazet { 9450602dd62dSEric Dumazet sctp_destroy_sock(sk); 9451602dd62dSEric Dumazet inet6_destroy_sock(sk); 9452602dd62dSEric Dumazet } 9453602dd62dSEric Dumazet 94541da177e4SLinus Torvalds struct proto sctpv6_prot = { 94551da177e4SLinus Torvalds .name = "SCTPv6", 94561da177e4SLinus Torvalds .owner = THIS_MODULE, 94571da177e4SLinus Torvalds .close = sctp_close, 94581da177e4SLinus Torvalds .disconnect = sctp_disconnect, 94591da177e4SLinus Torvalds .accept = sctp_accept, 94601da177e4SLinus Torvalds .ioctl = sctp_ioctl, 94611da177e4SLinus Torvalds .init = sctp_init_sock, 9462602dd62dSEric Dumazet .destroy = sctp_v6_destroy_sock, 94631da177e4SLinus Torvalds .shutdown = sctp_shutdown, 94641da177e4SLinus Torvalds .setsockopt = sctp_setsockopt, 94651da177e4SLinus Torvalds .getsockopt = sctp_getsockopt, 94661da177e4SLinus Torvalds .sendmsg = sctp_sendmsg, 94671da177e4SLinus Torvalds .recvmsg = sctp_recvmsg, 94681da177e4SLinus Torvalds .bind = sctp_bind, 9469c0425a42SChristoph Hellwig .bind_add = sctp_bind_add, 94701da177e4SLinus Torvalds .backlog_rcv = sctp_backlog_rcv, 94711da177e4SLinus Torvalds .hash = sctp_hash, 94721da177e4SLinus Torvalds .unhash = sctp_unhash, 947363dfb793SXin Long .no_autobind = true, 94741da177e4SLinus Torvalds .obj_size = sizeof(struct sctp6_sock), 9475ab9ee8e3SDavid Windsor .useroffset = offsetof(struct sctp6_sock, sctp.subscribe), 9476ab9ee8e3SDavid Windsor .usersize = offsetof(struct sctp6_sock, sctp.initmsg) - 9477ab9ee8e3SDavid Windsor offsetof(struct sctp6_sock, sctp.subscribe) + 9478ab9ee8e3SDavid Windsor sizeof_field(struct sctp6_sock, sctp.initmsg), 94794d93df0aSNeil Horman .sysctl_mem = sysctl_sctp_mem, 94804d93df0aSNeil Horman .sysctl_rmem = sysctl_sctp_rmem, 94814d93df0aSNeil Horman .sysctl_wmem = sysctl_sctp_wmem, 94824d93df0aSNeil Horman .memory_pressure = &sctp_memory_pressure, 94834d93df0aSNeil Horman .enter_memory_pressure = sctp_enter_memory_pressure, 94844d93df0aSNeil Horman .memory_allocated = &sctp_memory_allocated, 94855f31886fSPavel Emelyanov .sockets_allocated = &sctp_sockets_allocated, 94861da177e4SLinus Torvalds }; 9487dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */ 9488