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 */ 2245*0b49a65cSChristoph 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 2257*0b49a65cSChristoph 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, 2592b7058842SDavid S. Miller char __user *optval, 2593b7058842SDavid S. Miller unsigned int optlen) 25941da177e4SLinus Torvalds { 25951da177e4SLinus Torvalds struct sctp_paddrparams params; 259652ccb8e9SFrank Filz struct sctp_transport *trans = NULL; 259752ccb8e9SFrank Filz struct sctp_association *asoc = NULL; 259852ccb8e9SFrank Filz struct sctp_sock *sp = sctp_sk(sk); 25991da177e4SLinus Torvalds int error; 260052ccb8e9SFrank Filz int hb_change, pmtud_change, sackdelay_change; 26011da177e4SLinus Torvalds 26020b0dce7aSXin Long if (optlen == sizeof(params)) { 26031da177e4SLinus Torvalds if (copy_from_user(¶ms, optval, optlen)) 26041da177e4SLinus Torvalds return -EFAULT; 26050b0dce7aSXin Long } else if (optlen == ALIGN(offsetof(struct sctp_paddrparams, 26060b0dce7aSXin Long spp_ipv6_flowlabel), 4)) { 26070b0dce7aSXin Long if (copy_from_user(¶ms, optval, optlen)) 26080b0dce7aSXin Long return -EFAULT; 26090b0dce7aSXin Long if (params.spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL)) 26100b0dce7aSXin Long return -EINVAL; 26110b0dce7aSXin Long } else { 26120b0dce7aSXin Long return -EINVAL; 26130b0dce7aSXin Long } 26141da177e4SLinus Torvalds 261552ccb8e9SFrank Filz /* Validate flags and value parameters. */ 261652ccb8e9SFrank Filz hb_change = params.spp_flags & SPP_HB; 261752ccb8e9SFrank Filz pmtud_change = params.spp_flags & SPP_PMTUD; 261852ccb8e9SFrank Filz sackdelay_change = params.spp_flags & SPP_SACKDELAY; 26191da177e4SLinus Torvalds 262052ccb8e9SFrank Filz if (hb_change == SPP_HB || 262152ccb8e9SFrank Filz pmtud_change == SPP_PMTUD || 262252ccb8e9SFrank Filz sackdelay_change == SPP_SACKDELAY || 262352ccb8e9SFrank Filz params.spp_sackdelay > 500 || 2624f64f9e71SJoe Perches (params.spp_pathmtu && 2625f64f9e71SJoe Perches params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT)) 26261da177e4SLinus Torvalds return -EINVAL; 26271da177e4SLinus Torvalds 262852ccb8e9SFrank Filz /* If an address other than INADDR_ANY is specified, and 262952ccb8e9SFrank Filz * no transport is found, then the request is invalid. 263052ccb8e9SFrank Filz */ 263152cae8f0SVlad Yasevich if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { 26321da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, ¶ms.spp_address, 26331da177e4SLinus Torvalds params.spp_assoc_id); 26341da177e4SLinus Torvalds if (!trans) 26351da177e4SLinus Torvalds return -EINVAL; 26361da177e4SLinus Torvalds } 26371da177e4SLinus Torvalds 2638b99e5e02SXin Long /* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the 2639b99e5e02SXin Long * socket is a one to many style socket, and an association 2640b99e5e02SXin Long * was not found, then the id was invalid. 26411da177e4SLinus Torvalds */ 264252ccb8e9SFrank Filz asoc = sctp_id2assoc(sk, params.spp_assoc_id); 2643b99e5e02SXin Long if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC && 2644b99e5e02SXin Long sctp_style(sk, UDP)) 264552ccb8e9SFrank Filz return -EINVAL; 264652ccb8e9SFrank Filz 264752ccb8e9SFrank Filz /* Heartbeat demand can only be sent on a transport or 264852ccb8e9SFrank Filz * association, but not a socket. 264952ccb8e9SFrank Filz */ 265052ccb8e9SFrank Filz if (params.spp_flags & SPP_HB_DEMAND && !trans && !asoc) 265152ccb8e9SFrank Filz return -EINVAL; 265252ccb8e9SFrank Filz 265352ccb8e9SFrank Filz /* Process parameters. */ 265452ccb8e9SFrank Filz error = sctp_apply_peer_addr_params(¶ms, trans, asoc, sp, 265552ccb8e9SFrank Filz hb_change, pmtud_change, 265652ccb8e9SFrank Filz sackdelay_change); 265752ccb8e9SFrank Filz 265852ccb8e9SFrank Filz if (error) 265952ccb8e9SFrank Filz return error; 266052ccb8e9SFrank Filz 266152ccb8e9SFrank Filz /* If changes are for association, also apply parameters to each 266252ccb8e9SFrank Filz * transport. 266352ccb8e9SFrank Filz */ 266452ccb8e9SFrank Filz if (!trans && asoc) { 26659dbc15f0SRobert P. J. Day list_for_each_entry(trans, &asoc->peer.transport_addr_list, 26669dbc15f0SRobert P. J. Day transports) { 266752ccb8e9SFrank Filz sctp_apply_peer_addr_params(¶ms, trans, asoc, sp, 266852ccb8e9SFrank Filz hb_change, pmtud_change, 266952ccb8e9SFrank Filz sackdelay_change); 267052ccb8e9SFrank Filz } 267152ccb8e9SFrank Filz } 26721da177e4SLinus Torvalds 26731da177e4SLinus Torvalds return 0; 26741da177e4SLinus Torvalds } 26751da177e4SLinus Torvalds 26760ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags) 26770ea5e4dfSwangweidong { 26780ea5e4dfSwangweidong return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; 26790ea5e4dfSwangweidong } 26800ea5e4dfSwangweidong 26810ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags) 26820ea5e4dfSwangweidong { 26830ea5e4dfSwangweidong return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; 26840ea5e4dfSwangweidong } 26850ea5e4dfSwangweidong 26869c5829e1SXin Long static void sctp_apply_asoc_delayed_ack(struct sctp_sack_info *params, 26879c5829e1SXin Long struct sctp_association *asoc) 26889c5829e1SXin Long { 26899c5829e1SXin Long struct sctp_transport *trans; 26909c5829e1SXin Long 26919c5829e1SXin Long if (params->sack_delay) { 26929c5829e1SXin Long asoc->sackdelay = msecs_to_jiffies(params->sack_delay); 26939c5829e1SXin Long asoc->param_flags = 26949c5829e1SXin Long sctp_spp_sackdelay_enable(asoc->param_flags); 26959c5829e1SXin Long } 26969c5829e1SXin Long if (params->sack_freq == 1) { 26979c5829e1SXin Long asoc->param_flags = 26989c5829e1SXin Long sctp_spp_sackdelay_disable(asoc->param_flags); 26999c5829e1SXin Long } else if (params->sack_freq > 1) { 27009c5829e1SXin Long asoc->sackfreq = params->sack_freq; 27019c5829e1SXin Long asoc->param_flags = 27029c5829e1SXin Long sctp_spp_sackdelay_enable(asoc->param_flags); 27039c5829e1SXin Long } 27049c5829e1SXin Long 27059c5829e1SXin Long list_for_each_entry(trans, &asoc->peer.transport_addr_list, 27069c5829e1SXin Long transports) { 27079c5829e1SXin Long if (params->sack_delay) { 27089c5829e1SXin Long trans->sackdelay = msecs_to_jiffies(params->sack_delay); 27099c5829e1SXin Long trans->param_flags = 27109c5829e1SXin Long sctp_spp_sackdelay_enable(trans->param_flags); 27119c5829e1SXin Long } 27129c5829e1SXin Long if (params->sack_freq == 1) { 27139c5829e1SXin Long trans->param_flags = 27149c5829e1SXin Long sctp_spp_sackdelay_disable(trans->param_flags); 27159c5829e1SXin Long } else if (params->sack_freq > 1) { 27169c5829e1SXin Long trans->sackfreq = params->sack_freq; 27179c5829e1SXin Long trans->param_flags = 27189c5829e1SXin Long sctp_spp_sackdelay_enable(trans->param_flags); 27199c5829e1SXin Long } 27209c5829e1SXin Long } 27219c5829e1SXin Long } 27229c5829e1SXin Long 2723d364d927SWei Yongjun /* 2724d364d927SWei Yongjun * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 27257708610bSFrank Filz * 2726d364d927SWei Yongjun * This option will effect the way delayed acks are performed. This 2727d364d927SWei Yongjun * option allows you to get or set the delayed ack time, in 2728d364d927SWei Yongjun * milliseconds. It also allows changing the delayed ack frequency. 2729d364d927SWei Yongjun * Changing the frequency to 1 disables the delayed sack algorithm. If 2730d364d927SWei Yongjun * the assoc_id is 0, then this sets or gets the endpoints default 2731d364d927SWei Yongjun * values. If the assoc_id field is non-zero, then the set or get 2732d364d927SWei Yongjun * effects the specified association for the one to many model (the 2733d364d927SWei Yongjun * assoc_id field is ignored by the one to one model). Note that if 2734d364d927SWei Yongjun * sack_delay or sack_freq are 0 when setting this option, then the 2735d364d927SWei Yongjun * current values will remain unchanged. 27367708610bSFrank Filz * 2737d364d927SWei Yongjun * struct sctp_sack_info { 2738d364d927SWei Yongjun * sctp_assoc_t sack_assoc_id; 2739d364d927SWei Yongjun * uint32_t sack_delay; 2740d364d927SWei Yongjun * uint32_t sack_freq; 27417708610bSFrank Filz * }; 27427708610bSFrank Filz * 2743d364d927SWei Yongjun * sack_assoc_id - This parameter, indicates which association the user 2744d364d927SWei Yongjun * is performing an action upon. Note that if this field's value is 2745d364d927SWei Yongjun * zero then the endpoints default value is changed (effecting future 27467708610bSFrank Filz * associations only). 27477708610bSFrank Filz * 2748d364d927SWei Yongjun * sack_delay - This parameter contains the number of milliseconds that 2749d364d927SWei Yongjun * the user is requesting the delayed ACK timer be set to. Note that 2750d364d927SWei Yongjun * this value is defined in the standard to be between 200 and 500 2751d364d927SWei Yongjun * milliseconds. 27527708610bSFrank Filz * 2753d364d927SWei Yongjun * sack_freq - This parameter contains the number of packets that must 2754d364d927SWei Yongjun * be received before a sack is sent without waiting for the delay 2755d364d927SWei Yongjun * timer to expire. The default value for this is 2, setting this 2756d364d927SWei Yongjun * value to 1 will disable the delayed sack algorithm. 27577708610bSFrank Filz */ 27587708610bSFrank Filz 2759d364d927SWei Yongjun static int sctp_setsockopt_delayed_ack(struct sock *sk, 2760b7058842SDavid S. Miller char __user *optval, unsigned int optlen) 27617708610bSFrank Filz { 27627708610bSFrank Filz struct sctp_sock *sp = sctp_sk(sk); 27639c5829e1SXin Long struct sctp_association *asoc; 27649c5829e1SXin Long struct sctp_sack_info params; 27657708610bSFrank Filz 2766d364d927SWei Yongjun if (optlen == sizeof(struct sctp_sack_info)) { 27677708610bSFrank Filz if (copy_from_user(¶ms, optval, optlen)) 27687708610bSFrank Filz return -EFAULT; 27697708610bSFrank Filz 2770d364d927SWei Yongjun if (params.sack_delay == 0 && params.sack_freq == 0) 2771d364d927SWei Yongjun return 0; 2772d364d927SWei Yongjun } else if (optlen == sizeof(struct sctp_assoc_value)) { 277394f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 2774f916ec96SNeil Horman "%s (pid %d) " 277594f65193SNeil Horman "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 2776f916ec96SNeil Horman "Use struct sctp_sack_info instead\n", 2777f916ec96SNeil Horman current->comm, task_pid_nr(current)); 2778d364d927SWei Yongjun if (copy_from_user(¶ms, optval, optlen)) 2779d364d927SWei Yongjun return -EFAULT; 2780d364d927SWei Yongjun 2781d364d927SWei Yongjun if (params.sack_delay == 0) 2782d364d927SWei Yongjun params.sack_freq = 1; 2783d364d927SWei Yongjun else 2784d364d927SWei Yongjun params.sack_freq = 0; 2785d364d927SWei Yongjun } else 27867708610bSFrank Filz return -EINVAL; 27877708610bSFrank Filz 2788d364d927SWei Yongjun /* Validate value parameter. */ 2789d364d927SWei Yongjun if (params.sack_delay > 500) 2790d364d927SWei Yongjun return -EINVAL; 2791d364d927SWei Yongjun 27929c5829e1SXin Long /* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the 27939c5829e1SXin Long * socket is a one to many style socket, and an association 27949c5829e1SXin Long * was not found, then the id was invalid. 27957708610bSFrank Filz */ 2796d364d927SWei Yongjun asoc = sctp_id2assoc(sk, params.sack_assoc_id); 27979c5829e1SXin Long if (!asoc && params.sack_assoc_id > SCTP_ALL_ASSOC && 27989c5829e1SXin Long sctp_style(sk, UDP)) 27997708610bSFrank Filz return -EINVAL; 28007708610bSFrank Filz 28017708610bSFrank Filz if (asoc) { 28029c5829e1SXin Long sctp_apply_asoc_delayed_ack(¶ms, asoc); 28039c5829e1SXin Long 28049c5829e1SXin Long return 0; 28059c5829e1SXin Long } 28069c5829e1SXin Long 28078e2614fcSXin Long if (sctp_style(sk, TCP)) 28088e2614fcSXin Long params.sack_assoc_id = SCTP_FUTURE_ASSOC; 28098e2614fcSXin Long 28109c5829e1SXin Long if (params.sack_assoc_id == SCTP_FUTURE_ASSOC || 28119c5829e1SXin Long params.sack_assoc_id == SCTP_ALL_ASSOC) { 28129c5829e1SXin Long if (params.sack_delay) { 2813d364d927SWei Yongjun sp->sackdelay = params.sack_delay; 28147708610bSFrank Filz sp->param_flags = 28150ea5e4dfSwangweidong sctp_spp_sackdelay_enable(sp->param_flags); 28167708610bSFrank Filz } 2817d364d927SWei Yongjun if (params.sack_freq == 1) { 28187708610bSFrank Filz sp->param_flags = 28190ea5e4dfSwangweidong sctp_spp_sackdelay_disable(sp->param_flags); 2820d364d927SWei Yongjun } else if (params.sack_freq > 1) { 2821d364d927SWei Yongjun sp->sackfreq = params.sack_freq; 2822d364d927SWei Yongjun sp->param_flags = 28230ea5e4dfSwangweidong sctp_spp_sackdelay_enable(sp->param_flags); 2824d364d927SWei Yongjun } 28257708610bSFrank Filz } 28267708610bSFrank Filz 28279c5829e1SXin Long if (params.sack_assoc_id == SCTP_CURRENT_ASSOC || 28289c5829e1SXin Long params.sack_assoc_id == SCTP_ALL_ASSOC) 28299c5829e1SXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) 28309c5829e1SXin Long sctp_apply_asoc_delayed_ack(¶ms, asoc); 28317708610bSFrank Filz 28327708610bSFrank Filz return 0; 28337708610bSFrank Filz } 28347708610bSFrank Filz 28351da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG) 28361da177e4SLinus Torvalds * 28371da177e4SLinus Torvalds * Applications can specify protocol parameters for the default association 28381da177e4SLinus Torvalds * initialization. The option name argument to setsockopt() and getsockopt() 28391da177e4SLinus Torvalds * is SCTP_INITMSG. 28401da177e4SLinus Torvalds * 28411da177e4SLinus Torvalds * Setting initialization parameters is effective only on an unconnected 28421da177e4SLinus Torvalds * socket (for UDP-style sockets only future associations are effected 28431da177e4SLinus Torvalds * by the change). With TCP-style sockets, this option is inherited by 28441da177e4SLinus Torvalds * sockets derived from a listener socket. 28451da177e4SLinus Torvalds */ 2846b7058842SDavid S. Miller static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen) 28471da177e4SLinus Torvalds { 28481da177e4SLinus Torvalds struct sctp_initmsg sinit; 28491da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 28501da177e4SLinus Torvalds 28511da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_initmsg)) 28521da177e4SLinus Torvalds return -EINVAL; 28531da177e4SLinus Torvalds if (copy_from_user(&sinit, optval, optlen)) 28541da177e4SLinus Torvalds return -EFAULT; 28551da177e4SLinus Torvalds 28561da177e4SLinus Torvalds if (sinit.sinit_num_ostreams) 28571da177e4SLinus Torvalds sp->initmsg.sinit_num_ostreams = sinit.sinit_num_ostreams; 28581da177e4SLinus Torvalds if (sinit.sinit_max_instreams) 28591da177e4SLinus Torvalds sp->initmsg.sinit_max_instreams = sinit.sinit_max_instreams; 28601da177e4SLinus Torvalds if (sinit.sinit_max_attempts) 28611da177e4SLinus Torvalds sp->initmsg.sinit_max_attempts = sinit.sinit_max_attempts; 28621da177e4SLinus Torvalds if (sinit.sinit_max_init_timeo) 28631da177e4SLinus Torvalds sp->initmsg.sinit_max_init_timeo = sinit.sinit_max_init_timeo; 28641da177e4SLinus Torvalds 28651da177e4SLinus Torvalds return 0; 28661da177e4SLinus Torvalds } 28671da177e4SLinus Torvalds 28681da177e4SLinus Torvalds /* 28691da177e4SLinus Torvalds * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 28701da177e4SLinus Torvalds * 28711da177e4SLinus Torvalds * Applications that wish to use the sendto() system call may wish to 28721da177e4SLinus Torvalds * specify a default set of parameters that would normally be supplied 28731da177e4SLinus Torvalds * through the inclusion of ancillary data. This socket option allows 28741da177e4SLinus Torvalds * such an application to set the default sctp_sndrcvinfo structure. 28751da177e4SLinus Torvalds * The application that wishes to use this socket option simply passes 28761da177e4SLinus Torvalds * in to this call the sctp_sndrcvinfo structure defined in Section 28771da177e4SLinus Torvalds * 5.2.2) The input parameters accepted by this call include 28781da177e4SLinus Torvalds * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 28791da177e4SLinus Torvalds * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 28801da177e4SLinus Torvalds * to this call if the caller is using the UDP model. 28811da177e4SLinus Torvalds */ 28821da177e4SLinus Torvalds static int sctp_setsockopt_default_send_param(struct sock *sk, 2883b7058842SDavid S. Miller char __user *optval, 2884b7058842SDavid S. Miller unsigned int optlen) 28851da177e4SLinus Torvalds { 28861da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 28876b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 28886b3fd5f3SGeir Ola Vaagland struct sctp_sndrcvinfo info; 28891da177e4SLinus Torvalds 28906b3fd5f3SGeir Ola Vaagland if (optlen != sizeof(info)) 28911da177e4SLinus Torvalds return -EINVAL; 28921da177e4SLinus Torvalds if (copy_from_user(&info, optval, optlen)) 28931da177e4SLinus Torvalds return -EFAULT; 28946b3fd5f3SGeir Ola Vaagland if (info.sinfo_flags & 28956b3fd5f3SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 28966b3fd5f3SGeir Ola Vaagland SCTP_ABORT | SCTP_EOF)) 28976b3fd5f3SGeir Ola Vaagland return -EINVAL; 28981da177e4SLinus Torvalds 28991da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); 2900707e45b3SXin Long if (!asoc && info.sinfo_assoc_id > SCTP_ALL_ASSOC && 2901707e45b3SXin Long sctp_style(sk, UDP)) 29021da177e4SLinus Torvalds return -EINVAL; 2903707e45b3SXin Long 29041da177e4SLinus Torvalds if (asoc) { 29051da177e4SLinus Torvalds asoc->default_stream = info.sinfo_stream; 29061da177e4SLinus Torvalds asoc->default_flags = info.sinfo_flags; 29071da177e4SLinus Torvalds asoc->default_ppid = info.sinfo_ppid; 29081da177e4SLinus Torvalds asoc->default_context = info.sinfo_context; 29091da177e4SLinus Torvalds asoc->default_timetolive = info.sinfo_timetolive; 2910707e45b3SXin Long 2911707e45b3SXin Long return 0; 2912707e45b3SXin Long } 2913707e45b3SXin Long 29141354e72fSMarcelo Ricardo Leitner if (sctp_style(sk, TCP)) 29151354e72fSMarcelo Ricardo Leitner info.sinfo_assoc_id = SCTP_FUTURE_ASSOC; 29161354e72fSMarcelo Ricardo Leitner 2917707e45b3SXin Long if (info.sinfo_assoc_id == SCTP_FUTURE_ASSOC || 2918707e45b3SXin Long info.sinfo_assoc_id == SCTP_ALL_ASSOC) { 29191da177e4SLinus Torvalds sp->default_stream = info.sinfo_stream; 29201da177e4SLinus Torvalds sp->default_flags = info.sinfo_flags; 29211da177e4SLinus Torvalds sp->default_ppid = info.sinfo_ppid; 29221da177e4SLinus Torvalds sp->default_context = info.sinfo_context; 29231da177e4SLinus Torvalds sp->default_timetolive = info.sinfo_timetolive; 29241da177e4SLinus Torvalds } 29251da177e4SLinus Torvalds 2926707e45b3SXin Long if (info.sinfo_assoc_id == SCTP_CURRENT_ASSOC || 2927707e45b3SXin Long info.sinfo_assoc_id == SCTP_ALL_ASSOC) { 2928707e45b3SXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 2929707e45b3SXin Long asoc->default_stream = info.sinfo_stream; 2930707e45b3SXin Long asoc->default_flags = info.sinfo_flags; 2931707e45b3SXin Long asoc->default_ppid = info.sinfo_ppid; 2932707e45b3SXin Long asoc->default_context = info.sinfo_context; 2933707e45b3SXin Long asoc->default_timetolive = info.sinfo_timetolive; 2934707e45b3SXin Long } 2935707e45b3SXin Long } 2936707e45b3SXin Long 29371da177e4SLinus Torvalds return 0; 29381da177e4SLinus Torvalds } 29391da177e4SLinus Torvalds 29406b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters 29416b3fd5f3SGeir Ola Vaagland * (SCTP_DEFAULT_SNDINFO) 29426b3fd5f3SGeir Ola Vaagland */ 29436b3fd5f3SGeir Ola Vaagland static int sctp_setsockopt_default_sndinfo(struct sock *sk, 29446b3fd5f3SGeir Ola Vaagland char __user *optval, 29456b3fd5f3SGeir Ola Vaagland unsigned int optlen) 29466b3fd5f3SGeir Ola Vaagland { 29476b3fd5f3SGeir Ola Vaagland struct sctp_sock *sp = sctp_sk(sk); 29486b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 29496b3fd5f3SGeir Ola Vaagland struct sctp_sndinfo info; 29506b3fd5f3SGeir Ola Vaagland 29516b3fd5f3SGeir Ola Vaagland if (optlen != sizeof(info)) 29526b3fd5f3SGeir Ola Vaagland return -EINVAL; 29536b3fd5f3SGeir Ola Vaagland if (copy_from_user(&info, optval, optlen)) 29546b3fd5f3SGeir Ola Vaagland return -EFAULT; 29556b3fd5f3SGeir Ola Vaagland if (info.snd_flags & 29566b3fd5f3SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 29576b3fd5f3SGeir Ola Vaagland SCTP_ABORT | SCTP_EOF)) 29586b3fd5f3SGeir Ola Vaagland return -EINVAL; 29596b3fd5f3SGeir Ola Vaagland 29606b3fd5f3SGeir Ola Vaagland asoc = sctp_id2assoc(sk, info.snd_assoc_id); 296192fc3bd9SXin Long if (!asoc && info.snd_assoc_id > SCTP_ALL_ASSOC && 296292fc3bd9SXin Long sctp_style(sk, UDP)) 29636b3fd5f3SGeir Ola Vaagland return -EINVAL; 296492fc3bd9SXin Long 29656b3fd5f3SGeir Ola Vaagland if (asoc) { 29666b3fd5f3SGeir Ola Vaagland asoc->default_stream = info.snd_sid; 29676b3fd5f3SGeir Ola Vaagland asoc->default_flags = info.snd_flags; 29686b3fd5f3SGeir Ola Vaagland asoc->default_ppid = info.snd_ppid; 29696b3fd5f3SGeir Ola Vaagland asoc->default_context = info.snd_context; 297092fc3bd9SXin Long 297192fc3bd9SXin Long return 0; 297292fc3bd9SXin Long } 297392fc3bd9SXin Long 2974a842e65bSXin Long if (sctp_style(sk, TCP)) 2975a842e65bSXin Long info.snd_assoc_id = SCTP_FUTURE_ASSOC; 2976a842e65bSXin Long 297792fc3bd9SXin Long if (info.snd_assoc_id == SCTP_FUTURE_ASSOC || 297892fc3bd9SXin Long info.snd_assoc_id == SCTP_ALL_ASSOC) { 29796b3fd5f3SGeir Ola Vaagland sp->default_stream = info.snd_sid; 29806b3fd5f3SGeir Ola Vaagland sp->default_flags = info.snd_flags; 29816b3fd5f3SGeir Ola Vaagland sp->default_ppid = info.snd_ppid; 29826b3fd5f3SGeir Ola Vaagland sp->default_context = info.snd_context; 29836b3fd5f3SGeir Ola Vaagland } 29846b3fd5f3SGeir Ola Vaagland 298592fc3bd9SXin Long if (info.snd_assoc_id == SCTP_CURRENT_ASSOC || 298692fc3bd9SXin Long info.snd_assoc_id == SCTP_ALL_ASSOC) { 298792fc3bd9SXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 298892fc3bd9SXin Long asoc->default_stream = info.snd_sid; 298992fc3bd9SXin Long asoc->default_flags = info.snd_flags; 299092fc3bd9SXin Long asoc->default_ppid = info.snd_ppid; 299192fc3bd9SXin Long asoc->default_context = info.snd_context; 299292fc3bd9SXin Long } 299392fc3bd9SXin Long } 299492fc3bd9SXin Long 29956b3fd5f3SGeir Ola Vaagland return 0; 29966b3fd5f3SGeir Ola Vaagland } 29976b3fd5f3SGeir Ola Vaagland 29981da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 29991da177e4SLinus Torvalds * 30001da177e4SLinus Torvalds * Requests that the local SCTP stack use the enclosed peer address as 30011da177e4SLinus Torvalds * the association primary. The enclosed address must be one of the 30021da177e4SLinus Torvalds * association peer's addresses. 30031da177e4SLinus Torvalds */ 30041da177e4SLinus Torvalds static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, 3005b7058842SDavid S. Miller unsigned int optlen) 30061da177e4SLinus Torvalds { 30071da177e4SLinus Torvalds struct sctp_prim prim; 30081da177e4SLinus Torvalds struct sctp_transport *trans; 30092277c7cdSRichard Haines struct sctp_af *af; 30102277c7cdSRichard Haines int err; 30111da177e4SLinus Torvalds 30121da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_prim)) 30131da177e4SLinus Torvalds return -EINVAL; 30141da177e4SLinus Torvalds 30151da177e4SLinus Torvalds if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) 30161da177e4SLinus Torvalds return -EFAULT; 30171da177e4SLinus Torvalds 30182277c7cdSRichard Haines /* Allow security module to validate address but need address len. */ 30192277c7cdSRichard Haines af = sctp_get_af_specific(prim.ssp_addr.ss_family); 30202277c7cdSRichard Haines if (!af) 30212277c7cdSRichard Haines return -EINVAL; 30222277c7cdSRichard Haines 30232277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR, 30242277c7cdSRichard Haines (struct sockaddr *)&prim.ssp_addr, 30252277c7cdSRichard Haines af->sockaddr_len); 30262277c7cdSRichard Haines if (err) 30272277c7cdSRichard Haines return err; 30282277c7cdSRichard Haines 30291da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id); 30301da177e4SLinus Torvalds if (!trans) 30311da177e4SLinus Torvalds return -EINVAL; 30321da177e4SLinus Torvalds 30331da177e4SLinus Torvalds sctp_assoc_set_primary(trans->asoc, trans); 30341da177e4SLinus Torvalds 30351da177e4SLinus Torvalds return 0; 30361da177e4SLinus Torvalds } 30371da177e4SLinus Torvalds 30381da177e4SLinus Torvalds /* 30391da177e4SLinus Torvalds * 7.1.5 SCTP_NODELAY 30401da177e4SLinus Torvalds * 30411da177e4SLinus Torvalds * Turn on/off any Nagle-like algorithm. This means that packets are 30421da177e4SLinus Torvalds * generally sent as soon as possible and no unnecessary delays are 30431da177e4SLinus Torvalds * introduced, at the cost of more packets in the network. Expects an 30441da177e4SLinus Torvalds * integer boolean flag. 30451da177e4SLinus Torvalds */ 30461da177e4SLinus Torvalds static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval, 3047b7058842SDavid S. Miller unsigned int optlen) 30481da177e4SLinus Torvalds { 30491da177e4SLinus Torvalds int val; 30501da177e4SLinus Torvalds 30511da177e4SLinus Torvalds if (optlen < sizeof(int)) 30521da177e4SLinus Torvalds return -EINVAL; 30531da177e4SLinus Torvalds if (get_user(val, (int __user *)optval)) 30541da177e4SLinus Torvalds return -EFAULT; 30551da177e4SLinus Torvalds 30561da177e4SLinus Torvalds sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; 30571da177e4SLinus Torvalds return 0; 30581da177e4SLinus Torvalds } 30591da177e4SLinus Torvalds 30601da177e4SLinus Torvalds /* 30611da177e4SLinus Torvalds * 30621da177e4SLinus Torvalds * 7.1.1 SCTP_RTOINFO 30631da177e4SLinus Torvalds * 30641da177e4SLinus Torvalds * The protocol parameters used to initialize and bound retransmission 30651da177e4SLinus Torvalds * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 30661da177e4SLinus Torvalds * and modify these parameters. 30671da177e4SLinus Torvalds * All parameters are time values, in milliseconds. A value of 0, when 30681da177e4SLinus Torvalds * modifying the parameters, indicates that the current value should not 30691da177e4SLinus Torvalds * be changed. 30701da177e4SLinus Torvalds * 30711da177e4SLinus Torvalds */ 3072b7058842SDavid S. Miller static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen) 3073b7058842SDavid S. Miller { 30741da177e4SLinus Torvalds struct sctp_rtoinfo rtoinfo; 30751da177e4SLinus Torvalds struct sctp_association *asoc; 307685f935d4Swangweidong unsigned long rto_min, rto_max; 307785f935d4Swangweidong struct sctp_sock *sp = sctp_sk(sk); 30781da177e4SLinus Torvalds 30791da177e4SLinus Torvalds if (optlen != sizeof (struct sctp_rtoinfo)) 30801da177e4SLinus Torvalds return -EINVAL; 30811da177e4SLinus Torvalds 30821da177e4SLinus Torvalds if (copy_from_user(&rtoinfo, optval, optlen)) 30831da177e4SLinus Torvalds return -EFAULT; 30841da177e4SLinus Torvalds 30851da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); 30861da177e4SLinus Torvalds 30871da177e4SLinus Torvalds /* Set the values to the specific association */ 30887adb5ed5SXin Long if (!asoc && rtoinfo.srto_assoc_id != SCTP_FUTURE_ASSOC && 30897adb5ed5SXin Long sctp_style(sk, UDP)) 30901da177e4SLinus Torvalds return -EINVAL; 30911da177e4SLinus Torvalds 309285f935d4Swangweidong rto_max = rtoinfo.srto_max; 309385f935d4Swangweidong rto_min = rtoinfo.srto_min; 309485f935d4Swangweidong 309585f935d4Swangweidong if (rto_max) 309685f935d4Swangweidong rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max; 309785f935d4Swangweidong else 309885f935d4Swangweidong rto_max = asoc ? asoc->rto_max : sp->rtoinfo.srto_max; 309985f935d4Swangweidong 310085f935d4Swangweidong if (rto_min) 310185f935d4Swangweidong rto_min = asoc ? msecs_to_jiffies(rto_min) : rto_min; 310285f935d4Swangweidong else 310385f935d4Swangweidong rto_min = asoc ? asoc->rto_min : sp->rtoinfo.srto_min; 310485f935d4Swangweidong 310585f935d4Swangweidong if (rto_min > rto_max) 310685f935d4Swangweidong return -EINVAL; 310785f935d4Swangweidong 31081da177e4SLinus Torvalds if (asoc) { 31091da177e4SLinus Torvalds if (rtoinfo.srto_initial != 0) 31101da177e4SLinus Torvalds asoc->rto_initial = 31111da177e4SLinus Torvalds msecs_to_jiffies(rtoinfo.srto_initial); 311285f935d4Swangweidong asoc->rto_max = rto_max; 311385f935d4Swangweidong asoc->rto_min = rto_min; 31141da177e4SLinus Torvalds } else { 31151da177e4SLinus Torvalds /* If there is no association or the association-id = 0 31161da177e4SLinus Torvalds * set the values to the endpoint. 31171da177e4SLinus Torvalds */ 31181da177e4SLinus Torvalds if (rtoinfo.srto_initial != 0) 31191da177e4SLinus Torvalds sp->rtoinfo.srto_initial = rtoinfo.srto_initial; 312085f935d4Swangweidong sp->rtoinfo.srto_max = rto_max; 312185f935d4Swangweidong sp->rtoinfo.srto_min = rto_min; 31221da177e4SLinus Torvalds } 31231da177e4SLinus Torvalds 31241da177e4SLinus Torvalds return 0; 31251da177e4SLinus Torvalds } 31261da177e4SLinus Torvalds 31271da177e4SLinus Torvalds /* 31281da177e4SLinus Torvalds * 31291da177e4SLinus Torvalds * 7.1.2 SCTP_ASSOCINFO 31301da177e4SLinus Torvalds * 313159c51591SMichael Opdenacker * This option is used to tune the maximum retransmission attempts 31321da177e4SLinus Torvalds * of the association. 31331da177e4SLinus Torvalds * Returns an error if the new association retransmission value is 31341da177e4SLinus Torvalds * greater than the sum of the retransmission value of the peer. 31351da177e4SLinus Torvalds * See [SCTP] for more information. 31361da177e4SLinus Torvalds * 31371da177e4SLinus Torvalds */ 3138b7058842SDavid S. Miller static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen) 31391da177e4SLinus Torvalds { 31401da177e4SLinus Torvalds 31411da177e4SLinus Torvalds struct sctp_assocparams assocparams; 31421da177e4SLinus Torvalds struct sctp_association *asoc; 31431da177e4SLinus Torvalds 31441da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_assocparams)) 31451da177e4SLinus Torvalds return -EINVAL; 31461da177e4SLinus Torvalds if (copy_from_user(&assocparams, optval, optlen)) 31471da177e4SLinus Torvalds return -EFAULT; 31481da177e4SLinus Torvalds 31491da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); 31501da177e4SLinus Torvalds 31518889394dSXin Long if (!asoc && assocparams.sasoc_assoc_id != SCTP_FUTURE_ASSOC && 31528889394dSXin Long sctp_style(sk, UDP)) 31531da177e4SLinus Torvalds return -EINVAL; 31541da177e4SLinus Torvalds 31551da177e4SLinus Torvalds /* Set the values to the specific association */ 31561da177e4SLinus Torvalds if (asoc) { 3157402d68c4SVlad Yasevich if (assocparams.sasoc_asocmaxrxt != 0) { 3158402d68c4SVlad Yasevich __u32 path_sum = 0; 3159402d68c4SVlad Yasevich int paths = 0; 3160402d68c4SVlad Yasevich struct sctp_transport *peer_addr; 3161402d68c4SVlad Yasevich 31629dbc15f0SRobert P. J. Day list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list, 31639dbc15f0SRobert P. J. Day transports) { 3164402d68c4SVlad Yasevich path_sum += peer_addr->pathmaxrxt; 3165402d68c4SVlad Yasevich paths++; 3166402d68c4SVlad Yasevich } 3167402d68c4SVlad Yasevich 3168025dfdafSFrederik Schwarzer /* Only validate asocmaxrxt if we have more than 3169402d68c4SVlad Yasevich * one path/transport. We do this because path 3170402d68c4SVlad Yasevich * retransmissions are only counted when we have more 3171402d68c4SVlad Yasevich * then one path. 3172402d68c4SVlad Yasevich */ 3173402d68c4SVlad Yasevich if (paths > 1 && 3174402d68c4SVlad Yasevich assocparams.sasoc_asocmaxrxt > path_sum) 3175402d68c4SVlad Yasevich return -EINVAL; 3176402d68c4SVlad Yasevich 31771da177e4SLinus Torvalds asoc->max_retrans = assocparams.sasoc_asocmaxrxt; 3178402d68c4SVlad Yasevich } 3179402d68c4SVlad Yasevich 318052db882fSDaniel Borkmann if (assocparams.sasoc_cookie_life != 0) 318152db882fSDaniel Borkmann asoc->cookie_life = ms_to_ktime(assocparams.sasoc_cookie_life); 31821da177e4SLinus Torvalds } else { 31831da177e4SLinus Torvalds /* Set the values to the endpoint */ 31841da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 31851da177e4SLinus Torvalds 31861da177e4SLinus Torvalds if (assocparams.sasoc_asocmaxrxt != 0) 31871da177e4SLinus Torvalds sp->assocparams.sasoc_asocmaxrxt = 31881da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt; 31891da177e4SLinus Torvalds if (assocparams.sasoc_cookie_life != 0) 31901da177e4SLinus Torvalds sp->assocparams.sasoc_cookie_life = 31911da177e4SLinus Torvalds assocparams.sasoc_cookie_life; 31921da177e4SLinus Torvalds } 31931da177e4SLinus Torvalds return 0; 31941da177e4SLinus Torvalds } 31951da177e4SLinus Torvalds 31961da177e4SLinus Torvalds /* 31971da177e4SLinus Torvalds * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 31981da177e4SLinus Torvalds * 31991da177e4SLinus Torvalds * This socket option is a boolean flag which turns on or off mapped V4 32001da177e4SLinus Torvalds * addresses. If this option is turned on and the socket is type 32011da177e4SLinus Torvalds * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 32021da177e4SLinus Torvalds * If this option is turned off, then no mapping will be done of V4 32031da177e4SLinus Torvalds * addresses and a user will receive both PF_INET6 and PF_INET type 32041da177e4SLinus Torvalds * addresses on the socket. 32051da177e4SLinus Torvalds */ 3206b7058842SDavid S. Miller static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen) 32071da177e4SLinus Torvalds { 32081da177e4SLinus Torvalds int val; 32091da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 32101da177e4SLinus Torvalds 32111da177e4SLinus Torvalds if (optlen < sizeof(int)) 32121da177e4SLinus Torvalds return -EINVAL; 32131da177e4SLinus Torvalds if (get_user(val, (int __user *)optval)) 32141da177e4SLinus Torvalds return -EFAULT; 32151da177e4SLinus Torvalds if (val) 32161da177e4SLinus Torvalds sp->v4mapped = 1; 32171da177e4SLinus Torvalds else 32181da177e4SLinus Torvalds sp->v4mapped = 0; 32191da177e4SLinus Torvalds 32201da177e4SLinus Torvalds return 0; 32211da177e4SLinus Torvalds } 32221da177e4SLinus Torvalds 32231da177e4SLinus Torvalds /* 3224e89c2095SWei Yongjun * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 3225e89c2095SWei Yongjun * This option will get or set the maximum size to put in any outgoing 3226e89c2095SWei Yongjun * SCTP DATA chunk. If a message is larger than this size it will be 32271da177e4SLinus Torvalds * fragmented by SCTP into the specified size. Note that the underlying 32281da177e4SLinus Torvalds * SCTP implementation may fragment into smaller sized chunks when the 32291da177e4SLinus Torvalds * PMTU of the underlying association is smaller than the value set by 3230e89c2095SWei Yongjun * the user. The default value for this option is '0' which indicates 3231e89c2095SWei Yongjun * the user is NOT limiting fragmentation and only the PMTU will effect 3232e89c2095SWei Yongjun * SCTP's choice of DATA chunk size. Note also that values set larger 3233e89c2095SWei Yongjun * than the maximum size of an IP datagram will effectively let SCTP 3234e89c2095SWei Yongjun * control fragmentation (i.e. the same as setting this option to 0). 3235e89c2095SWei Yongjun * 3236e89c2095SWei Yongjun * The following structure is used to access and modify this parameter: 3237e89c2095SWei Yongjun * 3238e89c2095SWei Yongjun * struct sctp_assoc_value { 3239e89c2095SWei Yongjun * sctp_assoc_t assoc_id; 3240e89c2095SWei Yongjun * uint32_t assoc_value; 3241e89c2095SWei Yongjun * }; 3242e89c2095SWei Yongjun * 3243e89c2095SWei Yongjun * assoc_id: This parameter is ignored for one-to-one style sockets. 3244e89c2095SWei Yongjun * For one-to-many style sockets this parameter indicates which 3245e89c2095SWei Yongjun * association the user is performing an action upon. Note that if 3246e89c2095SWei Yongjun * this field's value is zero then the endpoints default value is 3247e89c2095SWei Yongjun * changed (effecting future associations only). 3248e89c2095SWei Yongjun * assoc_value: This parameter specifies the maximum size in bytes. 32491da177e4SLinus Torvalds */ 3250b7058842SDavid S. Miller static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen) 32511da177e4SLinus Torvalds { 3252ecca8f88SXin Long struct sctp_sock *sp = sctp_sk(sk); 3253e89c2095SWei Yongjun struct sctp_assoc_value params; 32541da177e4SLinus Torvalds struct sctp_association *asoc; 32551da177e4SLinus Torvalds int val; 32561da177e4SLinus Torvalds 3257e89c2095SWei Yongjun if (optlen == sizeof(int)) { 325894f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 3259f916ec96SNeil Horman "%s (pid %d) " 326094f65193SNeil Horman "Use of int in maxseg socket option.\n" 3261f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 3262f916ec96SNeil Horman current->comm, task_pid_nr(current)); 3263e89c2095SWei Yongjun if (copy_from_user(&val, optval, optlen)) 32641da177e4SLinus Torvalds return -EFAULT; 32656fd769beSXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 3266e89c2095SWei Yongjun } else if (optlen == sizeof(struct sctp_assoc_value)) { 3267e89c2095SWei Yongjun if (copy_from_user(¶ms, optval, optlen)) 3268e89c2095SWei Yongjun return -EFAULT; 3269e89c2095SWei Yongjun val = params.assoc_value; 3270ecca8f88SXin Long } else { 3271e89c2095SWei Yongjun return -EINVAL; 3272ecca8f88SXin Long } 3273e89c2095SWei Yongjun 3274439ef030SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 32756fd769beSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 32766fd769beSXin Long sctp_style(sk, UDP)) 32776fd769beSXin Long return -EINVAL; 3278439ef030SMarcelo Ricardo Leitner 3279ecca8f88SXin Long if (val) { 3280ecca8f88SXin Long int min_len, max_len; 3281439ef030SMarcelo Ricardo Leitner __u16 datasize = asoc ? sctp_datachk_len(&asoc->stream) : 3282ecca8f88SXin Long sizeof(struct sctp_data_chunk); 3283ecca8f88SXin Long 3284afd0a800SJakub Audykowicz min_len = sctp_min_frag_point(sp, datasize); 3285439ef030SMarcelo Ricardo Leitner max_len = SCTP_MAX_CHUNK_LEN - datasize; 3286ecca8f88SXin Long 3287ecca8f88SXin Long if (val < min_len || val > max_len) 32881da177e4SLinus Torvalds return -EINVAL; 3289ecca8f88SXin Long } 3290e89c2095SWei Yongjun 3291e89c2095SWei Yongjun if (asoc) { 3292f68b2e05SVlad Yasevich asoc->user_frag = val; 32932f5e3c9dSMarcelo Ricardo Leitner sctp_assoc_update_frag_point(asoc); 3294e89c2095SWei Yongjun } else { 32951da177e4SLinus Torvalds sp->user_frag = val; 3296e89c2095SWei Yongjun } 32971da177e4SLinus Torvalds 32981da177e4SLinus Torvalds return 0; 32991da177e4SLinus Torvalds } 33001da177e4SLinus Torvalds 33011da177e4SLinus Torvalds 33021da177e4SLinus Torvalds /* 33031da177e4SLinus Torvalds * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) 33041da177e4SLinus Torvalds * 33051da177e4SLinus Torvalds * Requests that the peer mark the enclosed address as the association 33061da177e4SLinus Torvalds * primary. The enclosed address must be one of the association's 33071da177e4SLinus Torvalds * locally bound addresses. The following structure is used to make a 33081da177e4SLinus Torvalds * set primary request: 33091da177e4SLinus Torvalds */ 33101da177e4SLinus Torvalds static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval, 3311b7058842SDavid S. Miller unsigned int optlen) 33121da177e4SLinus Torvalds { 33131da177e4SLinus Torvalds struct sctp_sock *sp; 33141da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 33151da177e4SLinus Torvalds struct sctp_setpeerprim prim; 33161da177e4SLinus Torvalds struct sctp_chunk *chunk; 331740a01039SWei Yongjun struct sctp_af *af; 33181da177e4SLinus Torvalds int err; 33191da177e4SLinus Torvalds 33201da177e4SLinus Torvalds sp = sctp_sk(sk); 33211da177e4SLinus Torvalds 33224e27428fSXin Long if (!sp->ep->asconf_enable) 33231da177e4SLinus Torvalds return -EPERM; 33241da177e4SLinus Torvalds 33251da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_setpeerprim)) 33261da177e4SLinus Torvalds return -EINVAL; 33271da177e4SLinus Torvalds 33281da177e4SLinus Torvalds if (copy_from_user(&prim, optval, optlen)) 33291da177e4SLinus Torvalds return -EFAULT; 33301da177e4SLinus Torvalds 33311da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, prim.sspp_assoc_id); 33321da177e4SLinus Torvalds if (!asoc) 33331da177e4SLinus Torvalds return -EINVAL; 33341da177e4SLinus Torvalds 33351da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 33361da177e4SLinus Torvalds return -EPERM; 33371da177e4SLinus Torvalds 33381da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_SET_PRIMARY) 33391da177e4SLinus Torvalds return -EPERM; 33401da177e4SLinus Torvalds 33411da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 33421da177e4SLinus Torvalds return -ENOTCONN; 33431da177e4SLinus Torvalds 334440a01039SWei Yongjun af = sctp_get_af_specific(prim.sspp_addr.ss_family); 334540a01039SWei Yongjun if (!af) 334640a01039SWei Yongjun return -EINVAL; 334740a01039SWei Yongjun 334840a01039SWei Yongjun if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL)) 334940a01039SWei Yongjun return -EADDRNOTAVAIL; 335040a01039SWei Yongjun 33511da177e4SLinus Torvalds if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr)) 33521da177e4SLinus Torvalds return -EADDRNOTAVAIL; 33531da177e4SLinus Torvalds 33542277c7cdSRichard Haines /* Allow security module to validate address. */ 33552277c7cdSRichard Haines err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR, 33562277c7cdSRichard Haines (struct sockaddr *)&prim.sspp_addr, 33572277c7cdSRichard Haines af->sockaddr_len); 33582277c7cdSRichard Haines if (err) 33592277c7cdSRichard Haines return err; 33602277c7cdSRichard Haines 33611da177e4SLinus Torvalds /* Create an ASCONF chunk with SET_PRIMARY parameter */ 33621da177e4SLinus Torvalds chunk = sctp_make_asconf_set_prim(asoc, 33631da177e4SLinus Torvalds (union sctp_addr *)&prim.sspp_addr); 33641da177e4SLinus Torvalds if (!chunk) 33651da177e4SLinus Torvalds return -ENOMEM; 33661da177e4SLinus Torvalds 33671da177e4SLinus Torvalds err = sctp_send_asconf(asoc, chunk); 33681da177e4SLinus Torvalds 3369bb33381dSDaniel Borkmann pr_debug("%s: we set peer primary addr primitively\n", __func__); 33701da177e4SLinus Torvalds 33711da177e4SLinus Torvalds return err; 33721da177e4SLinus Torvalds } 33731da177e4SLinus Torvalds 33740f3fffd8SIvan Skytte Jorgensen static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval, 3375b7058842SDavid S. Miller unsigned int optlen) 33761da177e4SLinus Torvalds { 33770f3fffd8SIvan Skytte Jorgensen struct sctp_setadaptation adaptation; 33781da177e4SLinus Torvalds 33790f3fffd8SIvan Skytte Jorgensen if (optlen != sizeof(struct sctp_setadaptation)) 33801da177e4SLinus Torvalds return -EINVAL; 33810f3fffd8SIvan Skytte Jorgensen if (copy_from_user(&adaptation, optval, optlen)) 33821da177e4SLinus Torvalds return -EFAULT; 33831da177e4SLinus Torvalds 33840f3fffd8SIvan Skytte Jorgensen sctp_sk(sk)->adaptation_ind = adaptation.ssb_adaptation_ind; 33851da177e4SLinus Torvalds 33861da177e4SLinus Torvalds return 0; 33871da177e4SLinus Torvalds } 33881da177e4SLinus Torvalds 33896ab792f5SIvan Skytte Jorgensen /* 33906ab792f5SIvan Skytte Jorgensen * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 33916ab792f5SIvan Skytte Jorgensen * 33926ab792f5SIvan Skytte Jorgensen * The context field in the sctp_sndrcvinfo structure is normally only 33936ab792f5SIvan Skytte Jorgensen * used when a failed message is retrieved holding the value that was 33946ab792f5SIvan Skytte Jorgensen * sent down on the actual send call. This option allows the setting of 33956ab792f5SIvan Skytte Jorgensen * a default context on an association basis that will be received on 33966ab792f5SIvan Skytte Jorgensen * reading messages from the peer. This is especially helpful in the 33976ab792f5SIvan Skytte Jorgensen * one-2-many model for an application to keep some reference to an 33986ab792f5SIvan Skytte Jorgensen * internal state machine that is processing messages on the 33996ab792f5SIvan Skytte Jorgensen * association. Note that the setting of this value only effects 34006ab792f5SIvan Skytte Jorgensen * received messages from the peer and does not effect the value that is 34016ab792f5SIvan Skytte Jorgensen * saved with outbound messages. 34026ab792f5SIvan Skytte Jorgensen */ 34036ab792f5SIvan Skytte Jorgensen static int sctp_setsockopt_context(struct sock *sk, char __user *optval, 3404b7058842SDavid S. Miller unsigned int optlen) 34056ab792f5SIvan Skytte Jorgensen { 340649b037acSXin Long struct sctp_sock *sp = sctp_sk(sk); 34076ab792f5SIvan Skytte Jorgensen struct sctp_assoc_value params; 34086ab792f5SIvan Skytte Jorgensen struct sctp_association *asoc; 34096ab792f5SIvan Skytte Jorgensen 34106ab792f5SIvan Skytte Jorgensen if (optlen != sizeof(struct sctp_assoc_value)) 34116ab792f5SIvan Skytte Jorgensen return -EINVAL; 34126ab792f5SIvan Skytte Jorgensen if (copy_from_user(¶ms, optval, optlen)) 34136ab792f5SIvan Skytte Jorgensen return -EFAULT; 34146ab792f5SIvan Skytte Jorgensen 34156ab792f5SIvan Skytte Jorgensen asoc = sctp_id2assoc(sk, params.assoc_id); 341649b037acSXin Long if (!asoc && params.assoc_id > SCTP_ALL_ASSOC && 341749b037acSXin Long sctp_style(sk, UDP)) 34186ab792f5SIvan Skytte Jorgensen return -EINVAL; 341949b037acSXin Long 342049b037acSXin Long if (asoc) { 34216ab792f5SIvan Skytte Jorgensen asoc->default_rcv_context = params.assoc_value; 342249b037acSXin Long 342349b037acSXin Long return 0; 34246ab792f5SIvan Skytte Jorgensen } 34256ab792f5SIvan Skytte Jorgensen 3426cface2cbSXin Long if (sctp_style(sk, TCP)) 3427cface2cbSXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 3428cface2cbSXin Long 342949b037acSXin Long if (params.assoc_id == SCTP_FUTURE_ASSOC || 343049b037acSXin Long params.assoc_id == SCTP_ALL_ASSOC) 343149b037acSXin Long sp->default_rcv_context = params.assoc_value; 343249b037acSXin Long 343349b037acSXin Long if (params.assoc_id == SCTP_CURRENT_ASSOC || 343449b037acSXin Long params.assoc_id == SCTP_ALL_ASSOC) 343549b037acSXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) 343649b037acSXin Long asoc->default_rcv_context = params.assoc_value; 343749b037acSXin Long 34386ab792f5SIvan Skytte Jorgensen return 0; 34396ab792f5SIvan Skytte Jorgensen } 34406ab792f5SIvan Skytte Jorgensen 3441b6e1331fSVlad Yasevich /* 3442b6e1331fSVlad Yasevich * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 3443b6e1331fSVlad Yasevich * 3444b6e1331fSVlad Yasevich * This options will at a minimum specify if the implementation is doing 3445b6e1331fSVlad Yasevich * fragmented interleave. Fragmented interleave, for a one to many 3446b6e1331fSVlad Yasevich * socket, is when subsequent calls to receive a message may return 3447b6e1331fSVlad Yasevich * parts of messages from different associations. Some implementations 3448b6e1331fSVlad Yasevich * may allow you to turn this value on or off. If so, when turned off, 3449b6e1331fSVlad Yasevich * no fragment interleave will occur (which will cause a head of line 3450b6e1331fSVlad Yasevich * blocking amongst multiple associations sharing the same one to many 3451b6e1331fSVlad Yasevich * socket). When this option is turned on, then each receive call may 3452b6e1331fSVlad Yasevich * come from a different association (thus the user must receive data 3453b6e1331fSVlad Yasevich * with the extended calls (e.g. sctp_recvmsg) to keep track of which 3454b6e1331fSVlad Yasevich * association each receive belongs to. 3455b6e1331fSVlad Yasevich * 3456b6e1331fSVlad Yasevich * This option takes a boolean value. A non-zero value indicates that 3457b6e1331fSVlad Yasevich * fragmented interleave is on. A value of zero indicates that 3458b6e1331fSVlad Yasevich * fragmented interleave is off. 3459b6e1331fSVlad Yasevich * 3460b6e1331fSVlad Yasevich * Note that it is important that an implementation that allows this 3461b6e1331fSVlad Yasevich * option to be turned on, have it off by default. Otherwise an unaware 3462b6e1331fSVlad Yasevich * application using the one to many model may become confused and act 3463b6e1331fSVlad Yasevich * incorrectly. 3464b6e1331fSVlad Yasevich */ 3465b6e1331fSVlad Yasevich static int sctp_setsockopt_fragment_interleave(struct sock *sk, 3466b6e1331fSVlad Yasevich char __user *optval, 3467b7058842SDavid S. Miller unsigned int optlen) 3468b6e1331fSVlad Yasevich { 3469b6e1331fSVlad Yasevich int val; 3470b6e1331fSVlad Yasevich 3471b6e1331fSVlad Yasevich if (optlen != sizeof(int)) 3472b6e1331fSVlad Yasevich return -EINVAL; 3473b6e1331fSVlad Yasevich if (get_user(val, (int __user *)optval)) 3474b6e1331fSVlad Yasevich return -EFAULT; 3475b6e1331fSVlad Yasevich 3476772a5869SXin Long sctp_sk(sk)->frag_interleave = !!val; 3477772a5869SXin Long 3478772a5869SXin Long if (!sctp_sk(sk)->frag_interleave) 3479e55f4b8bSXin Long sctp_sk(sk)->ep->intl_enable = 0; 3480b6e1331fSVlad Yasevich 3481b6e1331fSVlad Yasevich return 0; 3482b6e1331fSVlad Yasevich } 3483b6e1331fSVlad Yasevich 3484d49d91d7SVlad Yasevich /* 34858510b937SWei Yongjun * 8.1.21. Set or Get the SCTP Partial Delivery Point 3486d49d91d7SVlad Yasevich * (SCTP_PARTIAL_DELIVERY_POINT) 34878510b937SWei Yongjun * 3488d49d91d7SVlad Yasevich * This option will set or get the SCTP partial delivery point. This 3489d49d91d7SVlad Yasevich * point is the size of a message where the partial delivery API will be 3490d49d91d7SVlad Yasevich * invoked to help free up rwnd space for the peer. Setting this to a 34918510b937SWei Yongjun * lower value will cause partial deliveries to happen more often. The 3492d49d91d7SVlad Yasevich * calls argument is an integer that sets or gets the partial delivery 34938510b937SWei Yongjun * point. Note also that the call will fail if the user attempts to set 34948510b937SWei Yongjun * this value larger than the socket receive buffer size. 34958510b937SWei Yongjun * 34968510b937SWei Yongjun * Note that any single message having a length smaller than or equal to 34978510b937SWei Yongjun * the SCTP partial delivery point will be delivered in one single read 34988510b937SWei Yongjun * call as long as the user provided buffer is large enough to hold the 34998510b937SWei Yongjun * message. 3500d49d91d7SVlad Yasevich */ 3501d49d91d7SVlad Yasevich static int sctp_setsockopt_partial_delivery_point(struct sock *sk, 3502d49d91d7SVlad Yasevich char __user *optval, 3503b7058842SDavid S. Miller unsigned int optlen) 3504d49d91d7SVlad Yasevich { 3505d49d91d7SVlad Yasevich u32 val; 3506d49d91d7SVlad Yasevich 3507d49d91d7SVlad Yasevich if (optlen != sizeof(u32)) 3508d49d91d7SVlad Yasevich return -EINVAL; 3509d49d91d7SVlad Yasevich if (get_user(val, (int __user *)optval)) 3510d49d91d7SVlad Yasevich return -EFAULT; 3511d49d91d7SVlad Yasevich 35128510b937SWei Yongjun /* Note: We double the receive buffer from what the user sets 35138510b937SWei Yongjun * it to be, also initial rwnd is based on rcvbuf/2. 35148510b937SWei Yongjun */ 35158510b937SWei Yongjun if (val > (sk->sk_rcvbuf >> 1)) 35168510b937SWei Yongjun return -EINVAL; 35178510b937SWei Yongjun 3518d49d91d7SVlad Yasevich sctp_sk(sk)->pd_point = val; 3519d49d91d7SVlad Yasevich 3520d49d91d7SVlad Yasevich return 0; /* is this the right error code? */ 3521d49d91d7SVlad Yasevich } 3522d49d91d7SVlad Yasevich 352370331571SVlad Yasevich /* 352470331571SVlad Yasevich * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 352570331571SVlad Yasevich * 352670331571SVlad Yasevich * This option will allow a user to change the maximum burst of packets 352770331571SVlad Yasevich * that can be emitted by this association. Note that the default value 352870331571SVlad Yasevich * is 4, and some implementations may restrict this setting so that it 352970331571SVlad Yasevich * can only be lowered. 353070331571SVlad Yasevich * 353170331571SVlad Yasevich * NOTE: This text doesn't seem right. Do this on a socket basis with 353270331571SVlad Yasevich * future associations inheriting the socket value. 353370331571SVlad Yasevich */ 353470331571SVlad Yasevich static int sctp_setsockopt_maxburst(struct sock *sk, 353570331571SVlad Yasevich char __user *optval, 3536b7058842SDavid S. Miller unsigned int optlen) 353770331571SVlad Yasevich { 3538e0651a0dSXin Long struct sctp_sock *sp = sctp_sk(sk); 3539219b99a9SNeil Horman struct sctp_assoc_value params; 3540219b99a9SNeil Horman struct sctp_association *asoc; 354170331571SVlad Yasevich 3542219b99a9SNeil Horman if (optlen == sizeof(int)) { 354394f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 3544f916ec96SNeil Horman "%s (pid %d) " 354594f65193SNeil Horman "Use of int in max_burst socket option deprecated.\n" 3546f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 3547f916ec96SNeil Horman current->comm, task_pid_nr(current)); 3548e0651a0dSXin Long if (copy_from_user(¶ms.assoc_value, optval, optlen)) 354970331571SVlad Yasevich return -EFAULT; 3550e0651a0dSXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 3551219b99a9SNeil Horman } else if (optlen == sizeof(struct sctp_assoc_value)) { 3552219b99a9SNeil Horman if (copy_from_user(¶ms, optval, optlen)) 3553219b99a9SNeil Horman return -EFAULT; 3554219b99a9SNeil Horman } else 355570331571SVlad Yasevich return -EINVAL; 355670331571SVlad Yasevich 3557e0651a0dSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 3558e0651a0dSXin Long if (!asoc && params.assoc_id > SCTP_ALL_ASSOC && 3559e0651a0dSXin Long sctp_style(sk, UDP)) 3560219b99a9SNeil Horman return -EINVAL; 3561e0651a0dSXin Long 3562e0651a0dSXin Long if (asoc) { 3563e0651a0dSXin Long asoc->max_burst = params.assoc_value; 3564e0651a0dSXin Long 3565e0651a0dSXin Long return 0; 3566e0651a0dSXin Long } 3567e0651a0dSXin Long 3568746bc215SXin Long if (sctp_style(sk, TCP)) 3569746bc215SXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 3570746bc215SXin Long 3571e0651a0dSXin Long if (params.assoc_id == SCTP_FUTURE_ASSOC || 3572e0651a0dSXin Long params.assoc_id == SCTP_ALL_ASSOC) 3573e0651a0dSXin Long sp->max_burst = params.assoc_value; 3574e0651a0dSXin Long 3575e0651a0dSXin Long if (params.assoc_id == SCTP_CURRENT_ASSOC || 3576e0651a0dSXin Long params.assoc_id == SCTP_ALL_ASSOC) 3577e0651a0dSXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) 3578e0651a0dSXin Long asoc->max_burst = params.assoc_value; 357970331571SVlad Yasevich 358070331571SVlad Yasevich return 0; 358170331571SVlad Yasevich } 358270331571SVlad Yasevich 358365b07e5dSVlad Yasevich /* 358465b07e5dSVlad Yasevich * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) 358565b07e5dSVlad Yasevich * 358665b07e5dSVlad Yasevich * This set option adds a chunk type that the user is requesting to be 358765b07e5dSVlad Yasevich * received only in an authenticated way. Changes to the list of chunks 358865b07e5dSVlad Yasevich * will only effect future associations on the socket. 358965b07e5dSVlad Yasevich */ 359065b07e5dSVlad Yasevich static int sctp_setsockopt_auth_chunk(struct sock *sk, 359165b07e5dSVlad Yasevich char __user *optval, 3592b7058842SDavid S. Miller unsigned int optlen) 359365b07e5dSVlad Yasevich { 3594b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 359565b07e5dSVlad Yasevich struct sctp_authchunk val; 359665b07e5dSVlad Yasevich 3597b14878ccSVlad Yasevich if (!ep->auth_enable) 35985e739d17SVlad Yasevich return -EACCES; 35995e739d17SVlad Yasevich 360065b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authchunk)) 360165b07e5dSVlad Yasevich return -EINVAL; 360265b07e5dSVlad Yasevich if (copy_from_user(&val, optval, optlen)) 360365b07e5dSVlad Yasevich return -EFAULT; 360465b07e5dSVlad Yasevich 360565b07e5dSVlad Yasevich switch (val.sauth_chunk) { 360665b07e5dSVlad Yasevich case SCTP_CID_INIT: 360765b07e5dSVlad Yasevich case SCTP_CID_INIT_ACK: 360865b07e5dSVlad Yasevich case SCTP_CID_SHUTDOWN_COMPLETE: 360965b07e5dSVlad Yasevich case SCTP_CID_AUTH: 361065b07e5dSVlad Yasevich return -EINVAL; 361165b07e5dSVlad Yasevich } 361265b07e5dSVlad Yasevich 361365b07e5dSVlad Yasevich /* add this chunk id to the endpoint */ 3614b14878ccSVlad Yasevich return sctp_auth_ep_add_chunkid(ep, val.sauth_chunk); 361565b07e5dSVlad Yasevich } 361665b07e5dSVlad Yasevich 361765b07e5dSVlad Yasevich /* 361865b07e5dSVlad Yasevich * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) 361965b07e5dSVlad Yasevich * 362065b07e5dSVlad Yasevich * This option gets or sets the list of HMAC algorithms that the local 362165b07e5dSVlad Yasevich * endpoint requires the peer to use. 362265b07e5dSVlad Yasevich */ 362365b07e5dSVlad Yasevich static int sctp_setsockopt_hmac_ident(struct sock *sk, 362465b07e5dSVlad Yasevich char __user *optval, 3625b7058842SDavid S. Miller unsigned int optlen) 362665b07e5dSVlad Yasevich { 3627b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 362865b07e5dSVlad Yasevich struct sctp_hmacalgo *hmacs; 3629d9724055SVlad Yasevich u32 idents; 363065b07e5dSVlad Yasevich int err; 363165b07e5dSVlad Yasevich 3632b14878ccSVlad Yasevich if (!ep->auth_enable) 36335e739d17SVlad Yasevich return -EACCES; 36345e739d17SVlad Yasevich 363565b07e5dSVlad Yasevich if (optlen < sizeof(struct sctp_hmacalgo)) 363665b07e5dSVlad Yasevich return -EINVAL; 36375960cefaSMarcelo Ricardo Leitner optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) + 36385960cefaSMarcelo Ricardo Leitner SCTP_AUTH_NUM_HMACS * sizeof(u16)); 363965b07e5dSVlad Yasevich 3640934253a7SShan Wei hmacs = memdup_user(optval, optlen); 3641934253a7SShan Wei if (IS_ERR(hmacs)) 3642934253a7SShan Wei return PTR_ERR(hmacs); 364365b07e5dSVlad Yasevich 3644d9724055SVlad Yasevich idents = hmacs->shmac_num_idents; 3645d9724055SVlad Yasevich if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || 3646d9724055SVlad Yasevich (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) { 364765b07e5dSVlad Yasevich err = -EINVAL; 364865b07e5dSVlad Yasevich goto out; 364965b07e5dSVlad Yasevich } 365065b07e5dSVlad Yasevich 3651b14878ccSVlad Yasevich err = sctp_auth_ep_set_hmacs(ep, hmacs); 365265b07e5dSVlad Yasevich out: 365365b07e5dSVlad Yasevich kfree(hmacs); 365465b07e5dSVlad Yasevich return err; 365565b07e5dSVlad Yasevich } 365665b07e5dSVlad Yasevich 365765b07e5dSVlad Yasevich /* 365865b07e5dSVlad Yasevich * 7.1.20. Set a shared key (SCTP_AUTH_KEY) 365965b07e5dSVlad Yasevich * 366065b07e5dSVlad Yasevich * This option will set a shared secret key which is used to build an 366165b07e5dSVlad Yasevich * association shared key. 366265b07e5dSVlad Yasevich */ 366365b07e5dSVlad Yasevich static int sctp_setsockopt_auth_key(struct sock *sk, 366465b07e5dSVlad Yasevich char __user *optval, 3665b7058842SDavid S. Miller unsigned int optlen) 366665b07e5dSVlad Yasevich { 3667b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 366865b07e5dSVlad Yasevich struct sctp_authkey *authkey; 366965b07e5dSVlad Yasevich struct sctp_association *asoc; 36707fb3be13SXin Long int ret = -EINVAL; 367165b07e5dSVlad Yasevich 367265b07e5dSVlad Yasevich if (optlen <= sizeof(struct sctp_authkey)) 367365b07e5dSVlad Yasevich return -EINVAL; 36745960cefaSMarcelo Ricardo Leitner /* authkey->sca_keylength is u16, so optlen can't be bigger than 36755960cefaSMarcelo Ricardo Leitner * this. 36765960cefaSMarcelo Ricardo Leitner */ 36777fb3be13SXin Long optlen = min_t(unsigned int, optlen, USHRT_MAX + sizeof(*authkey)); 367865b07e5dSVlad Yasevich 3679934253a7SShan Wei authkey = memdup_user(optval, optlen); 3680934253a7SShan Wei if (IS_ERR(authkey)) 3681934253a7SShan Wei return PTR_ERR(authkey); 368265b07e5dSVlad Yasevich 36837fb3be13SXin Long if (authkey->sca_keylength > optlen - sizeof(*authkey)) 368430c2235cSVlad Yasevich goto out; 368530c2235cSVlad Yasevich 368665b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); 36877fb3be13SXin Long if (!asoc && authkey->sca_assoc_id > SCTP_ALL_ASSOC && 36887fb3be13SXin Long sctp_style(sk, UDP)) 36897fb3be13SXin Long goto out; 36907fb3be13SXin Long 36917fb3be13SXin Long if (asoc) { 36927fb3be13SXin Long ret = sctp_auth_set_key(ep, asoc, authkey); 369365b07e5dSVlad Yasevich goto out; 369465b07e5dSVlad Yasevich } 369565b07e5dSVlad Yasevich 36960685d6b7SXin Long if (sctp_style(sk, TCP)) 36970685d6b7SXin Long authkey->sca_assoc_id = SCTP_FUTURE_ASSOC; 36980685d6b7SXin Long 36997fb3be13SXin Long if (authkey->sca_assoc_id == SCTP_FUTURE_ASSOC || 37007fb3be13SXin Long authkey->sca_assoc_id == SCTP_ALL_ASSOC) { 3701b14878ccSVlad Yasevich ret = sctp_auth_set_key(ep, asoc, authkey); 37027fb3be13SXin Long if (ret) 37037fb3be13SXin Long goto out; 37047fb3be13SXin Long } 37057fb3be13SXin Long 37067fb3be13SXin Long ret = 0; 37077fb3be13SXin Long 37087fb3be13SXin Long if (authkey->sca_assoc_id == SCTP_CURRENT_ASSOC || 37097fb3be13SXin Long authkey->sca_assoc_id == SCTP_ALL_ASSOC) { 37107fb3be13SXin Long list_for_each_entry(asoc, &ep->asocs, asocs) { 37117fb3be13SXin Long int res = sctp_auth_set_key(ep, asoc, authkey); 37127fb3be13SXin Long 37137fb3be13SXin Long if (res && !ret) 37147fb3be13SXin Long ret = res; 37157fb3be13SXin Long } 37167fb3be13SXin Long } 37177fb3be13SXin Long 371865b07e5dSVlad Yasevich out: 37196ba542a2SDaniel Borkmann kzfree(authkey); 372065b07e5dSVlad Yasevich return ret; 372165b07e5dSVlad Yasevich } 372265b07e5dSVlad Yasevich 372365b07e5dSVlad Yasevich /* 372465b07e5dSVlad Yasevich * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) 372565b07e5dSVlad Yasevich * 372665b07e5dSVlad Yasevich * This option will get or set the active shared key to be used to build 372765b07e5dSVlad Yasevich * the association shared key. 372865b07e5dSVlad Yasevich */ 372965b07e5dSVlad Yasevich static int sctp_setsockopt_active_key(struct sock *sk, 373065b07e5dSVlad Yasevich char __user *optval, 3731b7058842SDavid S. Miller unsigned int optlen) 373265b07e5dSVlad Yasevich { 3733b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 373465b07e5dSVlad Yasevich struct sctp_association *asoc; 3735bf9fb6adSXin Long struct sctp_authkeyid val; 3736bf9fb6adSXin Long int ret = 0; 373765b07e5dSVlad Yasevich 373865b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authkeyid)) 373965b07e5dSVlad Yasevich return -EINVAL; 374065b07e5dSVlad Yasevich if (copy_from_user(&val, optval, optlen)) 374165b07e5dSVlad Yasevich return -EFAULT; 374265b07e5dSVlad Yasevich 374365b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 3744bf9fb6adSXin Long if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC && 3745bf9fb6adSXin Long sctp_style(sk, UDP)) 374665b07e5dSVlad Yasevich return -EINVAL; 374765b07e5dSVlad Yasevich 3748bf9fb6adSXin Long if (asoc) 3749b14878ccSVlad Yasevich return sctp_auth_set_active_key(ep, asoc, val.scact_keynumber); 3750bf9fb6adSXin Long 375106b39e85SXin Long if (sctp_style(sk, TCP)) 375206b39e85SXin Long val.scact_assoc_id = SCTP_FUTURE_ASSOC; 375306b39e85SXin Long 3754bf9fb6adSXin Long if (val.scact_assoc_id == SCTP_FUTURE_ASSOC || 3755bf9fb6adSXin Long val.scact_assoc_id == SCTP_ALL_ASSOC) { 3756bf9fb6adSXin Long ret = sctp_auth_set_active_key(ep, asoc, val.scact_keynumber); 3757bf9fb6adSXin Long if (ret) 3758bf9fb6adSXin Long return ret; 3759bf9fb6adSXin Long } 3760bf9fb6adSXin Long 3761bf9fb6adSXin Long if (val.scact_assoc_id == SCTP_CURRENT_ASSOC || 3762bf9fb6adSXin Long val.scact_assoc_id == SCTP_ALL_ASSOC) { 3763bf9fb6adSXin Long list_for_each_entry(asoc, &ep->asocs, asocs) { 3764bf9fb6adSXin Long int res = sctp_auth_set_active_key(ep, asoc, 3765bf9fb6adSXin Long val.scact_keynumber); 3766bf9fb6adSXin Long 3767bf9fb6adSXin Long if (res && !ret) 3768bf9fb6adSXin Long ret = res; 3769bf9fb6adSXin Long } 3770bf9fb6adSXin Long } 3771bf9fb6adSXin Long 3772bf9fb6adSXin Long return ret; 377365b07e5dSVlad Yasevich } 377465b07e5dSVlad Yasevich 377565b07e5dSVlad Yasevich /* 377665b07e5dSVlad Yasevich * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY) 377765b07e5dSVlad Yasevich * 377865b07e5dSVlad Yasevich * This set option will delete a shared secret key from use. 377965b07e5dSVlad Yasevich */ 378065b07e5dSVlad Yasevich static int sctp_setsockopt_del_key(struct sock *sk, 378165b07e5dSVlad Yasevich char __user *optval, 3782b7058842SDavid S. Miller unsigned int optlen) 378365b07e5dSVlad Yasevich { 3784b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 378565b07e5dSVlad Yasevich struct sctp_association *asoc; 37863adcc300SXin Long struct sctp_authkeyid val; 37873adcc300SXin Long int ret = 0; 378865b07e5dSVlad Yasevich 378965b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authkeyid)) 379065b07e5dSVlad Yasevich return -EINVAL; 379165b07e5dSVlad Yasevich if (copy_from_user(&val, optval, optlen)) 379265b07e5dSVlad Yasevich return -EFAULT; 379365b07e5dSVlad Yasevich 379465b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 37953adcc300SXin Long if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC && 37963adcc300SXin Long sctp_style(sk, UDP)) 379765b07e5dSVlad Yasevich return -EINVAL; 379865b07e5dSVlad Yasevich 37993adcc300SXin Long if (asoc) 3800b14878ccSVlad Yasevich return sctp_auth_del_key_id(ep, asoc, val.scact_keynumber); 380165b07e5dSVlad Yasevich 3802220675ebSXin Long if (sctp_style(sk, TCP)) 3803220675ebSXin Long val.scact_assoc_id = SCTP_FUTURE_ASSOC; 3804220675ebSXin Long 38053adcc300SXin Long if (val.scact_assoc_id == SCTP_FUTURE_ASSOC || 38063adcc300SXin Long val.scact_assoc_id == SCTP_ALL_ASSOC) { 38073adcc300SXin Long ret = sctp_auth_del_key_id(ep, asoc, val.scact_keynumber); 38083adcc300SXin Long if (ret) 38093adcc300SXin Long return ret; 38103adcc300SXin Long } 38113adcc300SXin Long 38123adcc300SXin Long if (val.scact_assoc_id == SCTP_CURRENT_ASSOC || 38133adcc300SXin Long val.scact_assoc_id == SCTP_ALL_ASSOC) { 38143adcc300SXin Long list_for_each_entry(asoc, &ep->asocs, asocs) { 38153adcc300SXin Long int res = sctp_auth_del_key_id(ep, asoc, 38163adcc300SXin Long val.scact_keynumber); 38173adcc300SXin Long 38183adcc300SXin Long if (res && !ret) 38193adcc300SXin Long ret = res; 38203adcc300SXin Long } 38213adcc300SXin Long } 38223adcc300SXin Long 38233adcc300SXin Long return ret; 382465b07e5dSVlad Yasevich } 382565b07e5dSVlad Yasevich 38267dc04d71SMichio Honda /* 3827601590ecSXin Long * 8.3.4 Deactivate a Shared Key (SCTP_AUTH_DEACTIVATE_KEY) 3828601590ecSXin Long * 3829601590ecSXin Long * This set option will deactivate a shared secret key. 3830601590ecSXin Long */ 3831601590ecSXin Long static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval, 3832601590ecSXin Long unsigned int optlen) 3833601590ecSXin Long { 3834601590ecSXin Long struct sctp_endpoint *ep = sctp_sk(sk)->ep; 3835601590ecSXin Long struct sctp_association *asoc; 38362af66ff3SXin Long struct sctp_authkeyid val; 38372af66ff3SXin Long int ret = 0; 3838601590ecSXin Long 3839601590ecSXin Long if (optlen != sizeof(struct sctp_authkeyid)) 3840601590ecSXin Long return -EINVAL; 3841601590ecSXin Long if (copy_from_user(&val, optval, optlen)) 3842601590ecSXin Long return -EFAULT; 3843601590ecSXin Long 3844601590ecSXin Long asoc = sctp_id2assoc(sk, val.scact_assoc_id); 38452af66ff3SXin Long if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC && 38462af66ff3SXin Long sctp_style(sk, UDP)) 3847601590ecSXin Long return -EINVAL; 3848601590ecSXin Long 38492af66ff3SXin Long if (asoc) 3850601590ecSXin Long return sctp_auth_deact_key_id(ep, asoc, val.scact_keynumber); 38512af66ff3SXin Long 3852200f3a3bSXin Long if (sctp_style(sk, TCP)) 3853200f3a3bSXin Long val.scact_assoc_id = SCTP_FUTURE_ASSOC; 3854200f3a3bSXin Long 38552af66ff3SXin Long if (val.scact_assoc_id == SCTP_FUTURE_ASSOC || 38562af66ff3SXin Long val.scact_assoc_id == SCTP_ALL_ASSOC) { 38572af66ff3SXin Long ret = sctp_auth_deact_key_id(ep, asoc, val.scact_keynumber); 38582af66ff3SXin Long if (ret) 38592af66ff3SXin Long return ret; 38602af66ff3SXin Long } 38612af66ff3SXin Long 38622af66ff3SXin Long if (val.scact_assoc_id == SCTP_CURRENT_ASSOC || 38632af66ff3SXin Long val.scact_assoc_id == SCTP_ALL_ASSOC) { 38642af66ff3SXin Long list_for_each_entry(asoc, &ep->asocs, asocs) { 38652af66ff3SXin Long int res = sctp_auth_deact_key_id(ep, asoc, 38662af66ff3SXin Long val.scact_keynumber); 38672af66ff3SXin Long 38682af66ff3SXin Long if (res && !ret) 38692af66ff3SXin Long ret = res; 38702af66ff3SXin Long } 38712af66ff3SXin Long } 38722af66ff3SXin Long 38732af66ff3SXin Long return ret; 3874601590ecSXin Long } 3875601590ecSXin Long 3876601590ecSXin Long /* 38777dc04d71SMichio Honda * 8.1.23 SCTP_AUTO_ASCONF 38787dc04d71SMichio Honda * 38797dc04d71SMichio Honda * This option will enable or disable the use of the automatic generation of 38807dc04d71SMichio Honda * ASCONF chunks to add and delete addresses to an existing association. Note 38817dc04d71SMichio Honda * that this option has two caveats namely: a) it only affects sockets that 38827dc04d71SMichio Honda * are bound to all addresses available to the SCTP stack, and b) the system 38837dc04d71SMichio Honda * administrator may have an overriding control that turns the ASCONF feature 38847dc04d71SMichio Honda * off no matter what setting the socket option may have. 38857dc04d71SMichio Honda * This option expects an integer boolean flag, where a non-zero value turns on 38867dc04d71SMichio Honda * the option, and a zero value turns off the option. 38877dc04d71SMichio Honda * Note. In this implementation, socket operation overrides default parameter 38887dc04d71SMichio Honda * being set by sysctl as well as FreeBSD implementation 38897dc04d71SMichio Honda */ 38907dc04d71SMichio Honda static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, 38917dc04d71SMichio Honda unsigned int optlen) 38927dc04d71SMichio Honda { 38937dc04d71SMichio Honda int val; 38947dc04d71SMichio Honda struct sctp_sock *sp = sctp_sk(sk); 38957dc04d71SMichio Honda 38967dc04d71SMichio Honda if (optlen < sizeof(int)) 38977dc04d71SMichio Honda return -EINVAL; 38987dc04d71SMichio Honda if (get_user(val, (int __user *)optval)) 38997dc04d71SMichio Honda return -EFAULT; 39007dc04d71SMichio Honda if (!sctp_is_ep_boundall(sk) && val) 39017dc04d71SMichio Honda return -EINVAL; 39027dc04d71SMichio Honda if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf)) 39037dc04d71SMichio Honda return 0; 39047dc04d71SMichio Honda 39052d45a02dSMarcelo Ricardo Leitner spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock); 39067dc04d71SMichio Honda if (val == 0 && sp->do_auto_asconf) { 39077dc04d71SMichio Honda list_del(&sp->auto_asconf_list); 39087dc04d71SMichio Honda sp->do_auto_asconf = 0; 39097dc04d71SMichio Honda } else if (val && !sp->do_auto_asconf) { 39107dc04d71SMichio Honda list_add_tail(&sp->auto_asconf_list, 39114db67e80SEric W. Biederman &sock_net(sk)->sctp.auto_asconf_splist); 39127dc04d71SMichio Honda sp->do_auto_asconf = 1; 39137dc04d71SMichio Honda } 39142d45a02dSMarcelo Ricardo Leitner spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock); 39157dc04d71SMichio Honda return 0; 39167dc04d71SMichio Honda } 39177dc04d71SMichio Honda 39185aa93bcfSNeil Horman /* 39195aa93bcfSNeil Horman * SCTP_PEER_ADDR_THLDS 39205aa93bcfSNeil Horman * 39215aa93bcfSNeil Horman * This option allows us to alter the partially failed threshold for one or all 39225aa93bcfSNeil Horman * transports in an association. See Section 6.1 of: 39235aa93bcfSNeil Horman * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 39245aa93bcfSNeil Horman */ 39255aa93bcfSNeil Horman static int sctp_setsockopt_paddr_thresholds(struct sock *sk, 39265aa93bcfSNeil Horman char __user *optval, 3927d467ac0aSXin Long unsigned int optlen, bool v2) 39285aa93bcfSNeil Horman { 3929d467ac0aSXin Long struct sctp_paddrthlds_v2 val; 39305aa93bcfSNeil Horman struct sctp_transport *trans; 39315aa93bcfSNeil Horman struct sctp_association *asoc; 3932d467ac0aSXin Long int len; 39335aa93bcfSNeil Horman 3934d467ac0aSXin Long len = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds); 3935d467ac0aSXin Long if (optlen < len) 39365aa93bcfSNeil Horman return -EINVAL; 3937d467ac0aSXin Long if (copy_from_user(&val, optval, len)) 39385aa93bcfSNeil Horman return -EFAULT; 39395aa93bcfSNeil Horman 3940d467ac0aSXin Long if (v2 && val.spt_pathpfthld > val.spt_pathcpthld) 3941d467ac0aSXin Long return -EINVAL; 3942d467ac0aSXin Long 39438add543eSXin Long if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { 39448add543eSXin Long trans = sctp_addr_id2transport(sk, &val.spt_address, 39458add543eSXin Long val.spt_assoc_id); 39468add543eSXin Long if (!trans) 39475aa93bcfSNeil Horman return -ENOENT; 39488add543eSXin Long 39498add543eSXin Long if (val.spt_pathmaxrxt) 39508add543eSXin Long trans->pathmaxrxt = val.spt_pathmaxrxt; 3951d467ac0aSXin Long if (v2) 3952d467ac0aSXin Long trans->ps_retrans = val.spt_pathcpthld; 39538add543eSXin Long trans->pf_retrans = val.spt_pathpfthld; 39548add543eSXin Long 39558add543eSXin Long return 0; 39568add543eSXin Long } 39578add543eSXin Long 39588add543eSXin Long asoc = sctp_id2assoc(sk, val.spt_assoc_id); 39598add543eSXin Long if (!asoc && val.spt_assoc_id != SCTP_FUTURE_ASSOC && 39608add543eSXin Long sctp_style(sk, UDP)) 39618add543eSXin Long return -EINVAL; 39628add543eSXin Long 39638add543eSXin Long if (asoc) { 39645aa93bcfSNeil Horman list_for_each_entry(trans, &asoc->peer.transport_addr_list, 39655aa93bcfSNeil Horman transports) { 39665aa93bcfSNeil Horman if (val.spt_pathmaxrxt) 39675aa93bcfSNeil Horman trans->pathmaxrxt = val.spt_pathmaxrxt; 3968d467ac0aSXin Long if (v2) 3969d467ac0aSXin Long trans->ps_retrans = val.spt_pathcpthld; 39705aa93bcfSNeil Horman trans->pf_retrans = val.spt_pathpfthld; 39715aa93bcfSNeil Horman } 39725aa93bcfSNeil Horman 39735aa93bcfSNeil Horman if (val.spt_pathmaxrxt) 39745aa93bcfSNeil Horman asoc->pathmaxrxt = val.spt_pathmaxrxt; 3975d467ac0aSXin Long if (v2) 3976d467ac0aSXin Long asoc->ps_retrans = val.spt_pathcpthld; 39775aa93bcfSNeil Horman asoc->pf_retrans = val.spt_pathpfthld; 39785aa93bcfSNeil Horman } else { 39798add543eSXin Long struct sctp_sock *sp = sctp_sk(sk); 39805aa93bcfSNeil Horman 39815aa93bcfSNeil Horman if (val.spt_pathmaxrxt) 39828add543eSXin Long sp->pathmaxrxt = val.spt_pathmaxrxt; 3983d467ac0aSXin Long if (v2) 3984d467ac0aSXin Long sp->ps_retrans = val.spt_pathcpthld; 39858add543eSXin Long sp->pf_retrans = val.spt_pathpfthld; 39865aa93bcfSNeil Horman } 39875aa93bcfSNeil Horman 39885aa93bcfSNeil Horman return 0; 39895aa93bcfSNeil Horman } 39905aa93bcfSNeil Horman 39910d3a421dSGeir Ola Vaagland static int sctp_setsockopt_recvrcvinfo(struct sock *sk, 39920d3a421dSGeir Ola Vaagland char __user *optval, 39930d3a421dSGeir Ola Vaagland unsigned int optlen) 39940d3a421dSGeir Ola Vaagland { 39950d3a421dSGeir Ola Vaagland int val; 39960d3a421dSGeir Ola Vaagland 39970d3a421dSGeir Ola Vaagland if (optlen < sizeof(int)) 39980d3a421dSGeir Ola Vaagland return -EINVAL; 39990d3a421dSGeir Ola Vaagland if (get_user(val, (int __user *) optval)) 40000d3a421dSGeir Ola Vaagland return -EFAULT; 40010d3a421dSGeir Ola Vaagland 40020d3a421dSGeir Ola Vaagland sctp_sk(sk)->recvrcvinfo = (val == 0) ? 0 : 1; 40030d3a421dSGeir Ola Vaagland 40040d3a421dSGeir Ola Vaagland return 0; 40050d3a421dSGeir Ola Vaagland } 40060d3a421dSGeir Ola Vaagland 40072347c80fSGeir Ola Vaagland static int sctp_setsockopt_recvnxtinfo(struct sock *sk, 40082347c80fSGeir Ola Vaagland char __user *optval, 40092347c80fSGeir Ola Vaagland unsigned int optlen) 40102347c80fSGeir Ola Vaagland { 40112347c80fSGeir Ola Vaagland int val; 40122347c80fSGeir Ola Vaagland 40132347c80fSGeir Ola Vaagland if (optlen < sizeof(int)) 40142347c80fSGeir Ola Vaagland return -EINVAL; 40152347c80fSGeir Ola Vaagland if (get_user(val, (int __user *) optval)) 40162347c80fSGeir Ola Vaagland return -EFAULT; 40172347c80fSGeir Ola Vaagland 40182347c80fSGeir Ola Vaagland sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1; 40192347c80fSGeir Ola Vaagland 40202347c80fSGeir Ola Vaagland return 0; 40212347c80fSGeir Ola Vaagland } 40222347c80fSGeir Ola Vaagland 402328aa4c26SXin Long static int sctp_setsockopt_pr_supported(struct sock *sk, 402428aa4c26SXin Long char __user *optval, 402528aa4c26SXin Long unsigned int optlen) 402628aa4c26SXin Long { 402728aa4c26SXin Long struct sctp_assoc_value params; 4028fb195605SXin Long struct sctp_association *asoc; 402928aa4c26SXin Long 403028aa4c26SXin Long if (optlen != sizeof(params)) 4031cc3ccf26SXin Long return -EINVAL; 403228aa4c26SXin Long 4033cc3ccf26SXin Long if (copy_from_user(¶ms, optval, optlen)) 4034cc3ccf26SXin Long return -EFAULT; 403528aa4c26SXin Long 4036fb195605SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 4037fb195605SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 4038fb195605SXin Long sctp_style(sk, UDP)) 4039fb195605SXin Long return -EINVAL; 4040fb195605SXin Long 4041cc3ccf26SXin Long sctp_sk(sk)->ep->prsctp_enable = !!params.assoc_value; 404228aa4c26SXin Long 4043cc3ccf26SXin Long return 0; 404428aa4c26SXin Long } 404528aa4c26SXin Long 4046f959fb44SXin Long static int sctp_setsockopt_default_prinfo(struct sock *sk, 4047f959fb44SXin Long char __user *optval, 4048f959fb44SXin Long unsigned int optlen) 4049f959fb44SXin Long { 40503a583059SXin Long struct sctp_sock *sp = sctp_sk(sk); 4051f959fb44SXin Long struct sctp_default_prinfo info; 4052f959fb44SXin Long struct sctp_association *asoc; 4053f959fb44SXin Long int retval = -EINVAL; 4054f959fb44SXin Long 4055f959fb44SXin Long if (optlen != sizeof(info)) 4056f959fb44SXin Long goto out; 4057f959fb44SXin Long 4058f959fb44SXin Long if (copy_from_user(&info, optval, sizeof(info))) { 4059f959fb44SXin Long retval = -EFAULT; 4060f959fb44SXin Long goto out; 4061f959fb44SXin Long } 4062f959fb44SXin Long 4063f959fb44SXin Long if (info.pr_policy & ~SCTP_PR_SCTP_MASK) 4064f959fb44SXin Long goto out; 4065f959fb44SXin Long 4066f959fb44SXin Long if (info.pr_policy == SCTP_PR_SCTP_NONE) 4067f959fb44SXin Long info.pr_value = 0; 4068f959fb44SXin Long 4069f959fb44SXin Long asoc = sctp_id2assoc(sk, info.pr_assoc_id); 40703a583059SXin Long if (!asoc && info.pr_assoc_id > SCTP_ALL_ASSOC && 40713a583059SXin Long sctp_style(sk, UDP)) 40723a583059SXin Long goto out; 40733a583059SXin Long 40743a583059SXin Long retval = 0; 40753a583059SXin Long 4076f959fb44SXin Long if (asoc) { 4077f959fb44SXin Long SCTP_PR_SET_POLICY(asoc->default_flags, info.pr_policy); 4078f959fb44SXin Long asoc->default_timetolive = info.pr_value; 4079f959fb44SXin Long goto out; 4080f959fb44SXin Long } 4081f959fb44SXin Long 4082cbb45c6cSXin Long if (sctp_style(sk, TCP)) 4083cbb45c6cSXin Long info.pr_assoc_id = SCTP_FUTURE_ASSOC; 4084cbb45c6cSXin Long 40853a583059SXin Long if (info.pr_assoc_id == SCTP_FUTURE_ASSOC || 40863a583059SXin Long info.pr_assoc_id == SCTP_ALL_ASSOC) { 40873a583059SXin Long SCTP_PR_SET_POLICY(sp->default_flags, info.pr_policy); 40883a583059SXin Long sp->default_timetolive = info.pr_value; 40893a583059SXin Long } 40903a583059SXin Long 40913a583059SXin Long if (info.pr_assoc_id == SCTP_CURRENT_ASSOC || 40923a583059SXin Long info.pr_assoc_id == SCTP_ALL_ASSOC) { 40933a583059SXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 40943a583059SXin Long SCTP_PR_SET_POLICY(asoc->default_flags, info.pr_policy); 40953a583059SXin Long asoc->default_timetolive = info.pr_value; 40963a583059SXin Long } 40973a583059SXin Long } 4098f959fb44SXin Long 4099f959fb44SXin Long out: 4100f959fb44SXin Long return retval; 4101f959fb44SXin Long } 4102f959fb44SXin Long 4103c0d8bab6SXin Long static int sctp_setsockopt_reconfig_supported(struct sock *sk, 4104c0d8bab6SXin Long char __user *optval, 4105c0d8bab6SXin Long unsigned int optlen) 4106c0d8bab6SXin Long { 4107c0d8bab6SXin Long struct sctp_assoc_value params; 4108c0d8bab6SXin Long struct sctp_association *asoc; 4109c0d8bab6SXin Long int retval = -EINVAL; 4110c0d8bab6SXin Long 4111c0d8bab6SXin Long if (optlen != sizeof(params)) 4112c0d8bab6SXin Long goto out; 4113c0d8bab6SXin Long 4114c0d8bab6SXin Long if (copy_from_user(¶ms, optval, optlen)) { 4115c0d8bab6SXin Long retval = -EFAULT; 4116c0d8bab6SXin Long goto out; 4117c0d8bab6SXin Long } 4118c0d8bab6SXin Long 4119c0d8bab6SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 4120acce7f3bSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 4121acce7f3bSXin Long sctp_style(sk, UDP)) 4122c0d8bab6SXin Long goto out; 4123acce7f3bSXin Long 4124acce7f3bSXin Long sctp_sk(sk)->ep->reconf_enable = !!params.assoc_value; 4125c0d8bab6SXin Long 4126c0d8bab6SXin Long retval = 0; 4127c0d8bab6SXin Long 4128c0d8bab6SXin Long out: 4129c0d8bab6SXin Long return retval; 4130c0d8bab6SXin Long } 4131c0d8bab6SXin Long 41329fb657aeSXin Long static int sctp_setsockopt_enable_strreset(struct sock *sk, 41339fb657aeSXin Long char __user *optval, 41349fb657aeSXin Long unsigned int optlen) 41359fb657aeSXin Long { 413699a62135SXin Long struct sctp_endpoint *ep = sctp_sk(sk)->ep; 41379fb657aeSXin Long struct sctp_assoc_value params; 41389fb657aeSXin Long struct sctp_association *asoc; 41399fb657aeSXin Long int retval = -EINVAL; 41409fb657aeSXin Long 41419fb657aeSXin Long if (optlen != sizeof(params)) 41429fb657aeSXin Long goto out; 41439fb657aeSXin Long 41449fb657aeSXin Long if (copy_from_user(¶ms, optval, optlen)) { 41459fb657aeSXin Long retval = -EFAULT; 41469fb657aeSXin Long goto out; 41479fb657aeSXin Long } 41489fb657aeSXin Long 41499fb657aeSXin Long if (params.assoc_value & (~SCTP_ENABLE_STRRESET_MASK)) 41509fb657aeSXin Long goto out; 41519fb657aeSXin Long 41529fb657aeSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 415399a62135SXin Long if (!asoc && params.assoc_id > SCTP_ALL_ASSOC && 415499a62135SXin Long sctp_style(sk, UDP)) 415599a62135SXin Long goto out; 415699a62135SXin Long 415799a62135SXin Long retval = 0; 415899a62135SXin Long 41599fb657aeSXin Long if (asoc) { 41609fb657aeSXin Long asoc->strreset_enable = params.assoc_value; 41619fb657aeSXin Long goto out; 41629fb657aeSXin Long } 41639fb657aeSXin Long 41649430ff99SXin Long if (sctp_style(sk, TCP)) 41659430ff99SXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 41669430ff99SXin Long 416799a62135SXin Long if (params.assoc_id == SCTP_FUTURE_ASSOC || 416899a62135SXin Long params.assoc_id == SCTP_ALL_ASSOC) 416999a62135SXin Long ep->strreset_enable = params.assoc_value; 417099a62135SXin Long 417199a62135SXin Long if (params.assoc_id == SCTP_CURRENT_ASSOC || 417299a62135SXin Long params.assoc_id == SCTP_ALL_ASSOC) 417399a62135SXin Long list_for_each_entry(asoc, &ep->asocs, asocs) 417499a62135SXin Long asoc->strreset_enable = params.assoc_value; 41759fb657aeSXin Long 41769fb657aeSXin Long out: 41779fb657aeSXin Long return retval; 41789fb657aeSXin Long } 41799fb657aeSXin Long 41807f9d68acSXin Long static int sctp_setsockopt_reset_streams(struct sock *sk, 41817f9d68acSXin Long char __user *optval, 41827f9d68acSXin Long unsigned int optlen) 41837f9d68acSXin Long { 41847f9d68acSXin Long struct sctp_reset_streams *params; 41857f9d68acSXin Long struct sctp_association *asoc; 41867f9d68acSXin Long int retval = -EINVAL; 41877f9d68acSXin Long 41882342b8d9SXin Long if (optlen < sizeof(*params)) 41897f9d68acSXin Long return -EINVAL; 41905960cefaSMarcelo Ricardo Leitner /* srs_number_streams is u16, so optlen can't be bigger than this. */ 41915960cefaSMarcelo Ricardo Leitner optlen = min_t(unsigned int, optlen, USHRT_MAX + 41925960cefaSMarcelo Ricardo Leitner sizeof(__u16) * sizeof(*params)); 41937f9d68acSXin Long 41947f9d68acSXin Long params = memdup_user(optval, optlen); 41957f9d68acSXin Long if (IS_ERR(params)) 41967f9d68acSXin Long return PTR_ERR(params); 41977f9d68acSXin Long 41982342b8d9SXin Long if (params->srs_number_streams * sizeof(__u16) > 41992342b8d9SXin Long optlen - sizeof(*params)) 42002342b8d9SXin Long goto out; 42012342b8d9SXin Long 42027f9d68acSXin Long asoc = sctp_id2assoc(sk, params->srs_assoc_id); 42037f9d68acSXin Long if (!asoc) 42047f9d68acSXin Long goto out; 42057f9d68acSXin Long 42067f9d68acSXin Long retval = sctp_send_reset_streams(asoc, params); 42077f9d68acSXin Long 42087f9d68acSXin Long out: 42097f9d68acSXin Long kfree(params); 42107f9d68acSXin Long return retval; 42117f9d68acSXin Long } 42127f9d68acSXin Long 4213a92ce1a4SXin Long static int sctp_setsockopt_reset_assoc(struct sock *sk, 4214a92ce1a4SXin Long char __user *optval, 4215a92ce1a4SXin Long unsigned int optlen) 4216a92ce1a4SXin Long { 4217a92ce1a4SXin Long struct sctp_association *asoc; 4218a92ce1a4SXin Long sctp_assoc_t associd; 4219a92ce1a4SXin Long int retval = -EINVAL; 4220a92ce1a4SXin Long 4221a92ce1a4SXin Long if (optlen != sizeof(associd)) 4222a92ce1a4SXin Long goto out; 4223a92ce1a4SXin Long 4224a92ce1a4SXin Long if (copy_from_user(&associd, optval, optlen)) { 4225a92ce1a4SXin Long retval = -EFAULT; 4226a92ce1a4SXin Long goto out; 4227a92ce1a4SXin Long } 4228a92ce1a4SXin Long 4229a92ce1a4SXin Long asoc = sctp_id2assoc(sk, associd); 4230a92ce1a4SXin Long if (!asoc) 4231a92ce1a4SXin Long goto out; 4232a92ce1a4SXin Long 4233a92ce1a4SXin Long retval = sctp_send_reset_assoc(asoc); 4234a92ce1a4SXin Long 4235a92ce1a4SXin Long out: 4236a92ce1a4SXin Long return retval; 4237a92ce1a4SXin Long } 4238a92ce1a4SXin Long 4239242bd2d5SXin Long static int sctp_setsockopt_add_streams(struct sock *sk, 4240242bd2d5SXin Long char __user *optval, 4241242bd2d5SXin Long unsigned int optlen) 4242242bd2d5SXin Long { 4243242bd2d5SXin Long struct sctp_association *asoc; 4244242bd2d5SXin Long struct sctp_add_streams params; 4245242bd2d5SXin Long int retval = -EINVAL; 4246242bd2d5SXin Long 4247242bd2d5SXin Long if (optlen != sizeof(params)) 4248242bd2d5SXin Long goto out; 4249242bd2d5SXin Long 4250242bd2d5SXin Long if (copy_from_user(¶ms, optval, optlen)) { 4251242bd2d5SXin Long retval = -EFAULT; 4252242bd2d5SXin Long goto out; 4253242bd2d5SXin Long } 4254242bd2d5SXin Long 4255242bd2d5SXin Long asoc = sctp_id2assoc(sk, params.sas_assoc_id); 4256242bd2d5SXin Long if (!asoc) 4257242bd2d5SXin Long goto out; 4258242bd2d5SXin Long 4259242bd2d5SXin Long retval = sctp_send_add_streams(asoc, ¶ms); 4260242bd2d5SXin Long 4261242bd2d5SXin Long out: 4262242bd2d5SXin Long return retval; 4263242bd2d5SXin Long } 4264242bd2d5SXin Long 426513aa8770SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler(struct sock *sk, 426613aa8770SMarcelo Ricardo Leitner char __user *optval, 426713aa8770SMarcelo Ricardo Leitner unsigned int optlen) 426813aa8770SMarcelo Ricardo Leitner { 42697efba10dSXin Long struct sctp_sock *sp = sctp_sk(sk); 427013aa8770SMarcelo Ricardo Leitner struct sctp_association *asoc; 427113aa8770SMarcelo Ricardo Leitner struct sctp_assoc_value params; 42727efba10dSXin Long int retval = 0; 427313aa8770SMarcelo Ricardo Leitner 427413aa8770SMarcelo Ricardo Leitner if (optlen < sizeof(params)) 42757efba10dSXin Long return -EINVAL; 427613aa8770SMarcelo Ricardo Leitner 427713aa8770SMarcelo Ricardo Leitner optlen = sizeof(params); 42787efba10dSXin Long if (copy_from_user(¶ms, optval, optlen)) 42797efba10dSXin Long return -EFAULT; 428013aa8770SMarcelo Ricardo Leitner 428113aa8770SMarcelo Ricardo Leitner if (params.assoc_value > SCTP_SS_MAX) 42827efba10dSXin Long return -EINVAL; 428313aa8770SMarcelo Ricardo Leitner 428413aa8770SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 42857efba10dSXin Long if (!asoc && params.assoc_id > SCTP_ALL_ASSOC && 42867efba10dSXin Long sctp_style(sk, UDP)) 42877efba10dSXin Long return -EINVAL; 428813aa8770SMarcelo Ricardo Leitner 42897efba10dSXin Long if (asoc) 42907efba10dSXin Long return sctp_sched_set_sched(asoc, params.assoc_value); 429113aa8770SMarcelo Ricardo Leitner 4292b59c19d9SXin Long if (sctp_style(sk, TCP)) 4293b59c19d9SXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 4294b59c19d9SXin Long 42957efba10dSXin Long if (params.assoc_id == SCTP_FUTURE_ASSOC || 42967efba10dSXin Long params.assoc_id == SCTP_ALL_ASSOC) 42977efba10dSXin Long sp->default_ss = params.assoc_value; 42987efba10dSXin Long 42997efba10dSXin Long if (params.assoc_id == SCTP_CURRENT_ASSOC || 43007efba10dSXin Long params.assoc_id == SCTP_ALL_ASSOC) { 43017efba10dSXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 43027efba10dSXin Long int ret = sctp_sched_set_sched(asoc, 43037efba10dSXin Long params.assoc_value); 43047efba10dSXin Long 43057efba10dSXin Long if (ret && !retval) 43067efba10dSXin Long retval = ret; 43077efba10dSXin Long } 43087efba10dSXin Long } 43097efba10dSXin Long 431013aa8770SMarcelo Ricardo Leitner return retval; 431113aa8770SMarcelo Ricardo Leitner } 431213aa8770SMarcelo Ricardo Leitner 43130ccdf3c7SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler_value(struct sock *sk, 43140ccdf3c7SMarcelo Ricardo Leitner char __user *optval, 43150ccdf3c7SMarcelo Ricardo Leitner unsigned int optlen) 43160ccdf3c7SMarcelo Ricardo Leitner { 43170ccdf3c7SMarcelo Ricardo Leitner struct sctp_stream_value params; 4318e7f28248SXin Long struct sctp_association *asoc; 43190ccdf3c7SMarcelo Ricardo Leitner int retval = -EINVAL; 43200ccdf3c7SMarcelo Ricardo Leitner 43210ccdf3c7SMarcelo Ricardo Leitner if (optlen < sizeof(params)) 43220ccdf3c7SMarcelo Ricardo Leitner goto out; 43230ccdf3c7SMarcelo Ricardo Leitner 43240ccdf3c7SMarcelo Ricardo Leitner optlen = sizeof(params); 43250ccdf3c7SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, optlen)) { 43260ccdf3c7SMarcelo Ricardo Leitner retval = -EFAULT; 43270ccdf3c7SMarcelo Ricardo Leitner goto out; 43280ccdf3c7SMarcelo Ricardo Leitner } 43290ccdf3c7SMarcelo Ricardo Leitner 43300ccdf3c7SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 4331e7f28248SXin Long if (!asoc && params.assoc_id != SCTP_CURRENT_ASSOC && 4332e7f28248SXin Long sctp_style(sk, UDP)) 43330ccdf3c7SMarcelo Ricardo Leitner goto out; 43340ccdf3c7SMarcelo Ricardo Leitner 4335e7f28248SXin Long if (asoc) { 43360ccdf3c7SMarcelo Ricardo Leitner retval = sctp_sched_set_value(asoc, params.stream_id, 43370ccdf3c7SMarcelo Ricardo Leitner params.stream_value, GFP_KERNEL); 4338e7f28248SXin Long goto out; 4339e7f28248SXin Long } 4340e7f28248SXin Long 4341e7f28248SXin Long retval = 0; 4342e7f28248SXin Long 4343e7f28248SXin Long list_for_each_entry(asoc, &sctp_sk(sk)->ep->asocs, asocs) { 4344e7f28248SXin Long int ret = sctp_sched_set_value(asoc, params.stream_id, 4345e7f28248SXin Long params.stream_value, GFP_KERNEL); 4346e7f28248SXin Long if (ret && !retval) /* try to return the 1st error. */ 4347e7f28248SXin Long retval = ret; 4348e7f28248SXin Long } 43490ccdf3c7SMarcelo Ricardo Leitner 43500ccdf3c7SMarcelo Ricardo Leitner out: 43510ccdf3c7SMarcelo Ricardo Leitner return retval; 43520ccdf3c7SMarcelo Ricardo Leitner } 43530ccdf3c7SMarcelo Ricardo Leitner 4354772a5869SXin Long static int sctp_setsockopt_interleaving_supported(struct sock *sk, 4355772a5869SXin Long char __user *optval, 4356772a5869SXin Long unsigned int optlen) 4357772a5869SXin Long { 4358772a5869SXin Long struct sctp_sock *sp = sctp_sk(sk); 4359772a5869SXin Long struct sctp_assoc_value params; 43602e7709d1SXin Long struct sctp_association *asoc; 4361772a5869SXin Long int retval = -EINVAL; 4362772a5869SXin Long 4363772a5869SXin Long if (optlen < sizeof(params)) 4364772a5869SXin Long goto out; 4365772a5869SXin Long 4366772a5869SXin Long optlen = sizeof(params); 4367772a5869SXin Long if (copy_from_user(¶ms, optval, optlen)) { 4368772a5869SXin Long retval = -EFAULT; 4369772a5869SXin Long goto out; 4370772a5869SXin Long } 4371772a5869SXin Long 43722e7709d1SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 43732e7709d1SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 43742e7709d1SXin Long sctp_style(sk, UDP)) 4375772a5869SXin Long goto out; 4376772a5869SXin Long 43772e7709d1SXin Long if (!sock_net(sk)->sctp.intl_enable || !sp->frag_interleave) { 4378772a5869SXin Long retval = -EPERM; 4379772a5869SXin Long goto out; 4380772a5869SXin Long } 4381772a5869SXin Long 4382e55f4b8bSXin Long sp->ep->intl_enable = !!params.assoc_value; 4383772a5869SXin Long 4384772a5869SXin Long retval = 0; 4385772a5869SXin Long 4386772a5869SXin Long out: 4387772a5869SXin Long return retval; 4388772a5869SXin Long } 4389772a5869SXin Long 4390b0e9a2feSXin Long static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval, 4391b0e9a2feSXin Long unsigned int optlen) 4392b0e9a2feSXin Long { 4393b0e9a2feSXin Long int val; 4394b0e9a2feSXin Long 4395b0e9a2feSXin Long if (!sctp_style(sk, TCP)) 4396b0e9a2feSXin Long return -EOPNOTSUPP; 4397b0e9a2feSXin Long 4398b0e9a2feSXin Long if (sctp_sk(sk)->ep->base.bind_addr.port) 4399b0e9a2feSXin Long return -EFAULT; 4400b0e9a2feSXin Long 4401b0e9a2feSXin Long if (optlen < sizeof(int)) 4402b0e9a2feSXin Long return -EINVAL; 4403b0e9a2feSXin Long 4404b0e9a2feSXin Long if (get_user(val, (int __user *)optval)) 4405b0e9a2feSXin Long return -EFAULT; 4406b0e9a2feSXin Long 4407b0e9a2feSXin Long sctp_sk(sk)->reuse = !!val; 4408b0e9a2feSXin Long 4409b0e9a2feSXin Long return 0; 4410b0e9a2feSXin Long } 4411b0e9a2feSXin Long 4412d251f05eSXin Long static int sctp_assoc_ulpevent_type_set(struct sctp_event *param, 4413d251f05eSXin Long struct sctp_association *asoc) 4414480ba9c1SXin Long { 4415480ba9c1SXin Long struct sctp_ulpevent *event; 4416480ba9c1SXin Long 4417d251f05eSXin Long sctp_ulpevent_type_set(&asoc->subscribe, param->se_type, param->se_on); 4418480ba9c1SXin Long 4419d251f05eSXin Long if (param->se_type == SCTP_SENDER_DRY_EVENT && param->se_on) { 4420480ba9c1SXin Long if (sctp_outq_is_empty(&asoc->outqueue)) { 4421480ba9c1SXin Long event = sctp_ulpevent_make_sender_dry_event(asoc, 4422480ba9c1SXin Long GFP_USER | __GFP_NOWARN); 4423d251f05eSXin Long if (!event) 4424d251f05eSXin Long return -ENOMEM; 4425480ba9c1SXin Long 4426480ba9c1SXin Long asoc->stream.si->enqueue_event(&asoc->ulpq, event); 4427480ba9c1SXin Long } 4428480ba9c1SXin Long } 4429480ba9c1SXin Long 4430d251f05eSXin Long return 0; 4431d251f05eSXin Long } 4432d251f05eSXin Long 4433d251f05eSXin Long static int sctp_setsockopt_event(struct sock *sk, char __user *optval, 4434d251f05eSXin Long unsigned int optlen) 4435d251f05eSXin Long { 4436d251f05eSXin Long struct sctp_sock *sp = sctp_sk(sk); 4437d251f05eSXin Long struct sctp_association *asoc; 4438d251f05eSXin Long struct sctp_event param; 4439d251f05eSXin Long int retval = 0; 4440d251f05eSXin Long 4441d251f05eSXin Long if (optlen < sizeof(param)) 4442d251f05eSXin Long return -EINVAL; 4443d251f05eSXin Long 4444d251f05eSXin Long optlen = sizeof(param); 4445d251f05eSXin Long if (copy_from_user(¶m, optval, optlen)) 4446d251f05eSXin Long return -EFAULT; 4447d251f05eSXin Long 4448d251f05eSXin Long if (param.se_type < SCTP_SN_TYPE_BASE || 4449d251f05eSXin Long param.se_type > SCTP_SN_TYPE_MAX) 4450d251f05eSXin Long return -EINVAL; 4451d251f05eSXin Long 4452d251f05eSXin Long asoc = sctp_id2assoc(sk, param.se_assoc_id); 4453d251f05eSXin Long if (!asoc && param.se_assoc_id > SCTP_ALL_ASSOC && 4454d251f05eSXin Long sctp_style(sk, UDP)) 4455d251f05eSXin Long return -EINVAL; 4456d251f05eSXin Long 4457d251f05eSXin Long if (asoc) 4458d251f05eSXin Long return sctp_assoc_ulpevent_type_set(¶m, asoc); 4459d251f05eSXin Long 446099518619SXin Long if (sctp_style(sk, TCP)) 446199518619SXin Long param.se_assoc_id = SCTP_FUTURE_ASSOC; 446299518619SXin Long 4463d251f05eSXin Long if (param.se_assoc_id == SCTP_FUTURE_ASSOC || 4464d251f05eSXin Long param.se_assoc_id == SCTP_ALL_ASSOC) 4465d251f05eSXin Long sctp_ulpevent_type_set(&sp->subscribe, 4466d251f05eSXin Long param.se_type, param.se_on); 4467d251f05eSXin Long 4468d251f05eSXin Long if (param.se_assoc_id == SCTP_CURRENT_ASSOC || 4469d251f05eSXin Long param.se_assoc_id == SCTP_ALL_ASSOC) { 4470d251f05eSXin Long list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 4471d251f05eSXin Long int ret = sctp_assoc_ulpevent_type_set(¶m, asoc); 4472d251f05eSXin Long 4473d251f05eSXin Long if (ret && !retval) 4474d251f05eSXin Long retval = ret; 4475d251f05eSXin Long } 4476d251f05eSXin Long } 4477d251f05eSXin Long 4478480ba9c1SXin Long return retval; 4479480ba9c1SXin Long } 4480480ba9c1SXin Long 4481df2c71ffSXin Long static int sctp_setsockopt_asconf_supported(struct sock *sk, 4482df2c71ffSXin Long char __user *optval, 4483df2c71ffSXin Long unsigned int optlen) 4484df2c71ffSXin Long { 4485df2c71ffSXin Long struct sctp_assoc_value params; 4486df2c71ffSXin Long struct sctp_association *asoc; 4487df2c71ffSXin Long struct sctp_endpoint *ep; 4488df2c71ffSXin Long int retval = -EINVAL; 4489df2c71ffSXin Long 4490df2c71ffSXin Long if (optlen != sizeof(params)) 4491df2c71ffSXin Long goto out; 4492df2c71ffSXin Long 4493df2c71ffSXin Long if (copy_from_user(¶ms, optval, optlen)) { 4494df2c71ffSXin Long retval = -EFAULT; 4495df2c71ffSXin Long goto out; 4496df2c71ffSXin Long } 4497df2c71ffSXin Long 4498df2c71ffSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 4499df2c71ffSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 4500df2c71ffSXin Long sctp_style(sk, UDP)) 4501df2c71ffSXin Long goto out; 4502df2c71ffSXin Long 4503df2c71ffSXin Long ep = sctp_sk(sk)->ep; 4504df2c71ffSXin Long ep->asconf_enable = !!params.assoc_value; 4505df2c71ffSXin Long 4506df2c71ffSXin Long if (ep->asconf_enable && ep->auth_enable) { 4507df2c71ffSXin Long sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF); 4508df2c71ffSXin Long sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK); 4509df2c71ffSXin Long } 4510df2c71ffSXin Long 4511df2c71ffSXin Long retval = 0; 4512df2c71ffSXin Long 4513df2c71ffSXin Long out: 4514df2c71ffSXin Long return retval; 4515df2c71ffSXin Long } 4516df2c71ffSXin Long 451756dd525aSXin Long static int sctp_setsockopt_auth_supported(struct sock *sk, 451856dd525aSXin Long char __user *optval, 451956dd525aSXin Long unsigned int optlen) 452056dd525aSXin Long { 452156dd525aSXin Long struct sctp_assoc_value params; 452256dd525aSXin Long struct sctp_association *asoc; 452356dd525aSXin Long struct sctp_endpoint *ep; 452456dd525aSXin Long int retval = -EINVAL; 452556dd525aSXin Long 452656dd525aSXin Long if (optlen != sizeof(params)) 452756dd525aSXin Long goto out; 452856dd525aSXin Long 452956dd525aSXin Long if (copy_from_user(¶ms, optval, optlen)) { 453056dd525aSXin Long retval = -EFAULT; 453156dd525aSXin Long goto out; 453256dd525aSXin Long } 453356dd525aSXin Long 453456dd525aSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 453556dd525aSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 453656dd525aSXin Long sctp_style(sk, UDP)) 453756dd525aSXin Long goto out; 453856dd525aSXin Long 453956dd525aSXin Long ep = sctp_sk(sk)->ep; 454056dd525aSXin Long if (params.assoc_value) { 454156dd525aSXin Long retval = sctp_auth_init(ep, GFP_KERNEL); 454256dd525aSXin Long if (retval) 454356dd525aSXin Long goto out; 454456dd525aSXin Long if (ep->asconf_enable) { 454556dd525aSXin Long sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF); 454656dd525aSXin Long sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK); 454756dd525aSXin Long } 454856dd525aSXin Long } 454956dd525aSXin Long 455056dd525aSXin Long ep->auth_enable = !!params.assoc_value; 455156dd525aSXin Long retval = 0; 455256dd525aSXin Long 455356dd525aSXin Long out: 455456dd525aSXin Long return retval; 455556dd525aSXin Long } 455656dd525aSXin Long 4557d5886b91SXin Long static int sctp_setsockopt_ecn_supported(struct sock *sk, 4558d5886b91SXin Long char __user *optval, 4559d5886b91SXin Long unsigned int optlen) 4560d5886b91SXin Long { 4561d5886b91SXin Long struct sctp_assoc_value params; 4562d5886b91SXin Long struct sctp_association *asoc; 4563d5886b91SXin Long int retval = -EINVAL; 4564d5886b91SXin Long 4565d5886b91SXin Long if (optlen != sizeof(params)) 4566d5886b91SXin Long goto out; 4567d5886b91SXin Long 4568d5886b91SXin Long if (copy_from_user(¶ms, optval, optlen)) { 4569d5886b91SXin Long retval = -EFAULT; 4570d5886b91SXin Long goto out; 4571d5886b91SXin Long } 4572d5886b91SXin Long 4573d5886b91SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 4574d5886b91SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 4575d5886b91SXin Long sctp_style(sk, UDP)) 4576d5886b91SXin Long goto out; 4577d5886b91SXin Long 4578d5886b91SXin Long sctp_sk(sk)->ep->ecn_enable = !!params.assoc_value; 4579d5886b91SXin Long retval = 0; 4580d5886b91SXin Long 4581d5886b91SXin Long out: 4582d5886b91SXin Long return retval; 4583d5886b91SXin Long } 4584d5886b91SXin Long 45858d2a6935SXin Long static int sctp_setsockopt_pf_expose(struct sock *sk, 45868d2a6935SXin Long char __user *optval, 45878d2a6935SXin Long unsigned int optlen) 45888d2a6935SXin Long { 45898d2a6935SXin Long struct sctp_assoc_value params; 45908d2a6935SXin Long struct sctp_association *asoc; 45918d2a6935SXin Long int retval = -EINVAL; 45928d2a6935SXin Long 45938d2a6935SXin Long if (optlen != sizeof(params)) 45948d2a6935SXin Long goto out; 45958d2a6935SXin Long 45968d2a6935SXin Long if (copy_from_user(¶ms, optval, optlen)) { 45978d2a6935SXin Long retval = -EFAULT; 45988d2a6935SXin Long goto out; 45998d2a6935SXin Long } 46008d2a6935SXin Long 46018d2a6935SXin Long if (params.assoc_value > SCTP_PF_EXPOSE_MAX) 46028d2a6935SXin Long goto out; 46038d2a6935SXin Long 46048d2a6935SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 46058d2a6935SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 46068d2a6935SXin Long sctp_style(sk, UDP)) 46078d2a6935SXin Long goto out; 46088d2a6935SXin Long 46098d2a6935SXin Long if (asoc) 46108d2a6935SXin Long asoc->pf_expose = params.assoc_value; 46118d2a6935SXin Long else 46128d2a6935SXin Long sctp_sk(sk)->pf_expose = params.assoc_value; 46138d2a6935SXin Long retval = 0; 46148d2a6935SXin Long 46158d2a6935SXin Long out: 46168d2a6935SXin Long return retval; 46178d2a6935SXin Long } 46188d2a6935SXin Long 46191da177e4SLinus Torvalds /* API 6.2 setsockopt(), getsockopt() 46201da177e4SLinus Torvalds * 46211da177e4SLinus Torvalds * Applications use setsockopt() and getsockopt() to set or retrieve 46221da177e4SLinus Torvalds * socket options. Socket options are used to change the default 46231da177e4SLinus Torvalds * behavior of sockets calls. They are described in Section 7. 46241da177e4SLinus Torvalds * 46251da177e4SLinus Torvalds * The syntax is: 46261da177e4SLinus Torvalds * 46271da177e4SLinus Torvalds * ret = getsockopt(int sd, int level, int optname, void __user *optval, 46281da177e4SLinus Torvalds * int __user *optlen); 46291da177e4SLinus Torvalds * ret = setsockopt(int sd, int level, int optname, const void __user *optval, 46301da177e4SLinus Torvalds * int optlen); 46311da177e4SLinus Torvalds * 46321da177e4SLinus Torvalds * sd - the socket descript. 46331da177e4SLinus Torvalds * level - set to IPPROTO_SCTP for all SCTP options. 46341da177e4SLinus Torvalds * optname - the option name. 46351da177e4SLinus Torvalds * optval - the buffer to store the value of the option. 46361da177e4SLinus Torvalds * optlen - the size of the buffer. 46371da177e4SLinus Torvalds */ 4638dda91928SDaniel Borkmann static int sctp_setsockopt(struct sock *sk, int level, int optname, 4639b7058842SDavid S. Miller char __user *optval, unsigned int optlen) 46401da177e4SLinus Torvalds { 4641ca84bd05SChristoph Hellwig void *kopt = NULL; 46421da177e4SLinus Torvalds int retval = 0; 46431da177e4SLinus Torvalds 4644bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 46451da177e4SLinus Torvalds 46461da177e4SLinus Torvalds /* I can hardly begin to describe how wrong this is. This is 46471da177e4SLinus Torvalds * so broken as to be worse than useless. The API draft 46481da177e4SLinus Torvalds * REALLY is NOT helpful here... I am not convinced that the 46491da177e4SLinus Torvalds * semantics of setsockopt() with a level OTHER THAN SOL_SCTP 46501da177e4SLinus Torvalds * are at all well-founded. 46511da177e4SLinus Torvalds */ 46521da177e4SLinus Torvalds if (level != SOL_SCTP) { 46531da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 46541da177e4SLinus Torvalds retval = af->setsockopt(sk, level, optname, optval, optlen); 46551da177e4SLinus Torvalds goto out_nounlock; 46561da177e4SLinus Torvalds } 46571da177e4SLinus Torvalds 4658ca84bd05SChristoph Hellwig if (optlen > 0) { 4659ca84bd05SChristoph Hellwig kopt = memdup_user(optval, optlen); 4660ca84bd05SChristoph Hellwig if (IS_ERR(kopt)) 4661ca84bd05SChristoph Hellwig return PTR_ERR(kopt); 4662ca84bd05SChristoph Hellwig } 4663ca84bd05SChristoph Hellwig 4664048ed4b6Swangweidong lock_sock(sk); 46651da177e4SLinus Torvalds 46661da177e4SLinus Torvalds switch (optname) { 46671da177e4SLinus Torvalds case SCTP_SOCKOPT_BINDX_ADD: 46681da177e4SLinus Torvalds /* 'optlen' is the size of the addresses buffer. */ 46698c7517f5SChristoph Hellwig retval = sctp_setsockopt_bindx(sk, kopt, optlen, 46708c7517f5SChristoph Hellwig SCTP_BINDX_ADD_ADDR); 46711da177e4SLinus Torvalds break; 46721da177e4SLinus Torvalds 46731da177e4SLinus Torvalds case SCTP_SOCKOPT_BINDX_REM: 46741da177e4SLinus Torvalds /* 'optlen' is the size of the addresses buffer. */ 46758c7517f5SChristoph Hellwig retval = sctp_setsockopt_bindx(sk, kopt, optlen, 46768c7517f5SChristoph Hellwig SCTP_BINDX_REM_ADDR); 46771da177e4SLinus Torvalds break; 46781da177e4SLinus Torvalds 467988a0a948SVlad Yasevich case SCTP_SOCKOPT_CONNECTX_OLD: 468088a0a948SVlad Yasevich /* 'optlen' is the size of the addresses buffer. */ 4681ce5b2f89SChristoph Hellwig retval = sctp_setsockopt_connectx_old(sk, kopt, optlen); 468288a0a948SVlad Yasevich break; 468388a0a948SVlad Yasevich 46843f7a87d2SFrank Filz case SCTP_SOCKOPT_CONNECTX: 46853f7a87d2SFrank Filz /* 'optlen' is the size of the addresses buffer. */ 4686ce5b2f89SChristoph Hellwig retval = sctp_setsockopt_connectx(sk, kopt, optlen); 46873f7a87d2SFrank Filz break; 46883f7a87d2SFrank Filz 46891da177e4SLinus Torvalds case SCTP_DISABLE_FRAGMENTS: 469010835825SChristoph Hellwig retval = sctp_setsockopt_disable_fragments(sk, kopt, optlen); 46911da177e4SLinus Torvalds break; 46921da177e4SLinus Torvalds 46931da177e4SLinus Torvalds case SCTP_EVENTS: 4694a98d21a1SChristoph Hellwig retval = sctp_setsockopt_events(sk, kopt, optlen); 46951da177e4SLinus Torvalds break; 46961da177e4SLinus Torvalds 46971da177e4SLinus Torvalds case SCTP_AUTOCLOSE: 4698*0b49a65cSChristoph Hellwig retval = sctp_setsockopt_autoclose(sk, kopt, optlen); 46991da177e4SLinus Torvalds break; 47001da177e4SLinus Torvalds 47011da177e4SLinus Torvalds case SCTP_PEER_ADDR_PARAMS: 47021da177e4SLinus Torvalds retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen); 47031da177e4SLinus Torvalds break; 47041da177e4SLinus Torvalds 47054580ccc0SShan Wei case SCTP_DELAYED_SACK: 4706d364d927SWei Yongjun retval = sctp_setsockopt_delayed_ack(sk, optval, optlen); 47077708610bSFrank Filz break; 4708d49d91d7SVlad Yasevich case SCTP_PARTIAL_DELIVERY_POINT: 4709d49d91d7SVlad Yasevich retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen); 4710d49d91d7SVlad Yasevich break; 47117708610bSFrank Filz 47121da177e4SLinus Torvalds case SCTP_INITMSG: 47131da177e4SLinus Torvalds retval = sctp_setsockopt_initmsg(sk, optval, optlen); 47141da177e4SLinus Torvalds break; 47151da177e4SLinus Torvalds case SCTP_DEFAULT_SEND_PARAM: 47161da177e4SLinus Torvalds retval = sctp_setsockopt_default_send_param(sk, optval, 47171da177e4SLinus Torvalds optlen); 47181da177e4SLinus Torvalds break; 47196b3fd5f3SGeir Ola Vaagland case SCTP_DEFAULT_SNDINFO: 47206b3fd5f3SGeir Ola Vaagland retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen); 47216b3fd5f3SGeir Ola Vaagland break; 47221da177e4SLinus Torvalds case SCTP_PRIMARY_ADDR: 47231da177e4SLinus Torvalds retval = sctp_setsockopt_primary_addr(sk, optval, optlen); 47241da177e4SLinus Torvalds break; 47251da177e4SLinus Torvalds case SCTP_SET_PEER_PRIMARY_ADDR: 47261da177e4SLinus Torvalds retval = sctp_setsockopt_peer_primary_addr(sk, optval, optlen); 47271da177e4SLinus Torvalds break; 47281da177e4SLinus Torvalds case SCTP_NODELAY: 47291da177e4SLinus Torvalds retval = sctp_setsockopt_nodelay(sk, optval, optlen); 47301da177e4SLinus Torvalds break; 47311da177e4SLinus Torvalds case SCTP_RTOINFO: 47321da177e4SLinus Torvalds retval = sctp_setsockopt_rtoinfo(sk, optval, optlen); 47331da177e4SLinus Torvalds break; 47341da177e4SLinus Torvalds case SCTP_ASSOCINFO: 47351da177e4SLinus Torvalds retval = sctp_setsockopt_associnfo(sk, optval, optlen); 47361da177e4SLinus Torvalds break; 47371da177e4SLinus Torvalds case SCTP_I_WANT_MAPPED_V4_ADDR: 47381da177e4SLinus Torvalds retval = sctp_setsockopt_mappedv4(sk, optval, optlen); 47391da177e4SLinus Torvalds break; 47401da177e4SLinus Torvalds case SCTP_MAXSEG: 47411da177e4SLinus Torvalds retval = sctp_setsockopt_maxseg(sk, optval, optlen); 47421da177e4SLinus Torvalds break; 47430f3fffd8SIvan Skytte Jorgensen case SCTP_ADAPTATION_LAYER: 47440f3fffd8SIvan Skytte Jorgensen retval = sctp_setsockopt_adaptation_layer(sk, optval, optlen); 47451da177e4SLinus Torvalds break; 47466ab792f5SIvan Skytte Jorgensen case SCTP_CONTEXT: 47476ab792f5SIvan Skytte Jorgensen retval = sctp_setsockopt_context(sk, optval, optlen); 47486ab792f5SIvan Skytte Jorgensen break; 4749b6e1331fSVlad Yasevich case SCTP_FRAGMENT_INTERLEAVE: 4750b6e1331fSVlad Yasevich retval = sctp_setsockopt_fragment_interleave(sk, optval, optlen); 4751b6e1331fSVlad Yasevich break; 475270331571SVlad Yasevich case SCTP_MAX_BURST: 475370331571SVlad Yasevich retval = sctp_setsockopt_maxburst(sk, optval, optlen); 475470331571SVlad Yasevich break; 475565b07e5dSVlad Yasevich case SCTP_AUTH_CHUNK: 475665b07e5dSVlad Yasevich retval = sctp_setsockopt_auth_chunk(sk, optval, optlen); 475765b07e5dSVlad Yasevich break; 475865b07e5dSVlad Yasevich case SCTP_HMAC_IDENT: 475965b07e5dSVlad Yasevich retval = sctp_setsockopt_hmac_ident(sk, optval, optlen); 476065b07e5dSVlad Yasevich break; 476165b07e5dSVlad Yasevich case SCTP_AUTH_KEY: 476265b07e5dSVlad Yasevich retval = sctp_setsockopt_auth_key(sk, optval, optlen); 476365b07e5dSVlad Yasevich break; 476465b07e5dSVlad Yasevich case SCTP_AUTH_ACTIVE_KEY: 476565b07e5dSVlad Yasevich retval = sctp_setsockopt_active_key(sk, optval, optlen); 476665b07e5dSVlad Yasevich break; 476765b07e5dSVlad Yasevich case SCTP_AUTH_DELETE_KEY: 476865b07e5dSVlad Yasevich retval = sctp_setsockopt_del_key(sk, optval, optlen); 476965b07e5dSVlad Yasevich break; 4770601590ecSXin Long case SCTP_AUTH_DEACTIVATE_KEY: 4771601590ecSXin Long retval = sctp_setsockopt_deactivate_key(sk, optval, optlen); 4772601590ecSXin Long break; 47737dc04d71SMichio Honda case SCTP_AUTO_ASCONF: 47747dc04d71SMichio Honda retval = sctp_setsockopt_auto_asconf(sk, optval, optlen); 47757dc04d71SMichio Honda break; 47765aa93bcfSNeil Horman case SCTP_PEER_ADDR_THLDS: 4777d467ac0aSXin Long retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen, 4778d467ac0aSXin Long false); 4779d467ac0aSXin Long break; 4780d467ac0aSXin Long case SCTP_PEER_ADDR_THLDS_V2: 4781d467ac0aSXin Long retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen, 4782d467ac0aSXin Long true); 47835aa93bcfSNeil Horman break; 47840d3a421dSGeir Ola Vaagland case SCTP_RECVRCVINFO: 47850d3a421dSGeir Ola Vaagland retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); 47860d3a421dSGeir Ola Vaagland break; 47872347c80fSGeir Ola Vaagland case SCTP_RECVNXTINFO: 47882347c80fSGeir Ola Vaagland retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen); 47892347c80fSGeir Ola Vaagland break; 479028aa4c26SXin Long case SCTP_PR_SUPPORTED: 479128aa4c26SXin Long retval = sctp_setsockopt_pr_supported(sk, optval, optlen); 479228aa4c26SXin Long break; 4793f959fb44SXin Long case SCTP_DEFAULT_PRINFO: 4794f959fb44SXin Long retval = sctp_setsockopt_default_prinfo(sk, optval, optlen); 4795f959fb44SXin Long break; 4796c0d8bab6SXin Long case SCTP_RECONFIG_SUPPORTED: 4797c0d8bab6SXin Long retval = sctp_setsockopt_reconfig_supported(sk, optval, optlen); 4798c0d8bab6SXin Long break; 47999fb657aeSXin Long case SCTP_ENABLE_STREAM_RESET: 48009fb657aeSXin Long retval = sctp_setsockopt_enable_strreset(sk, optval, optlen); 48019fb657aeSXin Long break; 48027f9d68acSXin Long case SCTP_RESET_STREAMS: 48037f9d68acSXin Long retval = sctp_setsockopt_reset_streams(sk, optval, optlen); 48047f9d68acSXin Long break; 4805a92ce1a4SXin Long case SCTP_RESET_ASSOC: 4806a92ce1a4SXin Long retval = sctp_setsockopt_reset_assoc(sk, optval, optlen); 4807a92ce1a4SXin Long break; 4808242bd2d5SXin Long case SCTP_ADD_STREAMS: 4809242bd2d5SXin Long retval = sctp_setsockopt_add_streams(sk, optval, optlen); 4810242bd2d5SXin Long break; 481113aa8770SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER: 481213aa8770SMarcelo Ricardo Leitner retval = sctp_setsockopt_scheduler(sk, optval, optlen); 481313aa8770SMarcelo Ricardo Leitner break; 48140ccdf3c7SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER_VALUE: 48150ccdf3c7SMarcelo Ricardo Leitner retval = sctp_setsockopt_scheduler_value(sk, optval, optlen); 48160ccdf3c7SMarcelo Ricardo Leitner break; 4817772a5869SXin Long case SCTP_INTERLEAVING_SUPPORTED: 4818772a5869SXin Long retval = sctp_setsockopt_interleaving_supported(sk, optval, 4819772a5869SXin Long optlen); 4820772a5869SXin Long break; 4821b0e9a2feSXin Long case SCTP_REUSE_PORT: 4822b0e9a2feSXin Long retval = sctp_setsockopt_reuse_port(sk, optval, optlen); 4823b0e9a2feSXin Long break; 4824480ba9c1SXin Long case SCTP_EVENT: 4825480ba9c1SXin Long retval = sctp_setsockopt_event(sk, optval, optlen); 4826480ba9c1SXin Long break; 4827df2c71ffSXin Long case SCTP_ASCONF_SUPPORTED: 4828df2c71ffSXin Long retval = sctp_setsockopt_asconf_supported(sk, optval, optlen); 4829df2c71ffSXin Long break; 483056dd525aSXin Long case SCTP_AUTH_SUPPORTED: 483156dd525aSXin Long retval = sctp_setsockopt_auth_supported(sk, optval, optlen); 483256dd525aSXin Long break; 4833d5886b91SXin Long case SCTP_ECN_SUPPORTED: 4834d5886b91SXin Long retval = sctp_setsockopt_ecn_supported(sk, optval, optlen); 4835d5886b91SXin Long break; 48368d2a6935SXin Long case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: 48378d2a6935SXin Long retval = sctp_setsockopt_pf_expose(sk, optval, optlen); 48388d2a6935SXin Long break; 48391da177e4SLinus Torvalds default: 48401da177e4SLinus Torvalds retval = -ENOPROTOOPT; 48411da177e4SLinus Torvalds break; 48423ff50b79SStephen Hemminger } 48431da177e4SLinus Torvalds 4844048ed4b6Swangweidong release_sock(sk); 4845ca84bd05SChristoph Hellwig kfree(kopt); 48461da177e4SLinus Torvalds 48471da177e4SLinus Torvalds out_nounlock: 48481da177e4SLinus Torvalds return retval; 48491da177e4SLinus Torvalds } 48501da177e4SLinus Torvalds 48511da177e4SLinus Torvalds /* API 3.1.6 connect() - UDP Style Syntax 48521da177e4SLinus Torvalds * 48531da177e4SLinus Torvalds * An application may use the connect() call in the UDP model to initiate an 48541da177e4SLinus Torvalds * association without sending data. 48551da177e4SLinus Torvalds * 48561da177e4SLinus Torvalds * The syntax is: 48571da177e4SLinus Torvalds * 48581da177e4SLinus Torvalds * ret = connect(int sd, const struct sockaddr *nam, socklen_t len); 48591da177e4SLinus Torvalds * 48601da177e4SLinus Torvalds * sd: the socket descriptor to have a new association added to. 48611da177e4SLinus Torvalds * 48621da177e4SLinus Torvalds * nam: the address structure (either struct sockaddr_in or struct 48631da177e4SLinus Torvalds * sockaddr_in6 defined in RFC2553 [7]). 48641da177e4SLinus Torvalds * 48651da177e4SLinus Torvalds * len: the size of the address. 48661da177e4SLinus Torvalds */ 4867dda91928SDaniel Borkmann static int sctp_connect(struct sock *sk, struct sockaddr *addr, 4868644fbdeaSXin Long int addr_len, int flags) 48691da177e4SLinus Torvalds { 48703f7a87d2SFrank Filz struct sctp_af *af; 48719b6c0887SXin Long int err = -EINVAL; 48721da177e4SLinus Torvalds 4873048ed4b6Swangweidong lock_sock(sk); 4874bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk, 4875bb33381dSDaniel Borkmann addr, addr_len); 48761da177e4SLinus Torvalds 48773f7a87d2SFrank Filz /* Validate addr_len before calling common connect/connectx routine. */ 48789b6c0887SXin Long af = sctp_get_af_specific(addr->sa_family); 48799b6c0887SXin Long if (af && addr_len >= af->sockaddr_len) 4880644fbdeaSXin Long err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL); 48811da177e4SLinus Torvalds 4882048ed4b6Swangweidong release_sock(sk); 48831da177e4SLinus Torvalds return err; 48841da177e4SLinus Torvalds } 48851da177e4SLinus Torvalds 4886644fbdeaSXin Long int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr, 4887644fbdeaSXin Long int addr_len, int flags) 4888644fbdeaSXin Long { 4889644fbdeaSXin Long if (addr_len < sizeof(uaddr->sa_family)) 4890644fbdeaSXin Long return -EINVAL; 4891644fbdeaSXin Long 4892644fbdeaSXin Long if (uaddr->sa_family == AF_UNSPEC) 4893644fbdeaSXin Long return -EOPNOTSUPP; 4894644fbdeaSXin Long 4895644fbdeaSXin Long return sctp_connect(sock->sk, uaddr, addr_len, flags); 4896644fbdeaSXin Long } 4897644fbdeaSXin Long 48981da177e4SLinus Torvalds /* FIXME: Write comments. */ 4899dda91928SDaniel Borkmann static int sctp_disconnect(struct sock *sk, int flags) 49001da177e4SLinus Torvalds { 49011da177e4SLinus Torvalds return -EOPNOTSUPP; /* STUB */ 49021da177e4SLinus Torvalds } 49031da177e4SLinus Torvalds 49041da177e4SLinus Torvalds /* 4.1.4 accept() - TCP Style Syntax 49051da177e4SLinus Torvalds * 49061da177e4SLinus Torvalds * Applications use accept() call to remove an established SCTP 49071da177e4SLinus Torvalds * association from the accept queue of the endpoint. A new socket 49081da177e4SLinus Torvalds * descriptor will be returned from accept() to represent the newly 49091da177e4SLinus Torvalds * formed association. 49101da177e4SLinus Torvalds */ 4911cdfbabfbSDavid Howells static struct sock *sctp_accept(struct sock *sk, int flags, int *err, bool kern) 49121da177e4SLinus Torvalds { 49131da177e4SLinus Torvalds struct sctp_sock *sp; 49141da177e4SLinus Torvalds struct sctp_endpoint *ep; 49151da177e4SLinus Torvalds struct sock *newsk = NULL; 49161da177e4SLinus Torvalds struct sctp_association *asoc; 49171da177e4SLinus Torvalds long timeo; 49181da177e4SLinus Torvalds int error = 0; 49191da177e4SLinus Torvalds 4920048ed4b6Swangweidong lock_sock(sk); 49211da177e4SLinus Torvalds 49221da177e4SLinus Torvalds sp = sctp_sk(sk); 49231da177e4SLinus Torvalds ep = sp->ep; 49241da177e4SLinus Torvalds 49251da177e4SLinus Torvalds if (!sctp_style(sk, TCP)) { 49261da177e4SLinus Torvalds error = -EOPNOTSUPP; 49271da177e4SLinus Torvalds goto out; 49281da177e4SLinus Torvalds } 49291da177e4SLinus Torvalds 49301da177e4SLinus Torvalds if (!sctp_sstate(sk, LISTENING)) { 49311da177e4SLinus Torvalds error = -EINVAL; 49321da177e4SLinus Torvalds goto out; 49331da177e4SLinus Torvalds } 49341da177e4SLinus Torvalds 49358abfedd8SSridhar Samudrala timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 49361da177e4SLinus Torvalds 49371da177e4SLinus Torvalds error = sctp_wait_for_accept(sk, timeo); 49381da177e4SLinus Torvalds if (error) 49391da177e4SLinus Torvalds goto out; 49401da177e4SLinus Torvalds 49411da177e4SLinus Torvalds /* We treat the list of associations on the endpoint as the accept 49421da177e4SLinus Torvalds * queue and pick the first association on the list. 49431da177e4SLinus Torvalds */ 49441da177e4SLinus Torvalds asoc = list_entry(ep->asocs.next, struct sctp_association, asocs); 49451da177e4SLinus Torvalds 4946cdfbabfbSDavid Howells newsk = sp->pf->create_accept_sk(sk, asoc, kern); 49471da177e4SLinus Torvalds if (!newsk) { 49481da177e4SLinus Torvalds error = -ENOMEM; 49491da177e4SLinus Torvalds goto out; 49501da177e4SLinus Torvalds } 49511da177e4SLinus Torvalds 49521da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the 49531da177e4SLinus Torvalds * asoc to the newsk. 49541da177e4SLinus Torvalds */ 495589664c62SXin Long error = sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); 495689664c62SXin Long if (error) { 495789664c62SXin Long sk_common_release(newsk); 495889664c62SXin Long newsk = NULL; 495989664c62SXin Long } 49601da177e4SLinus Torvalds 49611da177e4SLinus Torvalds out: 4962048ed4b6Swangweidong release_sock(sk); 49631da177e4SLinus Torvalds *err = error; 49641da177e4SLinus Torvalds return newsk; 49651da177e4SLinus Torvalds } 49661da177e4SLinus Torvalds 49671da177e4SLinus Torvalds /* The SCTP ioctl handler. */ 4968dda91928SDaniel Borkmann static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) 49691da177e4SLinus Torvalds { 497065040c33SDiego Elio 'Flameeyes' Pettenò int rc = -ENOTCONN; 497165040c33SDiego Elio 'Flameeyes' Pettenò 4972048ed4b6Swangweidong lock_sock(sk); 497365040c33SDiego Elio 'Flameeyes' Pettenò 497465040c33SDiego Elio 'Flameeyes' Pettenò /* 497565040c33SDiego Elio 'Flameeyes' Pettenò * SEQPACKET-style sockets in LISTENING state are valid, for 497665040c33SDiego Elio 'Flameeyes' Pettenò * SCTP, so only discard TCP-style sockets in LISTENING state. 497765040c33SDiego Elio 'Flameeyes' Pettenò */ 497865040c33SDiego Elio 'Flameeyes' Pettenò if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 497965040c33SDiego Elio 'Flameeyes' Pettenò goto out; 498065040c33SDiego Elio 'Flameeyes' Pettenò 498165040c33SDiego Elio 'Flameeyes' Pettenò switch (cmd) { 498265040c33SDiego Elio 'Flameeyes' Pettenò case SIOCINQ: { 498365040c33SDiego Elio 'Flameeyes' Pettenò struct sk_buff *skb; 498465040c33SDiego Elio 'Flameeyes' Pettenò unsigned int amount = 0; 498565040c33SDiego Elio 'Flameeyes' Pettenò 498665040c33SDiego Elio 'Flameeyes' Pettenò skb = skb_peek(&sk->sk_receive_queue); 498765040c33SDiego Elio 'Flameeyes' Pettenò if (skb != NULL) { 498865040c33SDiego Elio 'Flameeyes' Pettenò /* 498965040c33SDiego Elio 'Flameeyes' Pettenò * We will only return the amount of this packet since 499065040c33SDiego Elio 'Flameeyes' Pettenò * that is all that will be read. 499165040c33SDiego Elio 'Flameeyes' Pettenò */ 499265040c33SDiego Elio 'Flameeyes' Pettenò amount = skb->len; 499365040c33SDiego Elio 'Flameeyes' Pettenò } 499465040c33SDiego Elio 'Flameeyes' Pettenò rc = put_user(amount, (int __user *)arg); 499565040c33SDiego Elio 'Flameeyes' Pettenò break; 49969a7241c2SDavid S. Miller } 499765040c33SDiego Elio 'Flameeyes' Pettenò default: 499865040c33SDiego Elio 'Flameeyes' Pettenò rc = -ENOIOCTLCMD; 499965040c33SDiego Elio 'Flameeyes' Pettenò break; 500065040c33SDiego Elio 'Flameeyes' Pettenò } 500165040c33SDiego Elio 'Flameeyes' Pettenò out: 5002048ed4b6Swangweidong release_sock(sk); 500365040c33SDiego Elio 'Flameeyes' Pettenò return rc; 50041da177e4SLinus Torvalds } 50051da177e4SLinus Torvalds 50061da177e4SLinus Torvalds /* This is the function which gets called during socket creation to 50071da177e4SLinus Torvalds * initialized the SCTP-specific portion of the sock. 50081da177e4SLinus Torvalds * The sock structure should already be zero-filled memory. 50091da177e4SLinus Torvalds */ 5010dda91928SDaniel Borkmann static int sctp_init_sock(struct sock *sk) 50111da177e4SLinus Torvalds { 5012e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 50131da177e4SLinus Torvalds struct sctp_sock *sp; 50141da177e4SLinus Torvalds 5015bb33381dSDaniel Borkmann pr_debug("%s: sk:%p\n", __func__, sk); 50161da177e4SLinus Torvalds 50171da177e4SLinus Torvalds sp = sctp_sk(sk); 50181da177e4SLinus Torvalds 50191da177e4SLinus Torvalds /* Initialize the SCTP per socket area. */ 50201da177e4SLinus Torvalds switch (sk->sk_type) { 50211da177e4SLinus Torvalds case SOCK_SEQPACKET: 50221da177e4SLinus Torvalds sp->type = SCTP_SOCKET_UDP; 50231da177e4SLinus Torvalds break; 50241da177e4SLinus Torvalds case SOCK_STREAM: 50251da177e4SLinus Torvalds sp->type = SCTP_SOCKET_TCP; 50261da177e4SLinus Torvalds break; 50271da177e4SLinus Torvalds default: 50281da177e4SLinus Torvalds return -ESOCKTNOSUPPORT; 50291da177e4SLinus Torvalds } 50301da177e4SLinus Torvalds 503190017accSMarcelo Ricardo Leitner sk->sk_gso_type = SKB_GSO_SCTP; 503290017accSMarcelo Ricardo Leitner 50331da177e4SLinus Torvalds /* Initialize default send parameters. These parameters can be 50341da177e4SLinus Torvalds * modified with the SCTP_DEFAULT_SEND_PARAM socket option. 50351da177e4SLinus Torvalds */ 50361da177e4SLinus Torvalds sp->default_stream = 0; 50371da177e4SLinus Torvalds sp->default_ppid = 0; 50381da177e4SLinus Torvalds sp->default_flags = 0; 50391da177e4SLinus Torvalds sp->default_context = 0; 50401da177e4SLinus Torvalds sp->default_timetolive = 0; 50411da177e4SLinus Torvalds 50426ab792f5SIvan Skytte Jorgensen sp->default_rcv_context = 0; 5043e1fc3b14SEric W. Biederman sp->max_burst = net->sctp.max_burst; 50446ab792f5SIvan Skytte Jorgensen 50453c68198eSNeil Horman sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg; 50463c68198eSNeil Horman 50471da177e4SLinus Torvalds /* Initialize default setup parameters. These parameters 50481da177e4SLinus Torvalds * can be modified with the SCTP_INITMSG socket option or 50491da177e4SLinus Torvalds * overridden by the SCTP_INIT CMSG. 50501da177e4SLinus Torvalds */ 50511da177e4SLinus Torvalds sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; 50521da177e4SLinus Torvalds sp->initmsg.sinit_max_instreams = sctp_max_instreams; 5053e1fc3b14SEric W. Biederman sp->initmsg.sinit_max_attempts = net->sctp.max_retrans_init; 5054e1fc3b14SEric W. Biederman sp->initmsg.sinit_max_init_timeo = net->sctp.rto_max; 50551da177e4SLinus Torvalds 50561da177e4SLinus Torvalds /* Initialize default RTO related parameters. These parameters can 50571da177e4SLinus Torvalds * be modified for with the SCTP_RTOINFO socket option. 50581da177e4SLinus Torvalds */ 5059e1fc3b14SEric W. Biederman sp->rtoinfo.srto_initial = net->sctp.rto_initial; 5060e1fc3b14SEric W. Biederman sp->rtoinfo.srto_max = net->sctp.rto_max; 5061e1fc3b14SEric W. Biederman sp->rtoinfo.srto_min = net->sctp.rto_min; 50621da177e4SLinus Torvalds 50631da177e4SLinus Torvalds /* Initialize default association related parameters. These parameters 50641da177e4SLinus Torvalds * can be modified with the SCTP_ASSOCINFO socket option. 50651da177e4SLinus Torvalds */ 5066e1fc3b14SEric W. Biederman sp->assocparams.sasoc_asocmaxrxt = net->sctp.max_retrans_association; 50671da177e4SLinus Torvalds sp->assocparams.sasoc_number_peer_destinations = 0; 50681da177e4SLinus Torvalds sp->assocparams.sasoc_peer_rwnd = 0; 50691da177e4SLinus Torvalds sp->assocparams.sasoc_local_rwnd = 0; 5070e1fc3b14SEric W. Biederman sp->assocparams.sasoc_cookie_life = net->sctp.valid_cookie_life; 50711da177e4SLinus Torvalds 50721da177e4SLinus Torvalds /* Initialize default event subscriptions. By default, all the 50731da177e4SLinus Torvalds * options are off. 50741da177e4SLinus Torvalds */ 50752cc0eeb6SXin Long sp->subscribe = 0; 50761da177e4SLinus Torvalds 50771da177e4SLinus Torvalds /* Default Peer Address Parameters. These defaults can 50781da177e4SLinus Torvalds * be modified via SCTP_PEER_ADDR_PARAMS 50791da177e4SLinus Torvalds */ 5080e1fc3b14SEric W. Biederman sp->hbinterval = net->sctp.hb_interval; 5081e1fc3b14SEric W. Biederman sp->pathmaxrxt = net->sctp.max_retrans_path; 50828add543eSXin Long sp->pf_retrans = net->sctp.pf_retrans; 508334515e94SXin Long sp->ps_retrans = net->sctp.ps_retrans; 5084aef587beSXin Long sp->pf_expose = net->sctp.pf_expose; 50854e2d52bfSwangweidong sp->pathmtu = 0; /* allow default discovery */ 5086e1fc3b14SEric W. Biederman sp->sackdelay = net->sctp.sack_timeout; 50877bfe8bdbSVlad Yasevich sp->sackfreq = 2; 508852ccb8e9SFrank Filz sp->param_flags = SPP_HB_ENABLE | 508952ccb8e9SFrank Filz SPP_PMTUD_ENABLE | 509052ccb8e9SFrank Filz SPP_SACKDELAY_ENABLE; 50917efba10dSXin Long sp->default_ss = SCTP_SS_DEFAULT; 50921da177e4SLinus Torvalds 50931da177e4SLinus Torvalds /* If enabled no SCTP message fragmentation will be performed. 50941da177e4SLinus Torvalds * Configure through SCTP_DISABLE_FRAGMENTS socket option. 50951da177e4SLinus Torvalds */ 50961da177e4SLinus Torvalds sp->disable_fragments = 0; 50971da177e4SLinus Torvalds 5098208edef6SSridhar Samudrala /* Enable Nagle algorithm by default. */ 5099208edef6SSridhar Samudrala sp->nodelay = 0; 51001da177e4SLinus Torvalds 51010d3a421dSGeir Ola Vaagland sp->recvrcvinfo = 0; 51022347c80fSGeir Ola Vaagland sp->recvnxtinfo = 0; 51030d3a421dSGeir Ola Vaagland 51041da177e4SLinus Torvalds /* Enable by default. */ 51051da177e4SLinus Torvalds sp->v4mapped = 1; 51061da177e4SLinus Torvalds 51071da177e4SLinus Torvalds /* Auto-close idle associations after the configured 51081da177e4SLinus Torvalds * number of seconds. A value of 0 disables this 51091da177e4SLinus Torvalds * feature. Configure through the SCTP_AUTOCLOSE socket option, 51101da177e4SLinus Torvalds * for UDP-style sockets only. 51111da177e4SLinus Torvalds */ 51121da177e4SLinus Torvalds sp->autoclose = 0; 51131da177e4SLinus Torvalds 51141da177e4SLinus Torvalds /* User specified fragmentation limit. */ 51151da177e4SLinus Torvalds sp->user_frag = 0; 51161da177e4SLinus Torvalds 51170f3fffd8SIvan Skytte Jorgensen sp->adaptation_ind = 0; 51181da177e4SLinus Torvalds 51191da177e4SLinus Torvalds sp->pf = sctp_get_pf_specific(sk->sk_family); 51201da177e4SLinus Torvalds 51211da177e4SLinus Torvalds /* Control variables for partial data delivery. */ 5122b6e1331fSVlad Yasevich atomic_set(&sp->pd_mode, 0); 51231da177e4SLinus Torvalds skb_queue_head_init(&sp->pd_lobby); 5124b6e1331fSVlad Yasevich sp->frag_interleave = 0; 51251da177e4SLinus Torvalds 51261da177e4SLinus Torvalds /* Create a per socket endpoint structure. Even if we 51271da177e4SLinus Torvalds * change the data structure relationships, this may still 51281da177e4SLinus Torvalds * be useful for storing pre-connect address information. 51291da177e4SLinus Torvalds */ 5130c164b838SDaniel Borkmann sp->ep = sctp_endpoint_new(sk, GFP_KERNEL); 5131c164b838SDaniel Borkmann if (!sp->ep) 51321da177e4SLinus Torvalds return -ENOMEM; 51331da177e4SLinus Torvalds 51341da177e4SLinus Torvalds sp->hmac = NULL; 51351da177e4SLinus Torvalds 51360a2fbac1SDaniel Borkmann sk->sk_destruct = sctp_destruct_sock; 51370a2fbac1SDaniel Borkmann 51381da177e4SLinus Torvalds SCTP_DBG_OBJCNT_INC(sock); 51396f756a8cSDavid S. Miller 51406f756a8cSDavid S. Miller local_bh_disable(); 51418cb38a60STonghao Zhang sk_sockets_allocated_inc(sk); 5142e1fc3b14SEric W. Biederman sock_prot_inuse_add(net, sk->sk_prot, 1); 51432d45a02dSMarcelo Ricardo Leitner 51442d45a02dSMarcelo Ricardo Leitner /* Nothing can fail after this block, otherwise 51452d45a02dSMarcelo Ricardo Leitner * sctp_destroy_sock() will be called without addr_wq_lock held 51462d45a02dSMarcelo Ricardo Leitner */ 5147e1fc3b14SEric W. Biederman if (net->sctp.default_auto_asconf) { 51482d45a02dSMarcelo Ricardo Leitner spin_lock(&sock_net(sk)->sctp.addr_wq_lock); 51499f7d653bSMichio Honda list_add_tail(&sp->auto_asconf_list, 5150e1fc3b14SEric W. Biederman &net->sctp.auto_asconf_splist); 51519f7d653bSMichio Honda sp->do_auto_asconf = 1; 51522d45a02dSMarcelo Ricardo Leitner spin_unlock(&sock_net(sk)->sctp.addr_wq_lock); 51532d45a02dSMarcelo Ricardo Leitner } else { 51549f7d653bSMichio Honda sp->do_auto_asconf = 0; 51552d45a02dSMarcelo Ricardo Leitner } 51562d45a02dSMarcelo Ricardo Leitner 51576f756a8cSDavid S. Miller local_bh_enable(); 51586f756a8cSDavid S. Miller 51591da177e4SLinus Torvalds return 0; 51601da177e4SLinus Torvalds } 51611da177e4SLinus Torvalds 51622d45a02dSMarcelo Ricardo Leitner /* Cleanup any SCTP per socket resources. Must be called with 51632d45a02dSMarcelo Ricardo Leitner * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true 51642d45a02dSMarcelo Ricardo Leitner */ 5165dda91928SDaniel Borkmann static void sctp_destroy_sock(struct sock *sk) 51661da177e4SLinus Torvalds { 51679f7d653bSMichio Honda struct sctp_sock *sp; 51681da177e4SLinus Torvalds 5169bb33381dSDaniel Borkmann pr_debug("%s: sk:%p\n", __func__, sk); 51701da177e4SLinus Torvalds 51711da177e4SLinus Torvalds /* Release our hold on the endpoint. */ 51729f7d653bSMichio Honda sp = sctp_sk(sk); 51731abd165eSDaniel Borkmann /* This could happen during socket init, thus we bail out 51741abd165eSDaniel Borkmann * early, since the rest of the below is not setup either. 51751abd165eSDaniel Borkmann */ 51761abd165eSDaniel Borkmann if (sp->ep == NULL) 51771abd165eSDaniel Borkmann return; 51781abd165eSDaniel Borkmann 51799f7d653bSMichio Honda if (sp->do_auto_asconf) { 51809f7d653bSMichio Honda sp->do_auto_asconf = 0; 51819f7d653bSMichio Honda list_del(&sp->auto_asconf_list); 51829f7d653bSMichio Honda } 51839f7d653bSMichio Honda sctp_endpoint_free(sp->ep); 51845bc0b3bfSEric Dumazet local_bh_disable(); 51858cb38a60STonghao Zhang sk_sockets_allocated_dec(sk); 51869a57f7faSEric Dumazet sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 51875bc0b3bfSEric Dumazet local_bh_enable(); 51881da177e4SLinus Torvalds } 51891da177e4SLinus Torvalds 51900a2fbac1SDaniel Borkmann /* Triggered when there are no references on the socket anymore */ 51910a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk) 51920a2fbac1SDaniel Borkmann { 51930a2fbac1SDaniel Borkmann struct sctp_sock *sp = sctp_sk(sk); 51940a2fbac1SDaniel Borkmann 51950a2fbac1SDaniel Borkmann /* Free up the HMAC transform. */ 51965821c769SHerbert Xu crypto_free_shash(sp->hmac); 51970a2fbac1SDaniel Borkmann 51980a2fbac1SDaniel Borkmann inet_sock_destruct(sk); 51990a2fbac1SDaniel Borkmann } 52000a2fbac1SDaniel Borkmann 52011da177e4SLinus Torvalds /* API 4.1.7 shutdown() - TCP Style Syntax 52021da177e4SLinus Torvalds * int shutdown(int socket, int how); 52031da177e4SLinus Torvalds * 52041da177e4SLinus Torvalds * sd - the socket descriptor of the association to be closed. 52051da177e4SLinus Torvalds * how - Specifies the type of shutdown. The values are 52061da177e4SLinus Torvalds * as follows: 52071da177e4SLinus Torvalds * SHUT_RD 52081da177e4SLinus Torvalds * Disables further receive operations. No SCTP 52091da177e4SLinus Torvalds * protocol action is taken. 52101da177e4SLinus Torvalds * SHUT_WR 52111da177e4SLinus Torvalds * Disables further send operations, and initiates 52121da177e4SLinus Torvalds * the SCTP shutdown sequence. 52131da177e4SLinus Torvalds * SHUT_RDWR 52141da177e4SLinus Torvalds * Disables further send and receive operations 52151da177e4SLinus Torvalds * and initiates the SCTP shutdown sequence. 52161da177e4SLinus Torvalds */ 5217dda91928SDaniel Borkmann static void sctp_shutdown(struct sock *sk, int how) 52181da177e4SLinus Torvalds { 521955e26eb9SEric W. Biederman struct net *net = sock_net(sk); 52201da177e4SLinus Torvalds struct sctp_endpoint *ep; 52211da177e4SLinus Torvalds 52221da177e4SLinus Torvalds if (!sctp_style(sk, TCP)) 52231da177e4SLinus Torvalds return; 52241da177e4SLinus Torvalds 52251da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 52265bf35ddfSXin Long if (how & SEND_SHUTDOWN && !list_empty(&ep->asocs)) { 52275bf35ddfSXin Long struct sctp_association *asoc; 52285bf35ddfSXin Long 5229cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_CLOSING); 52301da177e4SLinus Torvalds asoc = list_entry(ep->asocs.next, 52311da177e4SLinus Torvalds struct sctp_association, asocs); 523255e26eb9SEric W. Biederman sctp_primitive_SHUTDOWN(net, asoc, NULL); 52331da177e4SLinus Torvalds } 52341da177e4SLinus Torvalds } 52351da177e4SLinus Torvalds 523652c52a61SXin Long int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, 523752c52a61SXin Long struct sctp_info *info) 523852c52a61SXin Long { 523952c52a61SXin Long struct sctp_transport *prim; 524052c52a61SXin Long struct list_head *pos; 524152c52a61SXin Long int mask; 524252c52a61SXin Long 524352c52a61SXin Long memset(info, 0, sizeof(*info)); 524452c52a61SXin Long if (!asoc) { 524552c52a61SXin Long struct sctp_sock *sp = sctp_sk(sk); 524652c52a61SXin Long 524752c52a61SXin Long info->sctpi_s_autoclose = sp->autoclose; 524852c52a61SXin Long info->sctpi_s_adaptation_ind = sp->adaptation_ind; 524952c52a61SXin Long info->sctpi_s_pd_point = sp->pd_point; 525052c52a61SXin Long info->sctpi_s_nodelay = sp->nodelay; 525152c52a61SXin Long info->sctpi_s_disable_fragments = sp->disable_fragments; 525252c52a61SXin Long info->sctpi_s_v4mapped = sp->v4mapped; 525352c52a61SXin Long info->sctpi_s_frag_interleave = sp->frag_interleave; 525440eb90e9SXin Long info->sctpi_s_type = sp->type; 525552c52a61SXin Long 525652c52a61SXin Long return 0; 525752c52a61SXin Long } 525852c52a61SXin Long 525952c52a61SXin Long info->sctpi_tag = asoc->c.my_vtag; 526052c52a61SXin Long info->sctpi_state = asoc->state; 526152c52a61SXin Long info->sctpi_rwnd = asoc->a_rwnd; 526252c52a61SXin Long info->sctpi_unackdata = asoc->unack_data; 526352c52a61SXin Long info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 5264cee360abSXin Long info->sctpi_instrms = asoc->stream.incnt; 5265cee360abSXin Long info->sctpi_outstrms = asoc->stream.outcnt; 526652c52a61SXin Long list_for_each(pos, &asoc->base.inqueue.in_chunk_list) 526752c52a61SXin Long info->sctpi_inqueue++; 526852c52a61SXin Long list_for_each(pos, &asoc->outqueue.out_chunk_list) 526952c52a61SXin Long info->sctpi_outqueue++; 527052c52a61SXin Long info->sctpi_overall_error = asoc->overall_error_count; 527152c52a61SXin Long info->sctpi_max_burst = asoc->max_burst; 527252c52a61SXin Long info->sctpi_maxseg = asoc->frag_point; 527352c52a61SXin Long info->sctpi_peer_rwnd = asoc->peer.rwnd; 527452c52a61SXin Long info->sctpi_peer_tag = asoc->c.peer_vtag; 527552c52a61SXin Long 527652c52a61SXin Long mask = asoc->peer.ecn_capable << 1; 527752c52a61SXin Long mask = (mask | asoc->peer.ipv4_address) << 1; 527852c52a61SXin Long mask = (mask | asoc->peer.ipv6_address) << 1; 527952c52a61SXin Long mask = (mask | asoc->peer.hostname_address) << 1; 528052c52a61SXin Long mask = (mask | asoc->peer.asconf_capable) << 1; 528152c52a61SXin Long mask = (mask | asoc->peer.prsctp_capable) << 1; 528252c52a61SXin Long mask = (mask | asoc->peer.auth_capable); 528352c52a61SXin Long info->sctpi_peer_capable = mask; 528452c52a61SXin Long mask = asoc->peer.sack_needed << 1; 528552c52a61SXin Long mask = (mask | asoc->peer.sack_generation) << 1; 528652c52a61SXin Long mask = (mask | asoc->peer.zero_window_announced); 528752c52a61SXin Long info->sctpi_peer_sack = mask; 528852c52a61SXin Long 528952c52a61SXin Long info->sctpi_isacks = asoc->stats.isacks; 529052c52a61SXin Long info->sctpi_osacks = asoc->stats.osacks; 529152c52a61SXin Long info->sctpi_opackets = asoc->stats.opackets; 529252c52a61SXin Long info->sctpi_ipackets = asoc->stats.ipackets; 529352c52a61SXin Long info->sctpi_rtxchunks = asoc->stats.rtxchunks; 529452c52a61SXin Long info->sctpi_outofseqtsns = asoc->stats.outofseqtsns; 529552c52a61SXin Long info->sctpi_idupchunks = asoc->stats.idupchunks; 529652c52a61SXin Long info->sctpi_gapcnt = asoc->stats.gapcnt; 529752c52a61SXin Long info->sctpi_ouodchunks = asoc->stats.ouodchunks; 529852c52a61SXin Long info->sctpi_iuodchunks = asoc->stats.iuodchunks; 529952c52a61SXin Long info->sctpi_oodchunks = asoc->stats.oodchunks; 530052c52a61SXin Long info->sctpi_iodchunks = asoc->stats.iodchunks; 530152c52a61SXin Long info->sctpi_octrlchunks = asoc->stats.octrlchunks; 530252c52a61SXin Long info->sctpi_ictrlchunks = asoc->stats.ictrlchunks; 530352c52a61SXin Long 530452c52a61SXin Long prim = asoc->peer.primary_path; 5305ee6c88bbSStefano Brivio memcpy(&info->sctpi_p_address, &prim->ipaddr, sizeof(prim->ipaddr)); 530652c52a61SXin Long info->sctpi_p_state = prim->state; 530752c52a61SXin Long info->sctpi_p_cwnd = prim->cwnd; 530852c52a61SXin Long info->sctpi_p_srtt = prim->srtt; 530952c52a61SXin Long info->sctpi_p_rto = jiffies_to_msecs(prim->rto); 531052c52a61SXin Long info->sctpi_p_hbinterval = prim->hbinterval; 531152c52a61SXin Long info->sctpi_p_pathmaxrxt = prim->pathmaxrxt; 531252c52a61SXin Long info->sctpi_p_sackdelay = jiffies_to_msecs(prim->sackdelay); 531352c52a61SXin Long info->sctpi_p_ssthresh = prim->ssthresh; 531452c52a61SXin Long info->sctpi_p_partial_bytes_acked = prim->partial_bytes_acked; 531552c52a61SXin Long info->sctpi_p_flight_size = prim->flight_size; 531652c52a61SXin Long info->sctpi_p_error = prim->error_count; 531752c52a61SXin Long 531852c52a61SXin Long return 0; 531952c52a61SXin Long } 532052c52a61SXin Long EXPORT_SYMBOL_GPL(sctp_get_sctp_info); 532152c52a61SXin Long 5322626d16f5SXin Long /* use callback to avoid exporting the core structure */ 53236c72b774SJules Irenge void sctp_transport_walk_start(struct rhashtable_iter *iter) __acquires(RCU) 5324626d16f5SXin Long { 53257fda702fSXin Long rhltable_walk_enter(&sctp_transport_hashtable, iter); 5326626d16f5SXin Long 532797a6ec4aSTom Herbert rhashtable_walk_start(iter); 5328626d16f5SXin Long } 5329626d16f5SXin Long 5330b77b4f63SJules Irenge void sctp_transport_walk_stop(struct rhashtable_iter *iter) __releases(RCU) 5331626d16f5SXin Long { 5332626d16f5SXin Long rhashtable_walk_stop(iter); 5333626d16f5SXin Long rhashtable_walk_exit(iter); 5334626d16f5SXin Long } 5335626d16f5SXin Long 5336626d16f5SXin Long struct sctp_transport *sctp_transport_get_next(struct net *net, 5337626d16f5SXin Long struct rhashtable_iter *iter) 5338626d16f5SXin Long { 5339626d16f5SXin Long struct sctp_transport *t; 5340626d16f5SXin Long 5341626d16f5SXin Long t = rhashtable_walk_next(iter); 5342626d16f5SXin Long for (; t; t = rhashtable_walk_next(iter)) { 5343626d16f5SXin Long if (IS_ERR(t)) { 5344626d16f5SXin Long if (PTR_ERR(t) == -EAGAIN) 5345626d16f5SXin Long continue; 5346626d16f5SXin Long break; 5347626d16f5SXin Long } 5348626d16f5SXin Long 5349bab1be79SXin Long if (!sctp_transport_hold(t)) 5350bab1be79SXin Long continue; 5351bab1be79SXin Long 53524e7696d9SXin Long if (net_eq(t->asoc->base.net, net) && 5353626d16f5SXin Long t->asoc->peer.primary_path == t) 5354626d16f5SXin Long break; 5355bab1be79SXin Long 5356bab1be79SXin Long sctp_transport_put(t); 5357626d16f5SXin Long } 5358626d16f5SXin Long 5359626d16f5SXin Long return t; 5360626d16f5SXin Long } 5361626d16f5SXin Long 5362626d16f5SXin Long struct sctp_transport *sctp_transport_get_idx(struct net *net, 5363626d16f5SXin Long struct rhashtable_iter *iter, 5364626d16f5SXin Long int pos) 5365626d16f5SXin Long { 5366bab1be79SXin Long struct sctp_transport *t; 5367626d16f5SXin Long 5368bab1be79SXin Long if (!pos) 5369bab1be79SXin Long return SEQ_START_TOKEN; 5370626d16f5SXin Long 5371bab1be79SXin Long while ((t = sctp_transport_get_next(net, iter)) && !IS_ERR(t)) { 5372bab1be79SXin Long if (!--pos) 5373bab1be79SXin Long break; 5374bab1be79SXin Long sctp_transport_put(t); 5375bab1be79SXin Long } 5376bab1be79SXin Long 5377bab1be79SXin Long return t; 5378626d16f5SXin Long } 5379626d16f5SXin Long 5380626d16f5SXin Long int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), 5381626d16f5SXin Long void *p) { 5382626d16f5SXin Long int err = 0; 5383626d16f5SXin Long int hash = 0; 5384626d16f5SXin Long struct sctp_ep_common *epb; 5385626d16f5SXin Long struct sctp_hashbucket *head; 5386626d16f5SXin Long 5387626d16f5SXin Long for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize; 5388626d16f5SXin Long hash++, head++) { 5389581409daSXin Long read_lock_bh(&head->lock); 5390626d16f5SXin Long sctp_for_each_hentry(epb, &head->chain) { 5391626d16f5SXin Long err = cb(sctp_ep(epb), p); 5392626d16f5SXin Long if (err) 5393626d16f5SXin Long break; 5394626d16f5SXin Long } 5395581409daSXin Long read_unlock_bh(&head->lock); 5396626d16f5SXin Long } 5397626d16f5SXin Long 5398626d16f5SXin Long return err; 5399626d16f5SXin Long } 5400626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_for_each_endpoint); 5401626d16f5SXin Long 5402626d16f5SXin Long int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *), 5403626d16f5SXin Long struct net *net, 5404626d16f5SXin Long const union sctp_addr *laddr, 5405626d16f5SXin Long const union sctp_addr *paddr, void *p) 5406626d16f5SXin Long { 5407626d16f5SXin Long struct sctp_transport *transport; 540808abb795SXin Long int err; 5409626d16f5SXin Long 5410626d16f5SXin Long rcu_read_lock(); 5411626d16f5SXin Long transport = sctp_addrs_lookup_transport(net, laddr, paddr); 5412626d16f5SXin Long rcu_read_unlock(); 541308abb795SXin Long if (!transport) 541408abb795SXin Long return -ENOENT; 541508abb795SXin Long 54161cceda78SXin Long err = cb(transport, p); 5417cd26da4fSXin Long sctp_transport_put(transport); 54181cceda78SXin Long 5419626d16f5SXin Long return err; 5420626d16f5SXin Long } 5421626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_transport_lookup_process); 5422626d16f5SXin Long 5423626d16f5SXin Long int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *), 5424d25adbebSXin Long int (*cb_done)(struct sctp_transport *, void *), 5425d25adbebSXin Long struct net *net, int *pos, void *p) { 5426626d16f5SXin Long struct rhashtable_iter hti; 5427d25adbebSXin Long struct sctp_transport *tsp; 5428d25adbebSXin Long int ret; 5429626d16f5SXin Long 5430d25adbebSXin Long again: 5431f53d77e1SXin Long ret = 0; 543297a6ec4aSTom Herbert sctp_transport_walk_start(&hti); 5433626d16f5SXin Long 5434d25adbebSXin Long tsp = sctp_transport_get_idx(net, &hti, *pos + 1); 5435d25adbebSXin Long for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) { 5436d25adbebSXin Long ret = cb(tsp, p); 5437d25adbebSXin Long if (ret) 5438626d16f5SXin Long break; 5439d25adbebSXin Long (*pos)++; 5440d25adbebSXin Long sctp_transport_put(tsp); 5441626d16f5SXin Long } 5442626d16f5SXin Long sctp_transport_walk_stop(&hti); 544353fa1036SXin Long 5444d25adbebSXin Long if (ret) { 5445d25adbebSXin Long if (cb_done && !cb_done(tsp, p)) { 5446d25adbebSXin Long (*pos)++; 5447d25adbebSXin Long sctp_transport_put(tsp); 5448d25adbebSXin Long goto again; 5449d25adbebSXin Long } 5450d25adbebSXin Long sctp_transport_put(tsp); 5451d25adbebSXin Long } 5452d25adbebSXin Long 5453d25adbebSXin Long return ret; 5454626d16f5SXin Long } 5455626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_for_each_transport); 5456626d16f5SXin Long 54571da177e4SLinus Torvalds /* 7.2.1 Association Status (SCTP_STATUS) 54581da177e4SLinus Torvalds 54591da177e4SLinus Torvalds * Applications can retrieve current status information about an 54601da177e4SLinus Torvalds * association, including association state, peer receiver window size, 54611da177e4SLinus Torvalds * number of unacked data chunks, and number of data chunks pending 54621da177e4SLinus Torvalds * receipt. This information is read-only. 54631da177e4SLinus Torvalds */ 54641da177e4SLinus Torvalds static int sctp_getsockopt_sctp_status(struct sock *sk, int len, 54651da177e4SLinus Torvalds char __user *optval, 54661da177e4SLinus Torvalds int __user *optlen) 54671da177e4SLinus Torvalds { 54681da177e4SLinus Torvalds struct sctp_status status; 54691da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 54701da177e4SLinus Torvalds struct sctp_transport *transport; 54711da177e4SLinus Torvalds sctp_assoc_t associd; 54721da177e4SLinus Torvalds int retval = 0; 54731da177e4SLinus Torvalds 5474408f22e8SNeil Horman if (len < sizeof(status)) { 54751da177e4SLinus Torvalds retval = -EINVAL; 54761da177e4SLinus Torvalds goto out; 54771da177e4SLinus Torvalds } 54781da177e4SLinus Torvalds 5479408f22e8SNeil Horman len = sizeof(status); 5480408f22e8SNeil Horman if (copy_from_user(&status, optval, len)) { 54811da177e4SLinus Torvalds retval = -EFAULT; 54821da177e4SLinus Torvalds goto out; 54831da177e4SLinus Torvalds } 54841da177e4SLinus Torvalds 54851da177e4SLinus Torvalds associd = status.sstat_assoc_id; 54861da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, associd); 54871da177e4SLinus Torvalds if (!asoc) { 54881da177e4SLinus Torvalds retval = -EINVAL; 54891da177e4SLinus Torvalds goto out; 54901da177e4SLinus Torvalds } 54911da177e4SLinus Torvalds 54921da177e4SLinus Torvalds transport = asoc->peer.primary_path; 54931da177e4SLinus Torvalds 54941da177e4SLinus Torvalds status.sstat_assoc_id = sctp_assoc2id(asoc); 549538ab1fa9SDaniel Borkmann status.sstat_state = sctp_assoc_to_state(asoc); 54961da177e4SLinus Torvalds status.sstat_rwnd = asoc->peer.rwnd; 54971da177e4SLinus Torvalds status.sstat_unackdata = asoc->unack_data; 54981da177e4SLinus Torvalds 54991da177e4SLinus Torvalds status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 5500cee360abSXin Long status.sstat_instrms = asoc->stream.incnt; 5501cee360abSXin Long status.sstat_outstrms = asoc->stream.outcnt; 55021da177e4SLinus Torvalds status.sstat_fragmentation_point = asoc->frag_point; 55031da177e4SLinus Torvalds status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 55048cec6b80SAl Viro memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, 55058cec6b80SAl Viro transport->af_specific->sockaddr_len); 55061da177e4SLinus Torvalds /* Map ipv4 address into v4-mapped-on-v6 address. */ 5507299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), 55081da177e4SLinus Torvalds (union sctp_addr *)&status.sstat_primary.spinfo_address); 55093f7a87d2SFrank Filz status.sstat_primary.spinfo_state = transport->state; 55101da177e4SLinus Torvalds status.sstat_primary.spinfo_cwnd = transport->cwnd; 55111da177e4SLinus Torvalds status.sstat_primary.spinfo_srtt = transport->srtt; 55121da177e4SLinus Torvalds status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto); 551352ccb8e9SFrank Filz status.sstat_primary.spinfo_mtu = transport->pathmtu; 55141da177e4SLinus Torvalds 55153f7a87d2SFrank Filz if (status.sstat_primary.spinfo_state == SCTP_UNKNOWN) 55163f7a87d2SFrank Filz status.sstat_primary.spinfo_state = SCTP_ACTIVE; 55173f7a87d2SFrank Filz 55181da177e4SLinus Torvalds if (put_user(len, optlen)) { 55191da177e4SLinus Torvalds retval = -EFAULT; 55201da177e4SLinus Torvalds goto out; 55211da177e4SLinus Torvalds } 55221da177e4SLinus Torvalds 5523bb33381dSDaniel Borkmann pr_debug("%s: len:%d, state:%d, rwnd:%d, assoc_id:%d\n", 5524bb33381dSDaniel Borkmann __func__, len, status.sstat_state, status.sstat_rwnd, 55251da177e4SLinus Torvalds status.sstat_assoc_id); 55261da177e4SLinus Torvalds 55271da177e4SLinus Torvalds if (copy_to_user(optval, &status, len)) { 55281da177e4SLinus Torvalds retval = -EFAULT; 55291da177e4SLinus Torvalds goto out; 55301da177e4SLinus Torvalds } 55311da177e4SLinus Torvalds 55321da177e4SLinus Torvalds out: 5533a02cec21SEric Dumazet return retval; 55341da177e4SLinus Torvalds } 55351da177e4SLinus Torvalds 55361da177e4SLinus Torvalds 55371da177e4SLinus Torvalds /* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO) 55381da177e4SLinus Torvalds * 55391da177e4SLinus Torvalds * Applications can retrieve information about a specific peer address 55401da177e4SLinus Torvalds * of an association, including its reachability state, congestion 55411da177e4SLinus Torvalds * window, and retransmission timer values. This information is 55421da177e4SLinus Torvalds * read-only. 55431da177e4SLinus Torvalds */ 55441da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, 55451da177e4SLinus Torvalds char __user *optval, 55461da177e4SLinus Torvalds int __user *optlen) 55471da177e4SLinus Torvalds { 55481da177e4SLinus Torvalds struct sctp_paddrinfo pinfo; 55491da177e4SLinus Torvalds struct sctp_transport *transport; 55501da177e4SLinus Torvalds int retval = 0; 55511da177e4SLinus Torvalds 5552408f22e8SNeil Horman if (len < sizeof(pinfo)) { 55531da177e4SLinus Torvalds retval = -EINVAL; 55541da177e4SLinus Torvalds goto out; 55551da177e4SLinus Torvalds } 55561da177e4SLinus Torvalds 5557408f22e8SNeil Horman len = sizeof(pinfo); 5558408f22e8SNeil Horman if (copy_from_user(&pinfo, optval, len)) { 55591da177e4SLinus Torvalds retval = -EFAULT; 55601da177e4SLinus Torvalds goto out; 55611da177e4SLinus Torvalds } 55621da177e4SLinus Torvalds 55631da177e4SLinus Torvalds transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address, 55641da177e4SLinus Torvalds pinfo.spinfo_assoc_id); 5565aef587beSXin Long if (!transport) { 5566aef587beSXin Long retval = -EINVAL; 5567aef587beSXin Long goto out; 5568aef587beSXin Long } 5569aef587beSXin Long 5570aef587beSXin Long if (transport->state == SCTP_PF && 5571aef587beSXin Long transport->asoc->pf_expose == SCTP_PF_EXPOSE_DISABLE) { 5572aef587beSXin Long retval = -EACCES; 5573aef587beSXin Long goto out; 5574aef587beSXin Long } 55751da177e4SLinus Torvalds 55761da177e4SLinus Torvalds pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 55773f7a87d2SFrank Filz pinfo.spinfo_state = transport->state; 55781da177e4SLinus Torvalds pinfo.spinfo_cwnd = transport->cwnd; 55791da177e4SLinus Torvalds pinfo.spinfo_srtt = transport->srtt; 55801da177e4SLinus Torvalds pinfo.spinfo_rto = jiffies_to_msecs(transport->rto); 558152ccb8e9SFrank Filz pinfo.spinfo_mtu = transport->pathmtu; 55821da177e4SLinus Torvalds 55833f7a87d2SFrank Filz if (pinfo.spinfo_state == SCTP_UNKNOWN) 55843f7a87d2SFrank Filz pinfo.spinfo_state = SCTP_ACTIVE; 55853f7a87d2SFrank Filz 55861da177e4SLinus Torvalds if (put_user(len, optlen)) { 55871da177e4SLinus Torvalds retval = -EFAULT; 55881da177e4SLinus Torvalds goto out; 55891da177e4SLinus Torvalds } 55901da177e4SLinus Torvalds 55911da177e4SLinus Torvalds if (copy_to_user(optval, &pinfo, len)) { 55921da177e4SLinus Torvalds retval = -EFAULT; 55931da177e4SLinus Torvalds goto out; 55941da177e4SLinus Torvalds } 55951da177e4SLinus Torvalds 55961da177e4SLinus Torvalds out: 5597a02cec21SEric Dumazet return retval; 55981da177e4SLinus Torvalds } 55991da177e4SLinus Torvalds 56001da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) 56011da177e4SLinus Torvalds * 56021da177e4SLinus Torvalds * This option is a on/off flag. If enabled no SCTP message 56031da177e4SLinus Torvalds * fragmentation will be performed. Instead if a message being sent 56041da177e4SLinus Torvalds * exceeds the current PMTU size, the message will NOT be sent and 56051da177e4SLinus Torvalds * instead a error will be indicated to the user. 56061da177e4SLinus Torvalds */ 56071da177e4SLinus Torvalds static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, 56081da177e4SLinus Torvalds char __user *optval, int __user *optlen) 56091da177e4SLinus Torvalds { 56101da177e4SLinus Torvalds int val; 56111da177e4SLinus Torvalds 56121da177e4SLinus Torvalds if (len < sizeof(int)) 56131da177e4SLinus Torvalds return -EINVAL; 56141da177e4SLinus Torvalds 56151da177e4SLinus Torvalds len = sizeof(int); 56161da177e4SLinus Torvalds val = (sctp_sk(sk)->disable_fragments == 1); 56171da177e4SLinus Torvalds if (put_user(len, optlen)) 56181da177e4SLinus Torvalds return -EFAULT; 56191da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 56201da177e4SLinus Torvalds return -EFAULT; 56211da177e4SLinus Torvalds return 0; 56221da177e4SLinus Torvalds } 56231da177e4SLinus Torvalds 56241da177e4SLinus Torvalds /* 7.1.15 Set notification and ancillary events (SCTP_EVENTS) 56251da177e4SLinus Torvalds * 56261da177e4SLinus Torvalds * This socket option is used to specify various notifications and 56271da177e4SLinus Torvalds * ancillary data the user wishes to receive. 56281da177e4SLinus Torvalds */ 56291da177e4SLinus Torvalds static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, 56301da177e4SLinus Torvalds int __user *optlen) 56311da177e4SLinus Torvalds { 56322cc0eeb6SXin Long struct sctp_event_subscribe subscribe; 56332cc0eeb6SXin Long __u8 *sn_type = (__u8 *)&subscribe; 56342cc0eeb6SXin Long int i; 56352cc0eeb6SXin Long 5636a4b8e71bSJiri Slaby if (len == 0) 56371da177e4SLinus Torvalds return -EINVAL; 5638acdd5985SThomas Graf if (len > sizeof(struct sctp_event_subscribe)) 5639408f22e8SNeil Horman len = sizeof(struct sctp_event_subscribe); 5640408f22e8SNeil Horman if (put_user(len, optlen)) 5641408f22e8SNeil Horman return -EFAULT; 56422cc0eeb6SXin Long 56432cc0eeb6SXin Long for (i = 0; i < len; i++) 56442cc0eeb6SXin Long sn_type[i] = sctp_ulpevent_type_enabled(sctp_sk(sk)->subscribe, 56452cc0eeb6SXin Long SCTP_SN_TYPE_BASE + i); 56462cc0eeb6SXin Long 56472cc0eeb6SXin Long if (copy_to_user(optval, &subscribe, len)) 56481da177e4SLinus Torvalds return -EFAULT; 56492cc0eeb6SXin Long 56501da177e4SLinus Torvalds return 0; 56511da177e4SLinus Torvalds } 56521da177e4SLinus Torvalds 56531da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) 56541da177e4SLinus Torvalds * 56551da177e4SLinus Torvalds * This socket option is applicable to the UDP-style socket only. When 56561da177e4SLinus Torvalds * set it will cause associations that are idle for more than the 56571da177e4SLinus Torvalds * specified number of seconds to automatically close. An association 56581da177e4SLinus Torvalds * being idle is defined an association that has NOT sent or received 56591da177e4SLinus Torvalds * user data. The special value of '0' indicates that no automatic 56601da177e4SLinus Torvalds * close of any associations should be performed. The option expects an 56611da177e4SLinus Torvalds * integer defining the number of seconds of idle time before an 56621da177e4SLinus Torvalds * association is closed. 56631da177e4SLinus Torvalds */ 56641da177e4SLinus Torvalds static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optval, int __user *optlen) 56651da177e4SLinus Torvalds { 56661da177e4SLinus Torvalds /* Applicable to UDP-style socket only */ 56671da177e4SLinus Torvalds if (sctp_style(sk, TCP)) 56681da177e4SLinus Torvalds return -EOPNOTSUPP; 5669408f22e8SNeil Horman if (len < sizeof(int)) 56701da177e4SLinus Torvalds return -EINVAL; 5671408f22e8SNeil Horman len = sizeof(int); 5672408f22e8SNeil Horman if (put_user(len, optlen)) 5673408f22e8SNeil Horman return -EFAULT; 5674b2ce04c2SDavid Windsor if (put_user(sctp_sk(sk)->autoclose, (int __user *)optval)) 56751da177e4SLinus Torvalds return -EFAULT; 56761da177e4SLinus Torvalds return 0; 56771da177e4SLinus Torvalds } 56781da177e4SLinus Torvalds 56791da177e4SLinus Torvalds /* Helper routine to branch off an association to a new socket. */ 56800343c554SBenjamin Poirier int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) 56811da177e4SLinus Torvalds { 56820343c554SBenjamin Poirier struct sctp_association *asoc = sctp_id2assoc(sk, id); 5683299ee123SJason Gunthorpe struct sctp_sock *sp = sctp_sk(sk); 56841da177e4SLinus Torvalds struct socket *sock; 56851da177e4SLinus Torvalds int err = 0; 56861da177e4SLinus Torvalds 5687df80cd9bSXin Long /* Do not peel off from one netns to another one. */ 5688df80cd9bSXin Long if (!net_eq(current->nsproxy->net_ns, sock_net(sk))) 5689df80cd9bSXin Long return -EINVAL; 5690df80cd9bSXin Long 56910343c554SBenjamin Poirier if (!asoc) 56920343c554SBenjamin Poirier return -EINVAL; 56930343c554SBenjamin Poirier 56941da177e4SLinus Torvalds /* An association cannot be branched off from an already peeled-off 56951da177e4SLinus Torvalds * socket, nor is this supported for tcp style sockets. 56961da177e4SLinus Torvalds */ 56971da177e4SLinus Torvalds if (!sctp_style(sk, UDP)) 56981da177e4SLinus Torvalds return -EINVAL; 56991da177e4SLinus Torvalds 57001da177e4SLinus Torvalds /* Create a new socket. */ 57011da177e4SLinus Torvalds err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); 57021da177e4SLinus Torvalds if (err < 0) 57031da177e4SLinus Torvalds return err; 57041da177e4SLinus Torvalds 5705914e1c8bSVlad Yasevich sctp_copy_sock(sock->sk, sk, asoc); 57064f444308SVlad Yasevich 57074f444308SVlad Yasevich /* Make peeled-off sockets more like 1-1 accepted sockets. 5708b7e10c25SRichard Haines * Set the daddr and initialize id to something more random and also 5709b7e10c25SRichard Haines * copy over any ip options. 57104f444308SVlad Yasevich */ 5711299ee123SJason Gunthorpe sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk); 5712b7e10c25SRichard Haines sp->pf->copy_ip_options(sk, sock->sk); 5713914e1c8bSVlad Yasevich 5714914e1c8bSVlad Yasevich /* Populate the fields of the newsk from the oldsk and migrate the 5715914e1c8bSVlad Yasevich * asoc to the newsk. 5716914e1c8bSVlad Yasevich */ 571789664c62SXin Long err = sctp_sock_migrate(sk, sock->sk, asoc, 571889664c62SXin Long SCTP_SOCKET_UDP_HIGH_BANDWIDTH); 571989664c62SXin Long if (err) { 572089664c62SXin Long sock_release(sock); 572189664c62SXin Long sock = NULL; 572289664c62SXin Long } 57234f444308SVlad Yasevich 57241da177e4SLinus Torvalds *sockp = sock; 57251da177e4SLinus Torvalds 57261da177e4SLinus Torvalds return err; 57271da177e4SLinus Torvalds } 57280343c554SBenjamin Poirier EXPORT_SYMBOL(sctp_do_peeloff); 57291da177e4SLinus Torvalds 57302cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *peeloff, 57312cb5c8e3SNeil Horman struct file **newfile, unsigned flags) 57322cb5c8e3SNeil Horman { 57332cb5c8e3SNeil Horman struct socket *newsock; 57342cb5c8e3SNeil Horman int retval; 57352cb5c8e3SNeil Horman 57362cb5c8e3SNeil Horman retval = sctp_do_peeloff(sk, peeloff->associd, &newsock); 57372cb5c8e3SNeil Horman if (retval < 0) 57382cb5c8e3SNeil Horman goto out; 57392cb5c8e3SNeil Horman 57402cb5c8e3SNeil Horman /* Map the socket to an unused fd that can be returned to the user. */ 57412cb5c8e3SNeil Horman retval = get_unused_fd_flags(flags & SOCK_CLOEXEC); 57422cb5c8e3SNeil Horman if (retval < 0) { 57432cb5c8e3SNeil Horman sock_release(newsock); 57442cb5c8e3SNeil Horman goto out; 57452cb5c8e3SNeil Horman } 57462cb5c8e3SNeil Horman 57472cb5c8e3SNeil Horman *newfile = sock_alloc_file(newsock, 0, NULL); 57482cb5c8e3SNeil Horman if (IS_ERR(*newfile)) { 57492cb5c8e3SNeil Horman put_unused_fd(retval); 57502cb5c8e3SNeil Horman retval = PTR_ERR(*newfile); 57512cb5c8e3SNeil Horman *newfile = NULL; 57522cb5c8e3SNeil Horman return retval; 57532cb5c8e3SNeil Horman } 57542cb5c8e3SNeil Horman 57552cb5c8e3SNeil Horman pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk, 57562cb5c8e3SNeil Horman retval); 57572cb5c8e3SNeil Horman 57582cb5c8e3SNeil Horman peeloff->sd = retval; 57592cb5c8e3SNeil Horman 57602cb5c8e3SNeil Horman if (flags & SOCK_NONBLOCK) 57612cb5c8e3SNeil Horman (*newfile)->f_flags |= O_NONBLOCK; 57622cb5c8e3SNeil Horman out: 57632cb5c8e3SNeil Horman return retval; 57642cb5c8e3SNeil Horman } 57652cb5c8e3SNeil Horman 57661da177e4SLinus Torvalds static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) 57671da177e4SLinus Torvalds { 57681da177e4SLinus Torvalds sctp_peeloff_arg_t peeloff; 57692cb5c8e3SNeil Horman struct file *newfile = NULL; 57701da177e4SLinus Torvalds int retval = 0; 57711da177e4SLinus Torvalds 5772408f22e8SNeil Horman if (len < sizeof(sctp_peeloff_arg_t)) 57731da177e4SLinus Torvalds return -EINVAL; 5774408f22e8SNeil Horman len = sizeof(sctp_peeloff_arg_t); 57751da177e4SLinus Torvalds if (copy_from_user(&peeloff, optval, len)) 57761da177e4SLinus Torvalds return -EFAULT; 57771da177e4SLinus Torvalds 57782cb5c8e3SNeil Horman retval = sctp_getsockopt_peeloff_common(sk, &peeloff, &newfile, 0); 57791da177e4SLinus Torvalds if (retval < 0) 57801da177e4SLinus Torvalds goto out; 57811da177e4SLinus Torvalds 57821da177e4SLinus Torvalds /* Return the fd mapped to the new socket. */ 578356b31d1cSAl Viro if (put_user(len, optlen)) { 578456b31d1cSAl Viro fput(newfile); 578556b31d1cSAl Viro put_unused_fd(retval); 5786408f22e8SNeil Horman return -EFAULT; 578756b31d1cSAl Viro } 57882cb5c8e3SNeil Horman 57892cb5c8e3SNeil Horman if (copy_to_user(optval, &peeloff, len)) { 57902cb5c8e3SNeil Horman fput(newfile); 57912cb5c8e3SNeil Horman put_unused_fd(retval); 57922cb5c8e3SNeil Horman return -EFAULT; 57932cb5c8e3SNeil Horman } 57942cb5c8e3SNeil Horman fd_install(retval, newfile); 57952cb5c8e3SNeil Horman out: 57962cb5c8e3SNeil Horman return retval; 57972cb5c8e3SNeil Horman } 57982cb5c8e3SNeil Horman 57992cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len, 58002cb5c8e3SNeil Horman char __user *optval, int __user *optlen) 58012cb5c8e3SNeil Horman { 58022cb5c8e3SNeil Horman sctp_peeloff_flags_arg_t peeloff; 58032cb5c8e3SNeil Horman struct file *newfile = NULL; 58042cb5c8e3SNeil Horman int retval = 0; 58052cb5c8e3SNeil Horman 58062cb5c8e3SNeil Horman if (len < sizeof(sctp_peeloff_flags_arg_t)) 58072cb5c8e3SNeil Horman return -EINVAL; 58082cb5c8e3SNeil Horman len = sizeof(sctp_peeloff_flags_arg_t); 58092cb5c8e3SNeil Horman if (copy_from_user(&peeloff, optval, len)) 58102cb5c8e3SNeil Horman return -EFAULT; 58112cb5c8e3SNeil Horman 58122cb5c8e3SNeil Horman retval = sctp_getsockopt_peeloff_common(sk, &peeloff.p_arg, 58132cb5c8e3SNeil Horman &newfile, peeloff.flags); 58142cb5c8e3SNeil Horman if (retval < 0) 58152cb5c8e3SNeil Horman goto out; 58162cb5c8e3SNeil Horman 58172cb5c8e3SNeil Horman /* Return the fd mapped to the new socket. */ 58182cb5c8e3SNeil Horman if (put_user(len, optlen)) { 58192cb5c8e3SNeil Horman fput(newfile); 58202cb5c8e3SNeil Horman put_unused_fd(retval); 58212cb5c8e3SNeil Horman return -EFAULT; 58222cb5c8e3SNeil Horman } 58232cb5c8e3SNeil Horman 582456b31d1cSAl Viro if (copy_to_user(optval, &peeloff, len)) { 582556b31d1cSAl Viro fput(newfile); 582656b31d1cSAl Viro put_unused_fd(retval); 582756b31d1cSAl Viro return -EFAULT; 582856b31d1cSAl Viro } 582956b31d1cSAl Viro fd_install(retval, newfile); 58301da177e4SLinus Torvalds out: 58311da177e4SLinus Torvalds return retval; 58321da177e4SLinus Torvalds } 58331da177e4SLinus Torvalds 58341da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) 58351da177e4SLinus Torvalds * 58361da177e4SLinus Torvalds * Applications can enable or disable heartbeats for any peer address of 58371da177e4SLinus Torvalds * an association, modify an address's heartbeat interval, force a 58381da177e4SLinus Torvalds * heartbeat to be sent immediately, and adjust the address's maximum 58391da177e4SLinus Torvalds * number of retransmissions sent before an address is considered 58401da177e4SLinus Torvalds * unreachable. The following structure is used to access and modify an 58411da177e4SLinus Torvalds * address's parameters: 58421da177e4SLinus Torvalds * 58431da177e4SLinus Torvalds * struct sctp_paddrparams { 58441da177e4SLinus Torvalds * sctp_assoc_t spp_assoc_id; 58451da177e4SLinus Torvalds * struct sockaddr_storage spp_address; 58461da177e4SLinus Torvalds * uint32_t spp_hbinterval; 58471da177e4SLinus Torvalds * uint16_t spp_pathmaxrxt; 584852ccb8e9SFrank Filz * uint32_t spp_pathmtu; 584952ccb8e9SFrank Filz * uint32_t spp_sackdelay; 585052ccb8e9SFrank Filz * uint32_t spp_flags; 58511da177e4SLinus Torvalds * }; 58521da177e4SLinus Torvalds * 585352ccb8e9SFrank Filz * spp_assoc_id - (one-to-many style socket) This is filled in the 585452ccb8e9SFrank Filz * application, and identifies the association for 585552ccb8e9SFrank Filz * this query. 58561da177e4SLinus Torvalds * spp_address - This specifies which address is of interest. 58571da177e4SLinus Torvalds * spp_hbinterval - This contains the value of the heartbeat interval, 585852ccb8e9SFrank Filz * in milliseconds. If a value of zero 585952ccb8e9SFrank Filz * is present in this field then no changes are to 586052ccb8e9SFrank Filz * be made to this parameter. 58611da177e4SLinus Torvalds * spp_pathmaxrxt - This contains the maximum number of 58621da177e4SLinus Torvalds * retransmissions before this address shall be 586352ccb8e9SFrank Filz * considered unreachable. If a value of zero 586452ccb8e9SFrank Filz * is present in this field then no changes are to 586552ccb8e9SFrank Filz * be made to this parameter. 586652ccb8e9SFrank Filz * spp_pathmtu - When Path MTU discovery is disabled the value 586752ccb8e9SFrank Filz * specified here will be the "fixed" path mtu. 586852ccb8e9SFrank Filz * Note that if the spp_address field is empty 586952ccb8e9SFrank Filz * then all associations on this address will 587052ccb8e9SFrank Filz * have this fixed path mtu set upon them. 587152ccb8e9SFrank Filz * 587252ccb8e9SFrank Filz * spp_sackdelay - When delayed sack is enabled, this value specifies 587352ccb8e9SFrank Filz * the number of milliseconds that sacks will be delayed 587452ccb8e9SFrank Filz * for. This value will apply to all addresses of an 587552ccb8e9SFrank Filz * association if the spp_address field is empty. Note 587652ccb8e9SFrank Filz * also, that if delayed sack is enabled and this 587752ccb8e9SFrank Filz * value is set to 0, no change is made to the last 587852ccb8e9SFrank Filz * recorded delayed sack timer value. 587952ccb8e9SFrank Filz * 588052ccb8e9SFrank Filz * spp_flags - These flags are used to control various features 588152ccb8e9SFrank Filz * on an association. The flag field may contain 588252ccb8e9SFrank Filz * zero or more of the following options. 588352ccb8e9SFrank Filz * 588452ccb8e9SFrank Filz * SPP_HB_ENABLE - Enable heartbeats on the 588552ccb8e9SFrank Filz * specified address. Note that if the address 588652ccb8e9SFrank Filz * field is empty all addresses for the association 588752ccb8e9SFrank Filz * have heartbeats enabled upon them. 588852ccb8e9SFrank Filz * 588952ccb8e9SFrank Filz * SPP_HB_DISABLE - Disable heartbeats on the 589052ccb8e9SFrank Filz * speicifed address. Note that if the address 589152ccb8e9SFrank Filz * field is empty all addresses for the association 589252ccb8e9SFrank Filz * will have their heartbeats disabled. Note also 589352ccb8e9SFrank Filz * that SPP_HB_ENABLE and SPP_HB_DISABLE are 589452ccb8e9SFrank Filz * mutually exclusive, only one of these two should 589552ccb8e9SFrank Filz * be specified. Enabling both fields will have 589652ccb8e9SFrank Filz * undetermined results. 589752ccb8e9SFrank Filz * 589852ccb8e9SFrank Filz * SPP_HB_DEMAND - Request a user initiated heartbeat 589952ccb8e9SFrank Filz * to be made immediately. 590052ccb8e9SFrank Filz * 590152ccb8e9SFrank Filz * SPP_PMTUD_ENABLE - This field will enable PMTU 590252ccb8e9SFrank Filz * discovery upon the specified address. Note that 590352ccb8e9SFrank Filz * if the address feild is empty then all addresses 590452ccb8e9SFrank Filz * on the association are effected. 590552ccb8e9SFrank Filz * 590652ccb8e9SFrank Filz * SPP_PMTUD_DISABLE - This field will disable PMTU 590752ccb8e9SFrank Filz * discovery upon the specified address. Note that 590852ccb8e9SFrank Filz * if the address feild is empty then all addresses 590952ccb8e9SFrank Filz * on the association are effected. Not also that 591052ccb8e9SFrank Filz * SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually 591152ccb8e9SFrank Filz * exclusive. Enabling both will have undetermined 591252ccb8e9SFrank Filz * results. 591352ccb8e9SFrank Filz * 591452ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE - Setting this flag turns 591552ccb8e9SFrank Filz * on delayed sack. The time specified in spp_sackdelay 591652ccb8e9SFrank Filz * is used to specify the sack delay for this address. Note 591752ccb8e9SFrank Filz * that if spp_address is empty then all addresses will 591852ccb8e9SFrank Filz * enable delayed sack and take on the sack delay 591952ccb8e9SFrank Filz * value specified in spp_sackdelay. 592052ccb8e9SFrank Filz * SPP_SACKDELAY_DISABLE - Setting this flag turns 592152ccb8e9SFrank Filz * off delayed sack. If the spp_address field is blank then 592252ccb8e9SFrank Filz * delayed sack is disabled for the entire association. Note 592352ccb8e9SFrank Filz * also that this field is mutually exclusive to 592452ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE, setting both will have undefined 592552ccb8e9SFrank Filz * results. 59260b0dce7aSXin Long * 59270b0dce7aSXin Long * SPP_IPV6_FLOWLABEL: Setting this flag enables the 59280b0dce7aSXin Long * setting of the IPV6 flow label value. The value is 59290b0dce7aSXin Long * contained in the spp_ipv6_flowlabel field. 59300b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 59310b0dce7aSXin Long * the spp_ipv6_flowlabel field has a valid value returned. 59320b0dce7aSXin Long * If a specific destination address is set (in the 59330b0dce7aSXin Long * spp_address field), then the value returned is that of 59340b0dce7aSXin Long * the address. If just an association is specified (and 59350b0dce7aSXin Long * no address), then the association's default flow label 59360b0dce7aSXin Long * is returned. If neither an association nor a destination 59370b0dce7aSXin Long * is specified, then the socket's default flow label is 59380b0dce7aSXin Long * returned. For non-IPv6 sockets, this flag will be left 59390b0dce7aSXin Long * cleared. 59400b0dce7aSXin Long * 59410b0dce7aSXin Long * SPP_DSCP: Setting this flag enables the setting of the 59420b0dce7aSXin Long * Differentiated Services Code Point (DSCP) value 59430b0dce7aSXin Long * associated with either the association or a specific 59440b0dce7aSXin Long * address. The value is obtained in the spp_dscp field. 59450b0dce7aSXin Long * Upon retrieval, this flag will be set to indicate that 59460b0dce7aSXin Long * the spp_dscp field has a valid value returned. If a 59470b0dce7aSXin Long * specific destination address is set when called (in the 59480b0dce7aSXin Long * spp_address field), then that specific destination 59490b0dce7aSXin Long * address's DSCP value is returned. If just an association 59500b0dce7aSXin Long * is specified, then the association's default DSCP is 59510b0dce7aSXin Long * returned. If neither an association nor a destination is 59520b0dce7aSXin Long * specified, then the socket's default DSCP is returned. 59530b0dce7aSXin Long * 59540b0dce7aSXin Long * spp_ipv6_flowlabel 59550b0dce7aSXin Long * - This field is used in conjunction with the 59560b0dce7aSXin Long * SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label. 59570b0dce7aSXin Long * The 20 least significant bits are used for the flow 59580b0dce7aSXin Long * label. This setting has precedence over any IPv6-layer 59590b0dce7aSXin Long * setting. 59600b0dce7aSXin Long * 59610b0dce7aSXin Long * spp_dscp - This field is used in conjunction with the SPP_DSCP flag 59620b0dce7aSXin Long * and contains the DSCP. The 6 most significant bits are 59630b0dce7aSXin Long * used for the DSCP. This setting has precedence over any 59640b0dce7aSXin Long * IPv4- or IPv6- layer setting. 59651da177e4SLinus Torvalds */ 59661da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, 59671da177e4SLinus Torvalds char __user *optval, int __user *optlen) 59681da177e4SLinus Torvalds { 59691da177e4SLinus Torvalds struct sctp_paddrparams params; 597052ccb8e9SFrank Filz struct sctp_transport *trans = NULL; 597152ccb8e9SFrank Filz struct sctp_association *asoc = NULL; 597252ccb8e9SFrank Filz struct sctp_sock *sp = sctp_sk(sk); 59731da177e4SLinus Torvalds 59740b0dce7aSXin Long if (len >= sizeof(params)) 59750b0dce7aSXin Long len = sizeof(params); 59760b0dce7aSXin Long else if (len >= ALIGN(offsetof(struct sctp_paddrparams, 59770b0dce7aSXin Long spp_ipv6_flowlabel), 4)) 59780b0dce7aSXin Long len = ALIGN(offsetof(struct sctp_paddrparams, 59790b0dce7aSXin Long spp_ipv6_flowlabel), 4); 59800b0dce7aSXin Long else 59811da177e4SLinus Torvalds return -EINVAL; 59820b0dce7aSXin Long 59831da177e4SLinus Torvalds if (copy_from_user(¶ms, optval, len)) 59841da177e4SLinus Torvalds return -EFAULT; 59851da177e4SLinus Torvalds 598652ccb8e9SFrank Filz /* If an address other than INADDR_ANY is specified, and 598752ccb8e9SFrank Filz * no transport is found, then the request is invalid. 59881da177e4SLinus Torvalds */ 598952cae8f0SVlad Yasevich if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { 59901da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, ¶ms.spp_address, 59911da177e4SLinus Torvalds params.spp_assoc_id); 599252ccb8e9SFrank Filz if (!trans) { 5993bb33381dSDaniel Borkmann pr_debug("%s: failed no transport\n", __func__); 59941da177e4SLinus Torvalds return -EINVAL; 599552ccb8e9SFrank Filz } 599652ccb8e9SFrank Filz } 59971da177e4SLinus Torvalds 5998b99e5e02SXin Long /* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the 5999b99e5e02SXin Long * socket is a one to many style socket, and an association 6000b99e5e02SXin Long * was not found, then the id was invalid. 60011da177e4SLinus Torvalds */ 600252ccb8e9SFrank Filz asoc = sctp_id2assoc(sk, params.spp_assoc_id); 6003b99e5e02SXin Long if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC && 6004b99e5e02SXin Long sctp_style(sk, UDP)) { 6005bb33381dSDaniel Borkmann pr_debug("%s: failed no association\n", __func__); 600652ccb8e9SFrank Filz return -EINVAL; 600752ccb8e9SFrank Filz } 60081da177e4SLinus Torvalds 600952ccb8e9SFrank Filz if (trans) { 601052ccb8e9SFrank Filz /* Fetch transport values. */ 601152ccb8e9SFrank Filz params.spp_hbinterval = jiffies_to_msecs(trans->hbinterval); 601252ccb8e9SFrank Filz params.spp_pathmtu = trans->pathmtu; 601352ccb8e9SFrank Filz params.spp_pathmaxrxt = trans->pathmaxrxt; 601452ccb8e9SFrank Filz params.spp_sackdelay = jiffies_to_msecs(trans->sackdelay); 60151da177e4SLinus Torvalds 601652ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 601752ccb8e9SFrank Filz params.spp_flags = trans->param_flags; 60180b0dce7aSXin Long if (trans->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 60190b0dce7aSXin Long params.spp_ipv6_flowlabel = trans->flowlabel & 60200b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 60210b0dce7aSXin Long params.spp_flags |= SPP_IPV6_FLOWLABEL; 60220b0dce7aSXin Long } 60230b0dce7aSXin Long if (trans->dscp & SCTP_DSCP_SET_MASK) { 60240b0dce7aSXin Long params.spp_dscp = trans->dscp & SCTP_DSCP_VAL_MASK; 60250b0dce7aSXin Long params.spp_flags |= SPP_DSCP; 60260b0dce7aSXin Long } 602752ccb8e9SFrank Filz } else if (asoc) { 602852ccb8e9SFrank Filz /* Fetch association values. */ 602952ccb8e9SFrank Filz params.spp_hbinterval = jiffies_to_msecs(asoc->hbinterval); 603052ccb8e9SFrank Filz params.spp_pathmtu = asoc->pathmtu; 603152ccb8e9SFrank Filz params.spp_pathmaxrxt = asoc->pathmaxrxt; 603252ccb8e9SFrank Filz params.spp_sackdelay = jiffies_to_msecs(asoc->sackdelay); 603352ccb8e9SFrank Filz 603452ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 603552ccb8e9SFrank Filz params.spp_flags = asoc->param_flags; 60360b0dce7aSXin Long if (asoc->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 60370b0dce7aSXin Long params.spp_ipv6_flowlabel = asoc->flowlabel & 60380b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 60390b0dce7aSXin Long params.spp_flags |= SPP_IPV6_FLOWLABEL; 60400b0dce7aSXin Long } 60410b0dce7aSXin Long if (asoc->dscp & SCTP_DSCP_SET_MASK) { 60420b0dce7aSXin Long params.spp_dscp = asoc->dscp & SCTP_DSCP_VAL_MASK; 60430b0dce7aSXin Long params.spp_flags |= SPP_DSCP; 60440b0dce7aSXin Long } 604552ccb8e9SFrank Filz } else { 604652ccb8e9SFrank Filz /* Fetch socket values. */ 604752ccb8e9SFrank Filz params.spp_hbinterval = sp->hbinterval; 604852ccb8e9SFrank Filz params.spp_pathmtu = sp->pathmtu; 604952ccb8e9SFrank Filz params.spp_sackdelay = sp->sackdelay; 605052ccb8e9SFrank Filz params.spp_pathmaxrxt = sp->pathmaxrxt; 605152ccb8e9SFrank Filz 605252ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 605352ccb8e9SFrank Filz params.spp_flags = sp->param_flags; 60540b0dce7aSXin Long if (sp->flowlabel & SCTP_FLOWLABEL_SET_MASK) { 60550b0dce7aSXin Long params.spp_ipv6_flowlabel = sp->flowlabel & 60560b0dce7aSXin Long SCTP_FLOWLABEL_VAL_MASK; 60570b0dce7aSXin Long params.spp_flags |= SPP_IPV6_FLOWLABEL; 60580b0dce7aSXin Long } 60590b0dce7aSXin Long if (sp->dscp & SCTP_DSCP_SET_MASK) { 60600b0dce7aSXin Long params.spp_dscp = sp->dscp & SCTP_DSCP_VAL_MASK; 60610b0dce7aSXin Long params.spp_flags |= SPP_DSCP; 60620b0dce7aSXin Long } 606352ccb8e9SFrank Filz } 606452ccb8e9SFrank Filz 60651da177e4SLinus Torvalds if (copy_to_user(optval, ¶ms, len)) 60661da177e4SLinus Torvalds return -EFAULT; 60671da177e4SLinus Torvalds 60681da177e4SLinus Torvalds if (put_user(len, optlen)) 60691da177e4SLinus Torvalds return -EFAULT; 60701da177e4SLinus Torvalds 60711da177e4SLinus Torvalds return 0; 60721da177e4SLinus Torvalds } 60731da177e4SLinus Torvalds 6074d364d927SWei Yongjun /* 6075d364d927SWei Yongjun * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 60767708610bSFrank Filz * 6077d364d927SWei Yongjun * This option will effect the way delayed acks are performed. This 6078d364d927SWei Yongjun * option allows you to get or set the delayed ack time, in 6079d364d927SWei Yongjun * milliseconds. It also allows changing the delayed ack frequency. 6080d364d927SWei Yongjun * Changing the frequency to 1 disables the delayed sack algorithm. If 6081d364d927SWei Yongjun * the assoc_id is 0, then this sets or gets the endpoints default 6082d364d927SWei Yongjun * values. If the assoc_id field is non-zero, then the set or get 6083d364d927SWei Yongjun * effects the specified association for the one to many model (the 6084d364d927SWei Yongjun * assoc_id field is ignored by the one to one model). Note that if 6085d364d927SWei Yongjun * sack_delay or sack_freq are 0 when setting this option, then the 6086d364d927SWei Yongjun * current values will remain unchanged. 60877708610bSFrank Filz * 6088d364d927SWei Yongjun * struct sctp_sack_info { 6089d364d927SWei Yongjun * sctp_assoc_t sack_assoc_id; 6090d364d927SWei Yongjun * uint32_t sack_delay; 6091d364d927SWei Yongjun * uint32_t sack_freq; 60927708610bSFrank Filz * }; 60937708610bSFrank Filz * 6094d364d927SWei Yongjun * sack_assoc_id - This parameter, indicates which association the user 6095d364d927SWei Yongjun * is performing an action upon. Note that if this field's value is 6096d364d927SWei Yongjun * zero then the endpoints default value is changed (effecting future 60977708610bSFrank Filz * associations only). 60987708610bSFrank Filz * 6099d364d927SWei Yongjun * sack_delay - This parameter contains the number of milliseconds that 6100d364d927SWei Yongjun * the user is requesting the delayed ACK timer be set to. Note that 6101d364d927SWei Yongjun * this value is defined in the standard to be between 200 and 500 6102d364d927SWei Yongjun * milliseconds. 61037708610bSFrank Filz * 6104d364d927SWei Yongjun * sack_freq - This parameter contains the number of packets that must 6105d364d927SWei Yongjun * be received before a sack is sent without waiting for the delay 6106d364d927SWei Yongjun * timer to expire. The default value for this is 2, setting this 6107d364d927SWei Yongjun * value to 1 will disable the delayed sack algorithm. 61087708610bSFrank Filz */ 6109d364d927SWei Yongjun static int sctp_getsockopt_delayed_ack(struct sock *sk, int len, 61107708610bSFrank Filz char __user *optval, 61117708610bSFrank Filz int __user *optlen) 61127708610bSFrank Filz { 6113d364d927SWei Yongjun struct sctp_sack_info params; 61147708610bSFrank Filz struct sctp_association *asoc = NULL; 61157708610bSFrank Filz struct sctp_sock *sp = sctp_sk(sk); 61167708610bSFrank Filz 6117d364d927SWei Yongjun if (len >= sizeof(struct sctp_sack_info)) { 6118d364d927SWei Yongjun len = sizeof(struct sctp_sack_info); 6119408f22e8SNeil Horman 61207708610bSFrank Filz if (copy_from_user(¶ms, optval, len)) 61217708610bSFrank Filz return -EFAULT; 6122d364d927SWei Yongjun } else if (len == sizeof(struct sctp_assoc_value)) { 612394f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 6124f916ec96SNeil Horman "%s (pid %d) " 612594f65193SNeil Horman "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 6126f916ec96SNeil Horman "Use struct sctp_sack_info instead\n", 6127f916ec96SNeil Horman current->comm, task_pid_nr(current)); 6128d364d927SWei Yongjun if (copy_from_user(¶ms, optval, len)) 6129d364d927SWei Yongjun return -EFAULT; 6130d364d927SWei Yongjun } else 6131d364d927SWei Yongjun return -EINVAL; 61327708610bSFrank Filz 61339c5829e1SXin Long /* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the 61349c5829e1SXin Long * socket is a one to many style socket, and an association 61359c5829e1SXin Long * was not found, then the id was invalid. 61367708610bSFrank Filz */ 6137d364d927SWei Yongjun asoc = sctp_id2assoc(sk, params.sack_assoc_id); 61389c5829e1SXin Long if (!asoc && params.sack_assoc_id != SCTP_FUTURE_ASSOC && 61399c5829e1SXin Long sctp_style(sk, UDP)) 61407708610bSFrank Filz return -EINVAL; 61417708610bSFrank Filz 61427708610bSFrank Filz if (asoc) { 61437708610bSFrank Filz /* Fetch association values. */ 6144d364d927SWei Yongjun if (asoc->param_flags & SPP_SACKDELAY_ENABLE) { 61459c5829e1SXin Long params.sack_delay = jiffies_to_msecs(asoc->sackdelay); 6146d364d927SWei Yongjun params.sack_freq = asoc->sackfreq; 6147d364d927SWei Yongjun 6148d364d927SWei Yongjun } else { 6149d364d927SWei Yongjun params.sack_delay = 0; 6150d364d927SWei Yongjun params.sack_freq = 1; 6151d364d927SWei Yongjun } 61527708610bSFrank Filz } else { 61537708610bSFrank Filz /* Fetch socket values. */ 6154d364d927SWei Yongjun if (sp->param_flags & SPP_SACKDELAY_ENABLE) { 6155d364d927SWei Yongjun params.sack_delay = sp->sackdelay; 6156d364d927SWei Yongjun params.sack_freq = sp->sackfreq; 6157d364d927SWei Yongjun } else { 6158d364d927SWei Yongjun params.sack_delay = 0; 6159d364d927SWei Yongjun params.sack_freq = 1; 6160d364d927SWei Yongjun } 61617708610bSFrank Filz } 61627708610bSFrank Filz 61637708610bSFrank Filz if (copy_to_user(optval, ¶ms, len)) 61647708610bSFrank Filz return -EFAULT; 61657708610bSFrank Filz 61667708610bSFrank Filz if (put_user(len, optlen)) 61677708610bSFrank Filz return -EFAULT; 61687708610bSFrank Filz 61697708610bSFrank Filz return 0; 61707708610bSFrank Filz } 61717708610bSFrank Filz 61721da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG) 61731da177e4SLinus Torvalds * 61741da177e4SLinus Torvalds * Applications can specify protocol parameters for the default association 61751da177e4SLinus Torvalds * initialization. The option name argument to setsockopt() and getsockopt() 61761da177e4SLinus Torvalds * is SCTP_INITMSG. 61771da177e4SLinus Torvalds * 61781da177e4SLinus Torvalds * Setting initialization parameters is effective only on an unconnected 61791da177e4SLinus Torvalds * socket (for UDP-style sockets only future associations are effected 61801da177e4SLinus Torvalds * by the change). With TCP-style sockets, this option is inherited by 61811da177e4SLinus Torvalds * sockets derived from a listener socket. 61821da177e4SLinus Torvalds */ 61831da177e4SLinus Torvalds static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen) 61841da177e4SLinus Torvalds { 6185408f22e8SNeil Horman if (len < sizeof(struct sctp_initmsg)) 61861da177e4SLinus Torvalds return -EINVAL; 6187408f22e8SNeil Horman len = sizeof(struct sctp_initmsg); 6188408f22e8SNeil Horman if (put_user(len, optlen)) 6189408f22e8SNeil Horman return -EFAULT; 61901da177e4SLinus Torvalds if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len)) 61911da177e4SLinus Torvalds return -EFAULT; 61921da177e4SLinus Torvalds return 0; 61931da177e4SLinus Torvalds } 61941da177e4SLinus Torvalds 61951da177e4SLinus Torvalds 61965fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, 61975fe467eeSIvan Skytte Jørgensen char __user *optval, int __user *optlen) 61985fe467eeSIvan Skytte Jørgensen { 61995fe467eeSIvan Skytte Jørgensen struct sctp_association *asoc; 62005fe467eeSIvan Skytte Jørgensen int cnt = 0; 62015fe467eeSIvan Skytte Jørgensen struct sctp_getaddrs getaddrs; 62025fe467eeSIvan Skytte Jørgensen struct sctp_transport *from; 62035fe467eeSIvan Skytte Jørgensen void __user *to; 62045fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 62055fe467eeSIvan Skytte Jørgensen struct sctp_sock *sp = sctp_sk(sk); 62065fe467eeSIvan Skytte Jørgensen int addrlen; 62075fe467eeSIvan Skytte Jørgensen size_t space_left; 62085fe467eeSIvan Skytte Jørgensen int bytes_copied; 62095fe467eeSIvan Skytte Jørgensen 62105fe467eeSIvan Skytte Jørgensen if (len < sizeof(struct sctp_getaddrs)) 62115fe467eeSIvan Skytte Jørgensen return -EINVAL; 62125fe467eeSIvan Skytte Jørgensen 62135fe467eeSIvan Skytte Jørgensen if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 62145fe467eeSIvan Skytte Jørgensen return -EFAULT; 62155fe467eeSIvan Skytte Jørgensen 62165fe467eeSIvan Skytte Jørgensen /* For UDP-style sockets, id specifies the association to query. */ 62175fe467eeSIvan Skytte Jørgensen asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 62185fe467eeSIvan Skytte Jørgensen if (!asoc) 62195fe467eeSIvan Skytte Jørgensen return -EINVAL; 62205fe467eeSIvan Skytte Jørgensen 62215fe467eeSIvan Skytte Jørgensen to = optval + offsetof(struct sctp_getaddrs, addrs); 6222186e2343SNeil Horman space_left = len - offsetof(struct sctp_getaddrs, addrs); 62235fe467eeSIvan Skytte Jørgensen 62249dbc15f0SRobert P. J. Day list_for_each_entry(from, &asoc->peer.transport_addr_list, 62259dbc15f0SRobert P. J. Day transports) { 6226b3f5b3b6SAl Viro memcpy(&temp, &from->ipaddr, sizeof(temp)); 6227299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 6228299ee123SJason Gunthorpe ->addr_to_user(sp, &temp); 62295fe467eeSIvan Skytte Jørgensen if (space_left < addrlen) 62305fe467eeSIvan Skytte Jørgensen return -ENOMEM; 62315fe467eeSIvan Skytte Jørgensen if (copy_to_user(to, &temp, addrlen)) 62325fe467eeSIvan Skytte Jørgensen return -EFAULT; 62335fe467eeSIvan Skytte Jørgensen to += addrlen; 62345fe467eeSIvan Skytte Jørgensen cnt++; 62355fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 62365fe467eeSIvan Skytte Jørgensen } 62375fe467eeSIvan Skytte Jørgensen 62385fe467eeSIvan Skytte Jørgensen if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) 62395fe467eeSIvan Skytte Jørgensen return -EFAULT; 62405fe467eeSIvan Skytte Jørgensen bytes_copied = ((char __user *)to) - optval; 62415fe467eeSIvan Skytte Jørgensen if (put_user(bytes_copied, optlen)) 62425fe467eeSIvan Skytte Jørgensen return -EFAULT; 62435fe467eeSIvan Skytte Jørgensen 62445fe467eeSIvan Skytte Jørgensen return 0; 62455fe467eeSIvan Skytte Jørgensen } 62465fe467eeSIvan Skytte Jørgensen 6247aad97f38SVlad Yasevich static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, 6248aad97f38SVlad Yasevich size_t space_left, int *bytes_copied) 62495fe467eeSIvan Skytte Jørgensen { 62505fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry *addr; 62515fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 62525fe467eeSIvan Skytte Jørgensen int cnt = 0; 62535fe467eeSIvan Skytte Jørgensen int addrlen; 62544db67e80SEric W. Biederman struct net *net = sock_net(sk); 62555fe467eeSIvan Skytte Jørgensen 625629303547SVlad Yasevich rcu_read_lock(); 62574db67e80SEric W. Biederman list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) { 625829303547SVlad Yasevich if (!addr->valid) 625929303547SVlad Yasevich continue; 626029303547SVlad Yasevich 62615fe467eeSIvan Skytte Jørgensen if ((PF_INET == sk->sk_family) && 62626244be4eSAl Viro (AF_INET6 == addr->a.sa.sa_family)) 62635fe467eeSIvan Skytte Jørgensen continue; 62647dab83deSVlad Yasevich if ((PF_INET6 == sk->sk_family) && 62657dab83deSVlad Yasevich inet_v6_ipv6only(sk) && 62667dab83deSVlad Yasevich (AF_INET == addr->a.sa.sa_family)) 62677dab83deSVlad Yasevich continue; 62686244be4eSAl Viro memcpy(&temp, &addr->a, sizeof(temp)); 6269b46ae36dSVlad Yasevich if (!temp.v4.sin_port) 6270b46ae36dSVlad Yasevich temp.v4.sin_port = htons(port); 6271b46ae36dSVlad Yasevich 6272299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 6273299ee123SJason Gunthorpe ->addr_to_user(sctp_sk(sk), &temp); 6274299ee123SJason Gunthorpe 627529303547SVlad Yasevich if (space_left < addrlen) { 627629303547SVlad Yasevich cnt = -ENOMEM; 627729303547SVlad Yasevich break; 627829303547SVlad Yasevich } 6279aad97f38SVlad Yasevich memcpy(to, &temp, addrlen); 628029c7cf96SSridhar Samudrala 6281aad97f38SVlad Yasevich to += addrlen; 62825fe467eeSIvan Skytte Jørgensen cnt++; 62835fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 62843663c306SVlad Yasevich *bytes_copied += addrlen; 62855fe467eeSIvan Skytte Jørgensen } 628629303547SVlad Yasevich rcu_read_unlock(); 62875fe467eeSIvan Skytte Jørgensen 62885fe467eeSIvan Skytte Jørgensen return cnt; 62895fe467eeSIvan Skytte Jørgensen } 62905fe467eeSIvan Skytte Jørgensen 62911da177e4SLinus Torvalds 62925fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_local_addrs(struct sock *sk, int len, 62935fe467eeSIvan Skytte Jørgensen char __user *optval, int __user *optlen) 62945fe467eeSIvan Skytte Jørgensen { 62955fe467eeSIvan Skytte Jørgensen struct sctp_bind_addr *bp; 62965fe467eeSIvan Skytte Jørgensen struct sctp_association *asoc; 62975fe467eeSIvan Skytte Jørgensen int cnt = 0; 62985fe467eeSIvan Skytte Jørgensen struct sctp_getaddrs getaddrs; 62995fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry *addr; 63005fe467eeSIvan Skytte Jørgensen void __user *to; 63015fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 63025fe467eeSIvan Skytte Jørgensen struct sctp_sock *sp = sctp_sk(sk); 63035fe467eeSIvan Skytte Jørgensen int addrlen; 63045fe467eeSIvan Skytte Jørgensen int err = 0; 63055fe467eeSIvan Skytte Jørgensen size_t space_left; 6306aad97f38SVlad Yasevich int bytes_copied = 0; 6307aad97f38SVlad Yasevich void *addrs; 630870b57b81SVlad Yasevich void *buf; 63095fe467eeSIvan Skytte Jørgensen 6310408f22e8SNeil Horman if (len < sizeof(struct sctp_getaddrs)) 63115fe467eeSIvan Skytte Jørgensen return -EINVAL; 63125fe467eeSIvan Skytte Jørgensen 63135fe467eeSIvan Skytte Jørgensen if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 63145fe467eeSIvan Skytte Jørgensen return -EFAULT; 63155fe467eeSIvan Skytte Jørgensen 63165fe467eeSIvan Skytte Jørgensen /* 63175fe467eeSIvan Skytte Jørgensen * For UDP-style sockets, id specifies the association to query. 63185fe467eeSIvan Skytte Jørgensen * If the id field is set to the value '0' then the locally bound 63195fe467eeSIvan Skytte Jørgensen * addresses are returned without regard to any particular 63205fe467eeSIvan Skytte Jørgensen * association. 63215fe467eeSIvan Skytte Jørgensen */ 63225fe467eeSIvan Skytte Jørgensen if (0 == getaddrs.assoc_id) { 63235fe467eeSIvan Skytte Jørgensen bp = &sctp_sk(sk)->ep->base.bind_addr; 63245fe467eeSIvan Skytte Jørgensen } else { 63255fe467eeSIvan Skytte Jørgensen asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 63265fe467eeSIvan Skytte Jørgensen if (!asoc) 63275fe467eeSIvan Skytte Jørgensen return -EINVAL; 63285fe467eeSIvan Skytte Jørgensen bp = &asoc->base.bind_addr; 63295fe467eeSIvan Skytte Jørgensen } 63305fe467eeSIvan Skytte Jørgensen 63315fe467eeSIvan Skytte Jørgensen to = optval + offsetof(struct sctp_getaddrs, addrs); 6332186e2343SNeil Horman space_left = len - offsetof(struct sctp_getaddrs, addrs); 6333186e2343SNeil Horman 6334cacc0621SMarcelo Ricardo Leitner addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN); 6335aad97f38SVlad Yasevich if (!addrs) 6336aad97f38SVlad Yasevich return -ENOMEM; 63375fe467eeSIvan Skytte Jørgensen 63385fe467eeSIvan Skytte Jørgensen /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid 63395fe467eeSIvan Skytte Jørgensen * addresses from the global local address list. 63405fe467eeSIvan Skytte Jørgensen */ 63415fe467eeSIvan Skytte Jørgensen if (sctp_list_single_entry(&bp->address_list)) { 63425fe467eeSIvan Skytte Jørgensen addr = list_entry(bp->address_list.next, 63435fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry, list); 634452cae8f0SVlad Yasevich if (sctp_is_any(sk, &addr->a)) { 6345aad97f38SVlad Yasevich cnt = sctp_copy_laddrs(sk, bp->port, addrs, 6346aad97f38SVlad Yasevich space_left, &bytes_copied); 63475fe467eeSIvan Skytte Jørgensen if (cnt < 0) { 63485fe467eeSIvan Skytte Jørgensen err = cnt; 6349559cf710SVlad Yasevich goto out; 63505fe467eeSIvan Skytte Jørgensen } 63515fe467eeSIvan Skytte Jørgensen goto copy_getaddrs; 63525fe467eeSIvan Skytte Jørgensen } 63535fe467eeSIvan Skytte Jørgensen } 63545fe467eeSIvan Skytte Jørgensen 635570b57b81SVlad Yasevich buf = addrs; 6356559cf710SVlad Yasevich /* Protection on the bound address list is not needed since 6357559cf710SVlad Yasevich * in the socket option context we hold a socket lock and 6358559cf710SVlad Yasevich * thus the bound address list can't change. 6359559cf710SVlad Yasevich */ 6360559cf710SVlad Yasevich list_for_each_entry(addr, &bp->address_list, list) { 63616244be4eSAl Viro memcpy(&temp, &addr->a, sizeof(temp)); 6362299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 6363299ee123SJason Gunthorpe ->addr_to_user(sp, &temp); 6364aad97f38SVlad Yasevich if (space_left < addrlen) { 6365aad97f38SVlad Yasevich err = -ENOMEM; /*fixme: right error?*/ 6366559cf710SVlad Yasevich goto out; 63675fe467eeSIvan Skytte Jørgensen } 636870b57b81SVlad Yasevich memcpy(buf, &temp, addrlen); 636970b57b81SVlad Yasevich buf += addrlen; 6370aad97f38SVlad Yasevich bytes_copied += addrlen; 63715fe467eeSIvan Skytte Jørgensen cnt++; 63725fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 63735fe467eeSIvan Skytte Jørgensen } 63745fe467eeSIvan Skytte Jørgensen 63755fe467eeSIvan Skytte Jørgensen copy_getaddrs: 6376aad97f38SVlad Yasevich if (copy_to_user(to, addrs, bytes_copied)) { 6377aad97f38SVlad Yasevich err = -EFAULT; 6378d6f9fdafSSebastian Siewior goto out; 6379aad97f38SVlad Yasevich } 6380fe979ac1SVlad Yasevich if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) { 6381fe979ac1SVlad Yasevich err = -EFAULT; 6382d6f9fdafSSebastian Siewior goto out; 6383fe979ac1SVlad Yasevich } 6384c76f97c9SMarcelo Ricardo Leitner /* XXX: We should have accounted for sizeof(struct sctp_getaddrs) too, 6385c76f97c9SMarcelo Ricardo Leitner * but we can't change it anymore. 6386c76f97c9SMarcelo Ricardo Leitner */ 63875fe467eeSIvan Skytte Jørgensen if (put_user(bytes_copied, optlen)) 6388fe979ac1SVlad Yasevich err = -EFAULT; 6389d6f9fdafSSebastian Siewior out: 6390aad97f38SVlad Yasevich kfree(addrs); 63915fe467eeSIvan Skytte Jørgensen return err; 63925fe467eeSIvan Skytte Jørgensen } 63935fe467eeSIvan Skytte Jørgensen 63941da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 63951da177e4SLinus Torvalds * 63961da177e4SLinus Torvalds * Requests that the local SCTP stack use the enclosed peer address as 63971da177e4SLinus Torvalds * the association primary. The enclosed address must be one of the 63981da177e4SLinus Torvalds * association peer's addresses. 63991da177e4SLinus Torvalds */ 64001da177e4SLinus Torvalds static int sctp_getsockopt_primary_addr(struct sock *sk, int len, 64011da177e4SLinus Torvalds char __user *optval, int __user *optlen) 64021da177e4SLinus Torvalds { 64031da177e4SLinus Torvalds struct sctp_prim prim; 64041da177e4SLinus Torvalds struct sctp_association *asoc; 64051da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 64061da177e4SLinus Torvalds 6407408f22e8SNeil Horman if (len < sizeof(struct sctp_prim)) 64081da177e4SLinus Torvalds return -EINVAL; 64091da177e4SLinus Torvalds 6410408f22e8SNeil Horman len = sizeof(struct sctp_prim); 6411408f22e8SNeil Horman 6412408f22e8SNeil Horman if (copy_from_user(&prim, optval, len)) 64131da177e4SLinus Torvalds return -EFAULT; 64141da177e4SLinus Torvalds 64151da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); 64161da177e4SLinus Torvalds if (!asoc) 64171da177e4SLinus Torvalds return -EINVAL; 64181da177e4SLinus Torvalds 64191da177e4SLinus Torvalds if (!asoc->peer.primary_path) 64201da177e4SLinus Torvalds return -ENOTCONN; 64211da177e4SLinus Torvalds 64228cec6b80SAl Viro memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, 64238cec6b80SAl Viro asoc->peer.primary_path->af_specific->sockaddr_len); 64241da177e4SLinus Torvalds 6425299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp, 64261da177e4SLinus Torvalds (union sctp_addr *)&prim.ssp_addr); 64271da177e4SLinus Torvalds 6428408f22e8SNeil Horman if (put_user(len, optlen)) 6429408f22e8SNeil Horman return -EFAULT; 6430408f22e8SNeil Horman if (copy_to_user(optval, &prim, len)) 64311da177e4SLinus Torvalds return -EFAULT; 64321da177e4SLinus Torvalds 64331da177e4SLinus Torvalds return 0; 64341da177e4SLinus Torvalds } 64351da177e4SLinus Torvalds 64361da177e4SLinus Torvalds /* 64370f3fffd8SIvan Skytte Jorgensen * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) 64381da177e4SLinus Torvalds * 64390f3fffd8SIvan Skytte Jorgensen * Requests that the local endpoint set the specified Adaptation Layer 64401da177e4SLinus Torvalds * Indication parameter for all future INIT and INIT-ACK exchanges. 64411da177e4SLinus Torvalds */ 64420f3fffd8SIvan Skytte Jorgensen static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len, 64431da177e4SLinus Torvalds char __user *optval, int __user *optlen) 64441da177e4SLinus Torvalds { 64450f3fffd8SIvan Skytte Jorgensen struct sctp_setadaptation adaptation; 64461da177e4SLinus Torvalds 6447408f22e8SNeil Horman if (len < sizeof(struct sctp_setadaptation)) 64481da177e4SLinus Torvalds return -EINVAL; 64491da177e4SLinus Torvalds 6450408f22e8SNeil Horman len = sizeof(struct sctp_setadaptation); 6451408f22e8SNeil Horman 64520f3fffd8SIvan Skytte Jorgensen adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind; 6453408f22e8SNeil Horman 6454408f22e8SNeil Horman if (put_user(len, optlen)) 6455408f22e8SNeil Horman return -EFAULT; 64560f3fffd8SIvan Skytte Jorgensen if (copy_to_user(optval, &adaptation, len)) 64571da177e4SLinus Torvalds return -EFAULT; 6458a1ab3582SIvan Skytte Jorgensen 64591da177e4SLinus Torvalds return 0; 64601da177e4SLinus Torvalds } 64611da177e4SLinus Torvalds 64621da177e4SLinus Torvalds /* 64631da177e4SLinus Torvalds * 64641da177e4SLinus Torvalds * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 64651da177e4SLinus Torvalds * 64661da177e4SLinus Torvalds * Applications that wish to use the sendto() system call may wish to 64671da177e4SLinus Torvalds * specify a default set of parameters that would normally be supplied 64681da177e4SLinus Torvalds * through the inclusion of ancillary data. This socket option allows 64691da177e4SLinus Torvalds * such an application to set the default sctp_sndrcvinfo structure. 64701da177e4SLinus Torvalds 64711da177e4SLinus Torvalds 64721da177e4SLinus Torvalds * The application that wishes to use this socket option simply passes 64731da177e4SLinus Torvalds * in to this call the sctp_sndrcvinfo structure defined in Section 64741da177e4SLinus Torvalds * 5.2.2) The input parameters accepted by this call include 64751da177e4SLinus Torvalds * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 64761da177e4SLinus Torvalds * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 64771da177e4SLinus Torvalds * to this call if the caller is using the UDP model. 64781da177e4SLinus Torvalds * 64791da177e4SLinus Torvalds * For getsockopt, it get the default sctp_sndrcvinfo structure. 64801da177e4SLinus Torvalds */ 64811da177e4SLinus Torvalds static int sctp_getsockopt_default_send_param(struct sock *sk, 64821da177e4SLinus Torvalds int len, char __user *optval, 64831da177e4SLinus Torvalds int __user *optlen) 64841da177e4SLinus Torvalds { 64851da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 64866b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 64876b3fd5f3SGeir Ola Vaagland struct sctp_sndrcvinfo info; 64881da177e4SLinus Torvalds 64896b3fd5f3SGeir Ola Vaagland if (len < sizeof(info)) 64901da177e4SLinus Torvalds return -EINVAL; 6491408f22e8SNeil Horman 64926b3fd5f3SGeir Ola Vaagland len = sizeof(info); 6493408f22e8SNeil Horman 6494408f22e8SNeil Horman if (copy_from_user(&info, optval, len)) 64951da177e4SLinus Torvalds return -EFAULT; 64961da177e4SLinus Torvalds 64971da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); 6498707e45b3SXin Long if (!asoc && info.sinfo_assoc_id != SCTP_FUTURE_ASSOC && 6499707e45b3SXin Long sctp_style(sk, UDP)) 65001da177e4SLinus Torvalds return -EINVAL; 6501707e45b3SXin Long 65021da177e4SLinus Torvalds if (asoc) { 65031da177e4SLinus Torvalds info.sinfo_stream = asoc->default_stream; 65041da177e4SLinus Torvalds info.sinfo_flags = asoc->default_flags; 65051da177e4SLinus Torvalds info.sinfo_ppid = asoc->default_ppid; 65061da177e4SLinus Torvalds info.sinfo_context = asoc->default_context; 65071da177e4SLinus Torvalds info.sinfo_timetolive = asoc->default_timetolive; 65081da177e4SLinus Torvalds } else { 65091da177e4SLinus Torvalds info.sinfo_stream = sp->default_stream; 65101da177e4SLinus Torvalds info.sinfo_flags = sp->default_flags; 65111da177e4SLinus Torvalds info.sinfo_ppid = sp->default_ppid; 65121da177e4SLinus Torvalds info.sinfo_context = sp->default_context; 65131da177e4SLinus Torvalds info.sinfo_timetolive = sp->default_timetolive; 65141da177e4SLinus Torvalds } 65151da177e4SLinus Torvalds 6516408f22e8SNeil Horman if (put_user(len, optlen)) 6517408f22e8SNeil Horman return -EFAULT; 6518408f22e8SNeil Horman if (copy_to_user(optval, &info, len)) 65191da177e4SLinus Torvalds return -EFAULT; 65201da177e4SLinus Torvalds 65211da177e4SLinus Torvalds return 0; 65221da177e4SLinus Torvalds } 65231da177e4SLinus Torvalds 65246b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters 65256b3fd5f3SGeir Ola Vaagland * (SCTP_DEFAULT_SNDINFO) 65266b3fd5f3SGeir Ola Vaagland */ 65276b3fd5f3SGeir Ola Vaagland static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len, 65286b3fd5f3SGeir Ola Vaagland char __user *optval, 65296b3fd5f3SGeir Ola Vaagland int __user *optlen) 65306b3fd5f3SGeir Ola Vaagland { 65316b3fd5f3SGeir Ola Vaagland struct sctp_sock *sp = sctp_sk(sk); 65326b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 65336b3fd5f3SGeir Ola Vaagland struct sctp_sndinfo info; 65346b3fd5f3SGeir Ola Vaagland 65356b3fd5f3SGeir Ola Vaagland if (len < sizeof(info)) 65366b3fd5f3SGeir Ola Vaagland return -EINVAL; 65376b3fd5f3SGeir Ola Vaagland 65386b3fd5f3SGeir Ola Vaagland len = sizeof(info); 65396b3fd5f3SGeir Ola Vaagland 65406b3fd5f3SGeir Ola Vaagland if (copy_from_user(&info, optval, len)) 65416b3fd5f3SGeir Ola Vaagland return -EFAULT; 65426b3fd5f3SGeir Ola Vaagland 65436b3fd5f3SGeir Ola Vaagland asoc = sctp_id2assoc(sk, info.snd_assoc_id); 654492fc3bd9SXin Long if (!asoc && info.snd_assoc_id != SCTP_FUTURE_ASSOC && 654592fc3bd9SXin Long sctp_style(sk, UDP)) 65466b3fd5f3SGeir Ola Vaagland return -EINVAL; 654792fc3bd9SXin Long 65486b3fd5f3SGeir Ola Vaagland if (asoc) { 65496b3fd5f3SGeir Ola Vaagland info.snd_sid = asoc->default_stream; 65506b3fd5f3SGeir Ola Vaagland info.snd_flags = asoc->default_flags; 65516b3fd5f3SGeir Ola Vaagland info.snd_ppid = asoc->default_ppid; 65526b3fd5f3SGeir Ola Vaagland info.snd_context = asoc->default_context; 65536b3fd5f3SGeir Ola Vaagland } else { 65546b3fd5f3SGeir Ola Vaagland info.snd_sid = sp->default_stream; 65556b3fd5f3SGeir Ola Vaagland info.snd_flags = sp->default_flags; 65566b3fd5f3SGeir Ola Vaagland info.snd_ppid = sp->default_ppid; 65576b3fd5f3SGeir Ola Vaagland info.snd_context = sp->default_context; 65586b3fd5f3SGeir Ola Vaagland } 65596b3fd5f3SGeir Ola Vaagland 65606b3fd5f3SGeir Ola Vaagland if (put_user(len, optlen)) 65616b3fd5f3SGeir Ola Vaagland return -EFAULT; 65626b3fd5f3SGeir Ola Vaagland if (copy_to_user(optval, &info, len)) 65636b3fd5f3SGeir Ola Vaagland return -EFAULT; 65646b3fd5f3SGeir Ola Vaagland 65656b3fd5f3SGeir Ola Vaagland return 0; 65666b3fd5f3SGeir Ola Vaagland } 65676b3fd5f3SGeir Ola Vaagland 65681da177e4SLinus Torvalds /* 65691da177e4SLinus Torvalds * 65701da177e4SLinus Torvalds * 7.1.5 SCTP_NODELAY 65711da177e4SLinus Torvalds * 65721da177e4SLinus Torvalds * Turn on/off any Nagle-like algorithm. This means that packets are 65731da177e4SLinus Torvalds * generally sent as soon as possible and no unnecessary delays are 65741da177e4SLinus Torvalds * introduced, at the cost of more packets in the network. Expects an 65751da177e4SLinus Torvalds * integer boolean flag. 65761da177e4SLinus Torvalds */ 65771da177e4SLinus Torvalds 65781da177e4SLinus Torvalds static int sctp_getsockopt_nodelay(struct sock *sk, int len, 65791da177e4SLinus Torvalds char __user *optval, int __user *optlen) 65801da177e4SLinus Torvalds { 65811da177e4SLinus Torvalds int val; 65821da177e4SLinus Torvalds 65831da177e4SLinus Torvalds if (len < sizeof(int)) 65841da177e4SLinus Torvalds return -EINVAL; 65851da177e4SLinus Torvalds 65861da177e4SLinus Torvalds len = sizeof(int); 65871da177e4SLinus Torvalds val = (sctp_sk(sk)->nodelay == 1); 65881da177e4SLinus Torvalds if (put_user(len, optlen)) 65891da177e4SLinus Torvalds return -EFAULT; 65901da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 65911da177e4SLinus Torvalds return -EFAULT; 65921da177e4SLinus Torvalds return 0; 65931da177e4SLinus Torvalds } 65941da177e4SLinus Torvalds 65951da177e4SLinus Torvalds /* 65961da177e4SLinus Torvalds * 65971da177e4SLinus Torvalds * 7.1.1 SCTP_RTOINFO 65981da177e4SLinus Torvalds * 65991da177e4SLinus Torvalds * The protocol parameters used to initialize and bound retransmission 66001da177e4SLinus Torvalds * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 66011da177e4SLinus Torvalds * and modify these parameters. 66021da177e4SLinus Torvalds * All parameters are time values, in milliseconds. A value of 0, when 66031da177e4SLinus Torvalds * modifying the parameters, indicates that the current value should not 66041da177e4SLinus Torvalds * be changed. 66051da177e4SLinus Torvalds * 66061da177e4SLinus Torvalds */ 66071da177e4SLinus Torvalds static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, 66081da177e4SLinus Torvalds char __user *optval, 66091da177e4SLinus Torvalds int __user *optlen) { 66101da177e4SLinus Torvalds struct sctp_rtoinfo rtoinfo; 66111da177e4SLinus Torvalds struct sctp_association *asoc; 66121da177e4SLinus Torvalds 6613408f22e8SNeil Horman if (len < sizeof (struct sctp_rtoinfo)) 66141da177e4SLinus Torvalds return -EINVAL; 66151da177e4SLinus Torvalds 6616408f22e8SNeil Horman len = sizeof(struct sctp_rtoinfo); 6617408f22e8SNeil Horman 6618408f22e8SNeil Horman if (copy_from_user(&rtoinfo, optval, len)) 66191da177e4SLinus Torvalds return -EFAULT; 66201da177e4SLinus Torvalds 66211da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); 66221da177e4SLinus Torvalds 66237adb5ed5SXin Long if (!asoc && rtoinfo.srto_assoc_id != SCTP_FUTURE_ASSOC && 66247adb5ed5SXin Long sctp_style(sk, UDP)) 66251da177e4SLinus Torvalds return -EINVAL; 66261da177e4SLinus Torvalds 66271da177e4SLinus Torvalds /* Values corresponding to the specific association. */ 66281da177e4SLinus Torvalds if (asoc) { 66291da177e4SLinus Torvalds rtoinfo.srto_initial = jiffies_to_msecs(asoc->rto_initial); 66301da177e4SLinus Torvalds rtoinfo.srto_max = jiffies_to_msecs(asoc->rto_max); 66311da177e4SLinus Torvalds rtoinfo.srto_min = jiffies_to_msecs(asoc->rto_min); 66321da177e4SLinus Torvalds } else { 66331da177e4SLinus Torvalds /* Values corresponding to the endpoint. */ 66341da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 66351da177e4SLinus Torvalds 66361da177e4SLinus Torvalds rtoinfo.srto_initial = sp->rtoinfo.srto_initial; 66371da177e4SLinus Torvalds rtoinfo.srto_max = sp->rtoinfo.srto_max; 66381da177e4SLinus Torvalds rtoinfo.srto_min = sp->rtoinfo.srto_min; 66391da177e4SLinus Torvalds } 66401da177e4SLinus Torvalds 66411da177e4SLinus Torvalds if (put_user(len, optlen)) 66421da177e4SLinus Torvalds return -EFAULT; 66431da177e4SLinus Torvalds 66441da177e4SLinus Torvalds if (copy_to_user(optval, &rtoinfo, len)) 66451da177e4SLinus Torvalds return -EFAULT; 66461da177e4SLinus Torvalds 66471da177e4SLinus Torvalds return 0; 66481da177e4SLinus Torvalds } 66491da177e4SLinus Torvalds 66501da177e4SLinus Torvalds /* 66511da177e4SLinus Torvalds * 66521da177e4SLinus Torvalds * 7.1.2 SCTP_ASSOCINFO 66531da177e4SLinus Torvalds * 665459c51591SMichael Opdenacker * This option is used to tune the maximum retransmission attempts 66551da177e4SLinus Torvalds * of the association. 66561da177e4SLinus Torvalds * Returns an error if the new association retransmission value is 66571da177e4SLinus Torvalds * greater than the sum of the retransmission value of the peer. 66581da177e4SLinus Torvalds * See [SCTP] for more information. 66591da177e4SLinus Torvalds * 66601da177e4SLinus Torvalds */ 66611da177e4SLinus Torvalds static int sctp_getsockopt_associnfo(struct sock *sk, int len, 66621da177e4SLinus Torvalds char __user *optval, 66631da177e4SLinus Torvalds int __user *optlen) 66641da177e4SLinus Torvalds { 66651da177e4SLinus Torvalds 66661da177e4SLinus Torvalds struct sctp_assocparams assocparams; 66671da177e4SLinus Torvalds struct sctp_association *asoc; 66681da177e4SLinus Torvalds struct list_head *pos; 66691da177e4SLinus Torvalds int cnt = 0; 66701da177e4SLinus Torvalds 6671408f22e8SNeil Horman if (len < sizeof (struct sctp_assocparams)) 66721da177e4SLinus Torvalds return -EINVAL; 66731da177e4SLinus Torvalds 6674408f22e8SNeil Horman len = sizeof(struct sctp_assocparams); 6675408f22e8SNeil Horman 6676408f22e8SNeil Horman if (copy_from_user(&assocparams, optval, len)) 66771da177e4SLinus Torvalds return -EFAULT; 66781da177e4SLinus Torvalds 66791da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); 66801da177e4SLinus Torvalds 66818889394dSXin Long if (!asoc && assocparams.sasoc_assoc_id != SCTP_FUTURE_ASSOC && 66828889394dSXin Long sctp_style(sk, UDP)) 66831da177e4SLinus Torvalds return -EINVAL; 66841da177e4SLinus Torvalds 66851da177e4SLinus Torvalds /* Values correspoinding to the specific association */ 668617337216SVladislav Yasevich if (asoc) { 66871da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt = asoc->max_retrans; 66881da177e4SLinus Torvalds assocparams.sasoc_peer_rwnd = asoc->peer.rwnd; 66891da177e4SLinus Torvalds assocparams.sasoc_local_rwnd = asoc->a_rwnd; 669052db882fSDaniel Borkmann assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life); 66911da177e4SLinus Torvalds 66921da177e4SLinus Torvalds list_for_each(pos, &asoc->peer.transport_addr_list) { 66931da177e4SLinus Torvalds cnt++; 66941da177e4SLinus Torvalds } 66951da177e4SLinus Torvalds 66961da177e4SLinus Torvalds assocparams.sasoc_number_peer_destinations = cnt; 66971da177e4SLinus Torvalds } else { 66981da177e4SLinus Torvalds /* Values corresponding to the endpoint */ 66991da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 67001da177e4SLinus Torvalds 67011da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt; 67021da177e4SLinus Torvalds assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd; 67031da177e4SLinus Torvalds assocparams.sasoc_local_rwnd = sp->assocparams.sasoc_local_rwnd; 67041da177e4SLinus Torvalds assocparams.sasoc_cookie_life = 67051da177e4SLinus Torvalds sp->assocparams.sasoc_cookie_life; 67061da177e4SLinus Torvalds assocparams.sasoc_number_peer_destinations = 67071da177e4SLinus Torvalds sp->assocparams. 67081da177e4SLinus Torvalds sasoc_number_peer_destinations; 67091da177e4SLinus Torvalds } 67101da177e4SLinus Torvalds 67111da177e4SLinus Torvalds if (put_user(len, optlen)) 67121da177e4SLinus Torvalds return -EFAULT; 67131da177e4SLinus Torvalds 67141da177e4SLinus Torvalds if (copy_to_user(optval, &assocparams, len)) 67151da177e4SLinus Torvalds return -EFAULT; 67161da177e4SLinus Torvalds 67171da177e4SLinus Torvalds return 0; 67181da177e4SLinus Torvalds } 67191da177e4SLinus Torvalds 67201da177e4SLinus Torvalds /* 67211da177e4SLinus Torvalds * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 67221da177e4SLinus Torvalds * 67231da177e4SLinus Torvalds * This socket option is a boolean flag which turns on or off mapped V4 67241da177e4SLinus Torvalds * addresses. If this option is turned on and the socket is type 67251da177e4SLinus Torvalds * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 67261da177e4SLinus Torvalds * If this option is turned off, then no mapping will be done of V4 67271da177e4SLinus Torvalds * addresses and a user will receive both PF_INET6 and PF_INET type 67281da177e4SLinus Torvalds * addresses on the socket. 67291da177e4SLinus Torvalds */ 67301da177e4SLinus Torvalds static int sctp_getsockopt_mappedv4(struct sock *sk, int len, 67311da177e4SLinus Torvalds char __user *optval, int __user *optlen) 67321da177e4SLinus Torvalds { 67331da177e4SLinus Torvalds int val; 67341da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 67351da177e4SLinus Torvalds 67361da177e4SLinus Torvalds if (len < sizeof(int)) 67371da177e4SLinus Torvalds return -EINVAL; 67381da177e4SLinus Torvalds 67391da177e4SLinus Torvalds len = sizeof(int); 67401da177e4SLinus Torvalds val = sp->v4mapped; 67411da177e4SLinus Torvalds if (put_user(len, optlen)) 67421da177e4SLinus Torvalds return -EFAULT; 67431da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 67441da177e4SLinus Torvalds return -EFAULT; 67451da177e4SLinus Torvalds 67461da177e4SLinus Torvalds return 0; 67471da177e4SLinus Torvalds } 67481da177e4SLinus Torvalds 67491da177e4SLinus Torvalds /* 67506ab792f5SIvan Skytte Jorgensen * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 67516ab792f5SIvan Skytte Jorgensen * (chapter and verse is quoted at sctp_setsockopt_context()) 67526ab792f5SIvan Skytte Jorgensen */ 67536ab792f5SIvan Skytte Jorgensen static int sctp_getsockopt_context(struct sock *sk, int len, 67546ab792f5SIvan Skytte Jorgensen char __user *optval, int __user *optlen) 67556ab792f5SIvan Skytte Jorgensen { 67566ab792f5SIvan Skytte Jorgensen struct sctp_assoc_value params; 67576ab792f5SIvan Skytte Jorgensen struct sctp_association *asoc; 67586ab792f5SIvan Skytte Jorgensen 6759408f22e8SNeil Horman if (len < sizeof(struct sctp_assoc_value)) 67606ab792f5SIvan Skytte Jorgensen return -EINVAL; 67616ab792f5SIvan Skytte Jorgensen 6762408f22e8SNeil Horman len = sizeof(struct sctp_assoc_value); 6763408f22e8SNeil Horman 67646ab792f5SIvan Skytte Jorgensen if (copy_from_user(¶ms, optval, len)) 67656ab792f5SIvan Skytte Jorgensen return -EFAULT; 67666ab792f5SIvan Skytte Jorgensen 67676ab792f5SIvan Skytte Jorgensen asoc = sctp_id2assoc(sk, params.assoc_id); 676849b037acSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 676949b037acSXin Long sctp_style(sk, UDP)) 67706ab792f5SIvan Skytte Jorgensen return -EINVAL; 677149b037acSXin Long 677249b037acSXin Long params.assoc_value = asoc ? asoc->default_rcv_context 677349b037acSXin Long : sctp_sk(sk)->default_rcv_context; 67746ab792f5SIvan Skytte Jorgensen 67756ab792f5SIvan Skytte Jorgensen if (put_user(len, optlen)) 67766ab792f5SIvan Skytte Jorgensen return -EFAULT; 67776ab792f5SIvan Skytte Jorgensen if (copy_to_user(optval, ¶ms, len)) 67786ab792f5SIvan Skytte Jorgensen return -EFAULT; 67796ab792f5SIvan Skytte Jorgensen 67806ab792f5SIvan Skytte Jorgensen return 0; 67816ab792f5SIvan Skytte Jorgensen } 67826ab792f5SIvan Skytte Jorgensen 67836ab792f5SIvan Skytte Jorgensen /* 6784e89c2095SWei Yongjun * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 6785e89c2095SWei Yongjun * This option will get or set the maximum size to put in any outgoing 6786e89c2095SWei Yongjun * SCTP DATA chunk. If a message is larger than this size it will be 67871da177e4SLinus Torvalds * fragmented by SCTP into the specified size. Note that the underlying 67881da177e4SLinus Torvalds * SCTP implementation may fragment into smaller sized chunks when the 67891da177e4SLinus Torvalds * PMTU of the underlying association is smaller than the value set by 6790e89c2095SWei Yongjun * the user. The default value for this option is '0' which indicates 6791e89c2095SWei Yongjun * the user is NOT limiting fragmentation and only the PMTU will effect 6792e89c2095SWei Yongjun * SCTP's choice of DATA chunk size. Note also that values set larger 6793e89c2095SWei Yongjun * than the maximum size of an IP datagram will effectively let SCTP 6794e89c2095SWei Yongjun * control fragmentation (i.e. the same as setting this option to 0). 6795e89c2095SWei Yongjun * 6796e89c2095SWei Yongjun * The following structure is used to access and modify this parameter: 6797e89c2095SWei Yongjun * 6798e89c2095SWei Yongjun * struct sctp_assoc_value { 6799e89c2095SWei Yongjun * sctp_assoc_t assoc_id; 6800e89c2095SWei Yongjun * uint32_t assoc_value; 6801e89c2095SWei Yongjun * }; 6802e89c2095SWei Yongjun * 6803e89c2095SWei Yongjun * assoc_id: This parameter is ignored for one-to-one style sockets. 6804e89c2095SWei Yongjun * For one-to-many style sockets this parameter indicates which 6805e89c2095SWei Yongjun * association the user is performing an action upon. Note that if 6806e89c2095SWei Yongjun * this field's value is zero then the endpoints default value is 6807e89c2095SWei Yongjun * changed (effecting future associations only). 6808e89c2095SWei Yongjun * assoc_value: This parameter specifies the maximum size in bytes. 68091da177e4SLinus Torvalds */ 68101da177e4SLinus Torvalds static int sctp_getsockopt_maxseg(struct sock *sk, int len, 68111da177e4SLinus Torvalds char __user *optval, int __user *optlen) 68121da177e4SLinus Torvalds { 6813e89c2095SWei Yongjun struct sctp_assoc_value params; 6814e89c2095SWei Yongjun struct sctp_association *asoc; 68151da177e4SLinus Torvalds 6816e89c2095SWei Yongjun if (len == sizeof(int)) { 681794f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 6818f916ec96SNeil Horman "%s (pid %d) " 681994f65193SNeil Horman "Use of int in maxseg socket option.\n" 6820f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 6821f916ec96SNeil Horman current->comm, task_pid_nr(current)); 68226fd769beSXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 6823e89c2095SWei Yongjun } else if (len >= sizeof(struct sctp_assoc_value)) { 6824e89c2095SWei Yongjun len = sizeof(struct sctp_assoc_value); 6825c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, len)) 6826e89c2095SWei Yongjun return -EFAULT; 6827e89c2095SWei Yongjun } else 68281da177e4SLinus Torvalds return -EINVAL; 68291da177e4SLinus Torvalds 6830e89c2095SWei Yongjun asoc = sctp_id2assoc(sk, params.assoc_id); 68316fd769beSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 68326fd769beSXin Long sctp_style(sk, UDP)) 6833e89c2095SWei Yongjun return -EINVAL; 68341da177e4SLinus Torvalds 6835e89c2095SWei Yongjun if (asoc) 6836e89c2095SWei Yongjun params.assoc_value = asoc->frag_point; 6837e89c2095SWei Yongjun else 6838e89c2095SWei Yongjun params.assoc_value = sctp_sk(sk)->user_frag; 6839e89c2095SWei Yongjun 68401da177e4SLinus Torvalds if (put_user(len, optlen)) 68411da177e4SLinus Torvalds return -EFAULT; 6842e89c2095SWei Yongjun if (len == sizeof(int)) { 6843e89c2095SWei Yongjun if (copy_to_user(optval, ¶ms.assoc_value, len)) 68441da177e4SLinus Torvalds return -EFAULT; 6845e89c2095SWei Yongjun } else { 6846e89c2095SWei Yongjun if (copy_to_user(optval, ¶ms, len)) 6847e89c2095SWei Yongjun return -EFAULT; 6848e89c2095SWei Yongjun } 68491da177e4SLinus Torvalds 68501da177e4SLinus Torvalds return 0; 68511da177e4SLinus Torvalds } 68521da177e4SLinus Torvalds 6853b6e1331fSVlad Yasevich /* 6854b6e1331fSVlad Yasevich * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 6855b6e1331fSVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_fragment_interleave()) 6856b6e1331fSVlad Yasevich */ 6857b6e1331fSVlad Yasevich static int sctp_getsockopt_fragment_interleave(struct sock *sk, int len, 6858b6e1331fSVlad Yasevich char __user *optval, int __user *optlen) 6859b6e1331fSVlad Yasevich { 6860b6e1331fSVlad Yasevich int val; 6861b6e1331fSVlad Yasevich 6862b6e1331fSVlad Yasevich if (len < sizeof(int)) 6863b6e1331fSVlad Yasevich return -EINVAL; 6864b6e1331fSVlad Yasevich 6865b6e1331fSVlad Yasevich len = sizeof(int); 6866b6e1331fSVlad Yasevich 6867b6e1331fSVlad Yasevich val = sctp_sk(sk)->frag_interleave; 6868b6e1331fSVlad Yasevich if (put_user(len, optlen)) 6869b6e1331fSVlad Yasevich return -EFAULT; 6870b6e1331fSVlad Yasevich if (copy_to_user(optval, &val, len)) 6871b6e1331fSVlad Yasevich return -EFAULT; 6872b6e1331fSVlad Yasevich 6873b6e1331fSVlad Yasevich return 0; 6874b6e1331fSVlad Yasevich } 6875b6e1331fSVlad Yasevich 6876d49d91d7SVlad Yasevich /* 6877d49d91d7SVlad Yasevich * 7.1.25. Set or Get the sctp partial delivery point 6878d49d91d7SVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_partial_delivery_point()) 6879d49d91d7SVlad Yasevich */ 6880d49d91d7SVlad Yasevich static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len, 6881d49d91d7SVlad Yasevich char __user *optval, 6882d49d91d7SVlad Yasevich int __user *optlen) 6883d49d91d7SVlad Yasevich { 6884d49d91d7SVlad Yasevich u32 val; 6885d49d91d7SVlad Yasevich 6886d49d91d7SVlad Yasevich if (len < sizeof(u32)) 6887d49d91d7SVlad Yasevich return -EINVAL; 6888d49d91d7SVlad Yasevich 6889d49d91d7SVlad Yasevich len = sizeof(u32); 6890d49d91d7SVlad Yasevich 6891d49d91d7SVlad Yasevich val = sctp_sk(sk)->pd_point; 6892d49d91d7SVlad Yasevich if (put_user(len, optlen)) 6893d49d91d7SVlad Yasevich return -EFAULT; 6894d49d91d7SVlad Yasevich if (copy_to_user(optval, &val, len)) 6895d49d91d7SVlad Yasevich return -EFAULT; 6896d49d91d7SVlad Yasevich 68977d743b7eSWei Yongjun return 0; 6898d49d91d7SVlad Yasevich } 6899d49d91d7SVlad Yasevich 690070331571SVlad Yasevich /* 690170331571SVlad Yasevich * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 690270331571SVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_maxburst()) 690370331571SVlad Yasevich */ 690470331571SVlad Yasevich static int sctp_getsockopt_maxburst(struct sock *sk, int len, 690570331571SVlad Yasevich char __user *optval, 690670331571SVlad Yasevich int __user *optlen) 690770331571SVlad Yasevich { 6908219b99a9SNeil Horman struct sctp_assoc_value params; 6909219b99a9SNeil Horman struct sctp_association *asoc; 691070331571SVlad Yasevich 6911219b99a9SNeil Horman if (len == sizeof(int)) { 691294f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 6913f916ec96SNeil Horman "%s (pid %d) " 691494f65193SNeil Horman "Use of int in max_burst socket option.\n" 6915f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 6916f916ec96SNeil Horman current->comm, task_pid_nr(current)); 6917e0651a0dSXin Long params.assoc_id = SCTP_FUTURE_ASSOC; 6918c6db93a5SWei Yongjun } else if (len >= sizeof(struct sctp_assoc_value)) { 6919c6db93a5SWei Yongjun len = sizeof(struct sctp_assoc_value); 6920219b99a9SNeil Horman if (copy_from_user(¶ms, optval, len)) 692170331571SVlad Yasevich return -EFAULT; 6922219b99a9SNeil Horman } else 6923219b99a9SNeil Horman return -EINVAL; 692470331571SVlad Yasevich 6925219b99a9SNeil Horman asoc = sctp_id2assoc(sk, params.assoc_id); 6926e0651a0dSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 6927e0651a0dSXin Long sctp_style(sk, UDP)) 6928219b99a9SNeil Horman return -EINVAL; 6929e0651a0dSXin Long 6930e0651a0dSXin Long params.assoc_value = asoc ? asoc->max_burst : sctp_sk(sk)->max_burst; 6931219b99a9SNeil Horman 6932219b99a9SNeil Horman if (len == sizeof(int)) { 6933219b99a9SNeil Horman if (copy_to_user(optval, ¶ms.assoc_value, len)) 6934219b99a9SNeil Horman return -EFAULT; 6935219b99a9SNeil Horman } else { 6936219b99a9SNeil Horman if (copy_to_user(optval, ¶ms, len)) 6937219b99a9SNeil Horman return -EFAULT; 6938219b99a9SNeil Horman } 6939219b99a9SNeil Horman 6940219b99a9SNeil Horman return 0; 6941219b99a9SNeil Horman 694270331571SVlad Yasevich } 694370331571SVlad Yasevich 694465b07e5dSVlad Yasevich static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, 694565b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 694665b07e5dSVlad Yasevich { 6947b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 69485e739d17SVlad Yasevich struct sctp_hmacalgo __user *p = (void __user *)optval; 694965b07e5dSVlad Yasevich struct sctp_hmac_algo_param *hmacs; 69505e739d17SVlad Yasevich __u16 data_len = 0; 69515e739d17SVlad Yasevich u32 num_idents; 69527a84bd46SXin Long int i; 69535e739d17SVlad Yasevich 6954b14878ccSVlad Yasevich if (!ep->auth_enable) 69555e739d17SVlad Yasevich return -EACCES; 695665b07e5dSVlad Yasevich 6957b14878ccSVlad Yasevich hmacs = ep->auth_hmacs_list; 69583c918704SXin Long data_len = ntohs(hmacs->param_hdr.length) - 69593c918704SXin Long sizeof(struct sctp_paramhdr); 696065b07e5dSVlad Yasevich 69615e739d17SVlad Yasevich if (len < sizeof(struct sctp_hmacalgo) + data_len) 696265b07e5dSVlad Yasevich return -EINVAL; 69635e739d17SVlad Yasevich 69645e739d17SVlad Yasevich len = sizeof(struct sctp_hmacalgo) + data_len; 69655e739d17SVlad Yasevich num_idents = data_len / sizeof(u16); 69665e739d17SVlad Yasevich 696765b07e5dSVlad Yasevich if (put_user(len, optlen)) 696865b07e5dSVlad Yasevich return -EFAULT; 69695e739d17SVlad Yasevich if (put_user(num_idents, &p->shmac_num_idents)) 697065b07e5dSVlad Yasevich return -EFAULT; 69717a84bd46SXin Long for (i = 0; i < num_idents; i++) { 69727a84bd46SXin Long __u16 hmacid = ntohs(hmacs->hmac_ids[i]); 69737a84bd46SXin Long 69747a84bd46SXin Long if (copy_to_user(&p->shmac_idents[i], &hmacid, sizeof(__u16))) 69755e739d17SVlad Yasevich return -EFAULT; 69767a84bd46SXin Long } 697765b07e5dSVlad Yasevich return 0; 697865b07e5dSVlad Yasevich } 697965b07e5dSVlad Yasevich 698065b07e5dSVlad Yasevich static int sctp_getsockopt_active_key(struct sock *sk, int len, 698165b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 698265b07e5dSVlad Yasevich { 6983b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 698465b07e5dSVlad Yasevich struct sctp_authkeyid val; 698565b07e5dSVlad Yasevich struct sctp_association *asoc; 698665b07e5dSVlad Yasevich 698765b07e5dSVlad Yasevich if (len < sizeof(struct sctp_authkeyid)) 698865b07e5dSVlad Yasevich return -EINVAL; 6989c76f97c9SMarcelo Ricardo Leitner 6990c76f97c9SMarcelo Ricardo Leitner len = sizeof(struct sctp_authkeyid); 6991c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(&val, optval, len)) 699265b07e5dSVlad Yasevich return -EFAULT; 699365b07e5dSVlad Yasevich 699465b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 699565b07e5dSVlad Yasevich if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 699665b07e5dSVlad Yasevich return -EINVAL; 699765b07e5dSVlad Yasevich 6998219f9ea4SXin Long if (asoc) { 6999219f9ea4SXin Long if (!asoc->peer.auth_capable) 7000219f9ea4SXin Long return -EACCES; 700165b07e5dSVlad Yasevich val.scact_keynumber = asoc->active_key_id; 7002219f9ea4SXin Long } else { 7003219f9ea4SXin Long if (!ep->auth_enable) 7004219f9ea4SXin Long return -EACCES; 7005b14878ccSVlad Yasevich val.scact_keynumber = ep->active_key_id; 7006219f9ea4SXin Long } 700765b07e5dSVlad Yasevich 70085e739d17SVlad Yasevich if (put_user(len, optlen)) 70095e739d17SVlad Yasevich return -EFAULT; 70105e739d17SVlad Yasevich if (copy_to_user(optval, &val, len)) 70115e739d17SVlad Yasevich return -EFAULT; 70125e739d17SVlad Yasevich 701365b07e5dSVlad Yasevich return 0; 701465b07e5dSVlad Yasevich } 701565b07e5dSVlad Yasevich 701665b07e5dSVlad Yasevich static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, 701765b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 701865b07e5dSVlad Yasevich { 7019411223c0SAl Viro struct sctp_authchunks __user *p = (void __user *)optval; 702065b07e5dSVlad Yasevich struct sctp_authchunks val; 702165b07e5dSVlad Yasevich struct sctp_association *asoc; 702265b07e5dSVlad Yasevich struct sctp_chunks_param *ch; 70235e739d17SVlad Yasevich u32 num_chunks = 0; 702465b07e5dSVlad Yasevich char __user *to; 702565b07e5dSVlad Yasevich 70265e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks)) 702765b07e5dSVlad Yasevich return -EINVAL; 702865b07e5dSVlad Yasevich 7029c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(&val, optval, sizeof(val))) 703065b07e5dSVlad Yasevich return -EFAULT; 703165b07e5dSVlad Yasevich 7032411223c0SAl Viro to = p->gauth_chunks; 703365b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 703465b07e5dSVlad Yasevich if (!asoc) 703565b07e5dSVlad Yasevich return -EINVAL; 703665b07e5dSVlad Yasevich 7037219f9ea4SXin Long if (!asoc->peer.auth_capable) 7038219f9ea4SXin Long return -EACCES; 7039219f9ea4SXin Long 704065b07e5dSVlad Yasevich ch = asoc->peer.peer_chunks; 70415e739d17SVlad Yasevich if (!ch) 70425e739d17SVlad Yasevich goto num; 704365b07e5dSVlad Yasevich 704465b07e5dSVlad Yasevich /* See if the user provided enough room for all the data */ 70453c918704SXin Long num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); 7046b40db684SVlad Yasevich if (len < num_chunks) 704765b07e5dSVlad Yasevich return -EINVAL; 704865b07e5dSVlad Yasevich 70495e739d17SVlad Yasevich if (copy_to_user(to, ch->chunks, num_chunks)) 705065b07e5dSVlad Yasevich return -EFAULT; 70515e739d17SVlad Yasevich num: 70525e739d17SVlad Yasevich len = sizeof(struct sctp_authchunks) + num_chunks; 70538d72651dSwangweidong if (put_user(len, optlen)) 70548d72651dSwangweidong return -EFAULT; 70557e8616d8SVlad Yasevich if (put_user(num_chunks, &p->gauth_number_of_chunks)) 70567e8616d8SVlad Yasevich return -EFAULT; 705765b07e5dSVlad Yasevich return 0; 705865b07e5dSVlad Yasevich } 705965b07e5dSVlad Yasevich 706065b07e5dSVlad Yasevich static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, 706165b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 706265b07e5dSVlad Yasevich { 7063b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 7064411223c0SAl Viro struct sctp_authchunks __user *p = (void __user *)optval; 706565b07e5dSVlad Yasevich struct sctp_authchunks val; 706665b07e5dSVlad Yasevich struct sctp_association *asoc; 706765b07e5dSVlad Yasevich struct sctp_chunks_param *ch; 70685e739d17SVlad Yasevich u32 num_chunks = 0; 706965b07e5dSVlad Yasevich char __user *to; 707065b07e5dSVlad Yasevich 70715e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks)) 707265b07e5dSVlad Yasevich return -EINVAL; 707365b07e5dSVlad Yasevich 7074c76f97c9SMarcelo Ricardo Leitner if (copy_from_user(&val, optval, sizeof(val))) 707565b07e5dSVlad Yasevich return -EFAULT; 707665b07e5dSVlad Yasevich 7077411223c0SAl Viro to = p->gauth_chunks; 707865b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 707948c07217SXin Long if (!asoc && val.gauth_assoc_id != SCTP_FUTURE_ASSOC && 708048c07217SXin Long sctp_style(sk, UDP)) 708165b07e5dSVlad Yasevich return -EINVAL; 708265b07e5dSVlad Yasevich 7083219f9ea4SXin Long if (asoc) { 7084219f9ea4SXin Long if (!asoc->peer.auth_capable) 7085219f9ea4SXin Long return -EACCES; 7086219f9ea4SXin Long ch = (struct sctp_chunks_param *)asoc->c.auth_chunks; 7087219f9ea4SXin Long } else { 7088219f9ea4SXin Long if (!ep->auth_enable) 7089219f9ea4SXin Long return -EACCES; 7090219f9ea4SXin Long ch = ep->auth_chunk_list; 7091219f9ea4SXin Long } 70925e739d17SVlad Yasevich if (!ch) 70935e739d17SVlad Yasevich goto num; 70945e739d17SVlad Yasevich 70953c918704SXin Long num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); 70965e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks) + num_chunks) 709765b07e5dSVlad Yasevich return -EINVAL; 709865b07e5dSVlad Yasevich 70995e739d17SVlad Yasevich if (copy_to_user(to, ch->chunks, num_chunks)) 71005e739d17SVlad Yasevich return -EFAULT; 71015e739d17SVlad Yasevich num: 71025e739d17SVlad Yasevich len = sizeof(struct sctp_authchunks) + num_chunks; 710365b07e5dSVlad Yasevich if (put_user(len, optlen)) 710465b07e5dSVlad Yasevich return -EFAULT; 71057e8616d8SVlad Yasevich if (put_user(num_chunks, &p->gauth_number_of_chunks)) 71067e8616d8SVlad Yasevich return -EFAULT; 710765b07e5dSVlad Yasevich 710865b07e5dSVlad Yasevich return 0; 710965b07e5dSVlad Yasevich } 711065b07e5dSVlad Yasevich 7111aea3c5c0SWei Yongjun /* 7112aea3c5c0SWei Yongjun * 8.2.5. Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER) 7113aea3c5c0SWei Yongjun * This option gets the current number of associations that are attached 7114aea3c5c0SWei Yongjun * to a one-to-many style socket. The option value is an uint32_t. 7115aea3c5c0SWei Yongjun */ 7116aea3c5c0SWei Yongjun static int sctp_getsockopt_assoc_number(struct sock *sk, int len, 7117aea3c5c0SWei Yongjun char __user *optval, int __user *optlen) 7118aea3c5c0SWei Yongjun { 7119aea3c5c0SWei Yongjun struct sctp_sock *sp = sctp_sk(sk); 7120aea3c5c0SWei Yongjun struct sctp_association *asoc; 7121aea3c5c0SWei Yongjun u32 val = 0; 7122aea3c5c0SWei Yongjun 7123aea3c5c0SWei Yongjun if (sctp_style(sk, TCP)) 7124aea3c5c0SWei Yongjun return -EOPNOTSUPP; 7125aea3c5c0SWei Yongjun 7126aea3c5c0SWei Yongjun if (len < sizeof(u32)) 7127aea3c5c0SWei Yongjun return -EINVAL; 7128aea3c5c0SWei Yongjun 7129aea3c5c0SWei Yongjun len = sizeof(u32); 7130aea3c5c0SWei Yongjun 7131aea3c5c0SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 7132aea3c5c0SWei Yongjun val++; 7133aea3c5c0SWei Yongjun } 7134aea3c5c0SWei Yongjun 7135aea3c5c0SWei Yongjun if (put_user(len, optlen)) 7136aea3c5c0SWei Yongjun return -EFAULT; 7137aea3c5c0SWei Yongjun if (copy_to_user(optval, &val, len)) 7138aea3c5c0SWei Yongjun return -EFAULT; 7139aea3c5c0SWei Yongjun 7140aea3c5c0SWei Yongjun return 0; 7141aea3c5c0SWei Yongjun } 7142aea3c5c0SWei Yongjun 7143209ba424SWei Yongjun /* 71447dc04d71SMichio Honda * 8.1.23 SCTP_AUTO_ASCONF 71457dc04d71SMichio Honda * See the corresponding setsockopt entry as description 71467dc04d71SMichio Honda */ 71477dc04d71SMichio Honda static int sctp_getsockopt_auto_asconf(struct sock *sk, int len, 71487dc04d71SMichio Honda char __user *optval, int __user *optlen) 71497dc04d71SMichio Honda { 71507dc04d71SMichio Honda int val = 0; 71517dc04d71SMichio Honda 71527dc04d71SMichio Honda if (len < sizeof(int)) 71537dc04d71SMichio Honda return -EINVAL; 71547dc04d71SMichio Honda 71557dc04d71SMichio Honda len = sizeof(int); 71567dc04d71SMichio Honda if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk)) 71577dc04d71SMichio Honda val = 1; 71587dc04d71SMichio Honda if (put_user(len, optlen)) 71597dc04d71SMichio Honda return -EFAULT; 71607dc04d71SMichio Honda if (copy_to_user(optval, &val, len)) 71617dc04d71SMichio Honda return -EFAULT; 71627dc04d71SMichio Honda return 0; 71637dc04d71SMichio Honda } 71647dc04d71SMichio Honda 71657dc04d71SMichio Honda /* 7166209ba424SWei Yongjun * 8.2.6. Get the Current Identifiers of Associations 7167209ba424SWei Yongjun * (SCTP_GET_ASSOC_ID_LIST) 7168209ba424SWei Yongjun * 7169209ba424SWei Yongjun * This option gets the current list of SCTP association identifiers of 7170209ba424SWei Yongjun * the SCTP associations handled by a one-to-many style socket. 7171209ba424SWei Yongjun */ 7172209ba424SWei Yongjun static int sctp_getsockopt_assoc_ids(struct sock *sk, int len, 7173209ba424SWei Yongjun char __user *optval, int __user *optlen) 7174209ba424SWei Yongjun { 7175209ba424SWei Yongjun struct sctp_sock *sp = sctp_sk(sk); 7176209ba424SWei Yongjun struct sctp_association *asoc; 7177209ba424SWei Yongjun struct sctp_assoc_ids *ids; 7178209ba424SWei Yongjun u32 num = 0; 7179209ba424SWei Yongjun 7180209ba424SWei Yongjun if (sctp_style(sk, TCP)) 7181209ba424SWei Yongjun return -EOPNOTSUPP; 7182209ba424SWei Yongjun 7183209ba424SWei Yongjun if (len < sizeof(struct sctp_assoc_ids)) 7184209ba424SWei Yongjun return -EINVAL; 7185209ba424SWei Yongjun 7186209ba424SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 7187209ba424SWei Yongjun num++; 7188209ba424SWei Yongjun } 7189209ba424SWei Yongjun 7190209ba424SWei Yongjun if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num) 7191209ba424SWei Yongjun return -EINVAL; 7192209ba424SWei Yongjun 7193209ba424SWei Yongjun len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num; 7194209ba424SWei Yongjun 71959ba0b963SMarcelo Ricardo Leitner ids = kmalloc(len, GFP_USER | __GFP_NOWARN); 7196209ba424SWei Yongjun if (unlikely(!ids)) 7197209ba424SWei Yongjun return -ENOMEM; 7198209ba424SWei Yongjun 7199209ba424SWei Yongjun ids->gaids_number_of_ids = num; 7200209ba424SWei Yongjun num = 0; 7201209ba424SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 7202209ba424SWei Yongjun ids->gaids_assoc_id[num++] = asoc->assoc_id; 7203209ba424SWei Yongjun } 7204209ba424SWei Yongjun 7205209ba424SWei Yongjun if (put_user(len, optlen) || copy_to_user(optval, ids, len)) { 7206209ba424SWei Yongjun kfree(ids); 7207209ba424SWei Yongjun return -EFAULT; 7208209ba424SWei Yongjun } 7209209ba424SWei Yongjun 7210209ba424SWei Yongjun kfree(ids); 7211209ba424SWei Yongjun return 0; 7212209ba424SWei Yongjun } 7213209ba424SWei Yongjun 72145aa93bcfSNeil Horman /* 72155aa93bcfSNeil Horman * SCTP_PEER_ADDR_THLDS 72165aa93bcfSNeil Horman * 72175aa93bcfSNeil Horman * This option allows us to fetch the partially failed threshold for one or all 72185aa93bcfSNeil Horman * transports in an association. See Section 6.1 of: 72195aa93bcfSNeil Horman * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 72205aa93bcfSNeil Horman */ 72215aa93bcfSNeil Horman static int sctp_getsockopt_paddr_thresholds(struct sock *sk, 7222d467ac0aSXin Long char __user *optval, int len, 7223d467ac0aSXin Long int __user *optlen, bool v2) 72245aa93bcfSNeil Horman { 7225d467ac0aSXin Long struct sctp_paddrthlds_v2 val; 72265aa93bcfSNeil Horman struct sctp_transport *trans; 72275aa93bcfSNeil Horman struct sctp_association *asoc; 7228d467ac0aSXin Long int min; 72295aa93bcfSNeil Horman 7230d467ac0aSXin Long min = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds); 7231d467ac0aSXin Long if (len < min) 72325aa93bcfSNeil Horman return -EINVAL; 7233d467ac0aSXin Long len = min; 7234d467ac0aSXin Long if (copy_from_user(&val, optval, len)) 72355aa93bcfSNeil Horman return -EFAULT; 72365aa93bcfSNeil Horman 72378add543eSXin Long if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { 72385aa93bcfSNeil Horman trans = sctp_addr_id2transport(sk, &val.spt_address, 72395aa93bcfSNeil Horman val.spt_assoc_id); 72405aa93bcfSNeil Horman if (!trans) 72415aa93bcfSNeil Horman return -ENOENT; 72425aa93bcfSNeil Horman 72435aa93bcfSNeil Horman val.spt_pathmaxrxt = trans->pathmaxrxt; 72445aa93bcfSNeil Horman val.spt_pathpfthld = trans->pf_retrans; 7245d467ac0aSXin Long val.spt_pathcpthld = trans->ps_retrans; 72468add543eSXin Long 7247f794dc23SXin Long goto out; 72488add543eSXin Long } 72498add543eSXin Long 72508add543eSXin Long asoc = sctp_id2assoc(sk, val.spt_assoc_id); 72518add543eSXin Long if (!asoc && val.spt_assoc_id != SCTP_FUTURE_ASSOC && 72528add543eSXin Long sctp_style(sk, UDP)) 72538add543eSXin Long return -EINVAL; 72548add543eSXin Long 72558add543eSXin Long if (asoc) { 72568add543eSXin Long val.spt_pathpfthld = asoc->pf_retrans; 72578add543eSXin Long val.spt_pathmaxrxt = asoc->pathmaxrxt; 7258d467ac0aSXin Long val.spt_pathcpthld = asoc->ps_retrans; 72598add543eSXin Long } else { 72608add543eSXin Long struct sctp_sock *sp = sctp_sk(sk); 72618add543eSXin Long 72628add543eSXin Long val.spt_pathpfthld = sp->pf_retrans; 72638add543eSXin Long val.spt_pathmaxrxt = sp->pathmaxrxt; 7264d467ac0aSXin Long val.spt_pathcpthld = sp->ps_retrans; 72655aa93bcfSNeil Horman } 72665aa93bcfSNeil Horman 7267f794dc23SXin Long out: 72685aa93bcfSNeil Horman if (put_user(len, optlen) || copy_to_user(optval, &val, len)) 72695aa93bcfSNeil Horman return -EFAULT; 72705aa93bcfSNeil Horman 72715aa93bcfSNeil Horman return 0; 72725aa93bcfSNeil Horman } 72735aa93bcfSNeil Horman 7274196d6759SMichele Baldessari /* 7275196d6759SMichele Baldessari * SCTP_GET_ASSOC_STATS 7276196d6759SMichele Baldessari * 7277196d6759SMichele Baldessari * This option retrieves local per endpoint statistics. It is modeled 7278196d6759SMichele Baldessari * after OpenSolaris' implementation 7279196d6759SMichele Baldessari */ 7280196d6759SMichele Baldessari static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, 7281196d6759SMichele Baldessari char __user *optval, 7282196d6759SMichele Baldessari int __user *optlen) 7283196d6759SMichele Baldessari { 7284196d6759SMichele Baldessari struct sctp_assoc_stats sas; 7285196d6759SMichele Baldessari struct sctp_association *asoc = NULL; 7286196d6759SMichele Baldessari 7287196d6759SMichele Baldessari /* User must provide at least the assoc id */ 7288196d6759SMichele Baldessari if (len < sizeof(sctp_assoc_t)) 7289196d6759SMichele Baldessari return -EINVAL; 7290196d6759SMichele Baldessari 7291726bc6b0SGuenter Roeck /* Allow the struct to grow and fill in as much as possible */ 7292726bc6b0SGuenter Roeck len = min_t(size_t, len, sizeof(sas)); 7293726bc6b0SGuenter Roeck 7294196d6759SMichele Baldessari if (copy_from_user(&sas, optval, len)) 7295196d6759SMichele Baldessari return -EFAULT; 7296196d6759SMichele Baldessari 7297196d6759SMichele Baldessari asoc = sctp_id2assoc(sk, sas.sas_assoc_id); 7298196d6759SMichele Baldessari if (!asoc) 7299196d6759SMichele Baldessari return -EINVAL; 7300196d6759SMichele Baldessari 7301196d6759SMichele Baldessari sas.sas_rtxchunks = asoc->stats.rtxchunks; 7302196d6759SMichele Baldessari sas.sas_gapcnt = asoc->stats.gapcnt; 7303196d6759SMichele Baldessari sas.sas_outofseqtsns = asoc->stats.outofseqtsns; 7304196d6759SMichele Baldessari sas.sas_osacks = asoc->stats.osacks; 7305196d6759SMichele Baldessari sas.sas_isacks = asoc->stats.isacks; 7306196d6759SMichele Baldessari sas.sas_octrlchunks = asoc->stats.octrlchunks; 7307196d6759SMichele Baldessari sas.sas_ictrlchunks = asoc->stats.ictrlchunks; 7308196d6759SMichele Baldessari sas.sas_oodchunks = asoc->stats.oodchunks; 7309196d6759SMichele Baldessari sas.sas_iodchunks = asoc->stats.iodchunks; 7310196d6759SMichele Baldessari sas.sas_ouodchunks = asoc->stats.ouodchunks; 7311196d6759SMichele Baldessari sas.sas_iuodchunks = asoc->stats.iuodchunks; 7312196d6759SMichele Baldessari sas.sas_idupchunks = asoc->stats.idupchunks; 7313196d6759SMichele Baldessari sas.sas_opackets = asoc->stats.opackets; 7314196d6759SMichele Baldessari sas.sas_ipackets = asoc->stats.ipackets; 7315196d6759SMichele Baldessari 7316196d6759SMichele Baldessari /* New high max rto observed, will return 0 if not a single 7317196d6759SMichele Baldessari * RTO update took place. obs_rto_ipaddr will be bogus 7318196d6759SMichele Baldessari * in such a case 7319196d6759SMichele Baldessari */ 7320196d6759SMichele Baldessari sas.sas_maxrto = asoc->stats.max_obs_rto; 7321196d6759SMichele Baldessari memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr, 7322196d6759SMichele Baldessari sizeof(struct sockaddr_storage)); 7323196d6759SMichele Baldessari 7324196d6759SMichele Baldessari /* Mark beginning of a new observation period */ 7325196d6759SMichele Baldessari asoc->stats.max_obs_rto = asoc->rto_min; 7326196d6759SMichele Baldessari 7327196d6759SMichele Baldessari if (put_user(len, optlen)) 7328196d6759SMichele Baldessari return -EFAULT; 7329196d6759SMichele Baldessari 7330bb33381dSDaniel Borkmann pr_debug("%s: len:%d, assoc_id:%d\n", __func__, len, sas.sas_assoc_id); 7331196d6759SMichele Baldessari 7332196d6759SMichele Baldessari if (copy_to_user(optval, &sas, len)) 7333196d6759SMichele Baldessari return -EFAULT; 7334196d6759SMichele Baldessari 7335196d6759SMichele Baldessari return 0; 7336196d6759SMichele Baldessari } 7337196d6759SMichele Baldessari 73380d3a421dSGeir Ola Vaagland static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, 73390d3a421dSGeir Ola Vaagland char __user *optval, 73400d3a421dSGeir Ola Vaagland int __user *optlen) 73410d3a421dSGeir Ola Vaagland { 73420d3a421dSGeir Ola Vaagland int val = 0; 73430d3a421dSGeir Ola Vaagland 73440d3a421dSGeir Ola Vaagland if (len < sizeof(int)) 73450d3a421dSGeir Ola Vaagland return -EINVAL; 73460d3a421dSGeir Ola Vaagland 73470d3a421dSGeir Ola Vaagland len = sizeof(int); 73480d3a421dSGeir Ola Vaagland if (sctp_sk(sk)->recvrcvinfo) 73490d3a421dSGeir Ola Vaagland val = 1; 73500d3a421dSGeir Ola Vaagland if (put_user(len, optlen)) 73510d3a421dSGeir Ola Vaagland return -EFAULT; 73520d3a421dSGeir Ola Vaagland if (copy_to_user(optval, &val, len)) 73530d3a421dSGeir Ola Vaagland return -EFAULT; 73540d3a421dSGeir Ola Vaagland 73550d3a421dSGeir Ola Vaagland return 0; 73560d3a421dSGeir Ola Vaagland } 73570d3a421dSGeir Ola Vaagland 73582347c80fSGeir Ola Vaagland static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len, 73592347c80fSGeir Ola Vaagland char __user *optval, 73602347c80fSGeir Ola Vaagland int __user *optlen) 73612347c80fSGeir Ola Vaagland { 73622347c80fSGeir Ola Vaagland int val = 0; 73632347c80fSGeir Ola Vaagland 73642347c80fSGeir Ola Vaagland if (len < sizeof(int)) 73652347c80fSGeir Ola Vaagland return -EINVAL; 73662347c80fSGeir Ola Vaagland 73672347c80fSGeir Ola Vaagland len = sizeof(int); 73682347c80fSGeir Ola Vaagland if (sctp_sk(sk)->recvnxtinfo) 73692347c80fSGeir Ola Vaagland val = 1; 73702347c80fSGeir Ola Vaagland if (put_user(len, optlen)) 73712347c80fSGeir Ola Vaagland return -EFAULT; 73722347c80fSGeir Ola Vaagland if (copy_to_user(optval, &val, len)) 73732347c80fSGeir Ola Vaagland return -EFAULT; 73742347c80fSGeir Ola Vaagland 73752347c80fSGeir Ola Vaagland return 0; 73762347c80fSGeir Ola Vaagland } 73772347c80fSGeir Ola Vaagland 737828aa4c26SXin Long static int sctp_getsockopt_pr_supported(struct sock *sk, int len, 737928aa4c26SXin Long char __user *optval, 738028aa4c26SXin Long int __user *optlen) 738128aa4c26SXin Long { 738228aa4c26SXin Long struct sctp_assoc_value params; 738328aa4c26SXin Long struct sctp_association *asoc; 738428aa4c26SXin Long int retval = -EFAULT; 738528aa4c26SXin Long 738628aa4c26SXin Long if (len < sizeof(params)) { 738728aa4c26SXin Long retval = -EINVAL; 738828aa4c26SXin Long goto out; 738928aa4c26SXin Long } 739028aa4c26SXin Long 739128aa4c26SXin Long len = sizeof(params); 739228aa4c26SXin Long if (copy_from_user(¶ms, optval, len)) 739328aa4c26SXin Long goto out; 739428aa4c26SXin Long 739528aa4c26SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7396fb195605SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 7397fb195605SXin Long sctp_style(sk, UDP)) { 739828aa4c26SXin Long retval = -EINVAL; 739928aa4c26SXin Long goto out; 740028aa4c26SXin Long } 740128aa4c26SXin Long 74021c134753SXin Long params.assoc_value = asoc ? asoc->peer.prsctp_capable 7403fb195605SXin Long : sctp_sk(sk)->ep->prsctp_enable; 7404fb195605SXin Long 740528aa4c26SXin Long if (put_user(len, optlen)) 740628aa4c26SXin Long goto out; 740728aa4c26SXin Long 740828aa4c26SXin Long if (copy_to_user(optval, ¶ms, len)) 740928aa4c26SXin Long goto out; 741028aa4c26SXin Long 741128aa4c26SXin Long retval = 0; 741228aa4c26SXin Long 741328aa4c26SXin Long out: 741428aa4c26SXin Long return retval; 741528aa4c26SXin Long } 741628aa4c26SXin Long 7417f959fb44SXin Long static int sctp_getsockopt_default_prinfo(struct sock *sk, int len, 7418f959fb44SXin Long char __user *optval, 7419f959fb44SXin Long int __user *optlen) 7420f959fb44SXin Long { 7421f959fb44SXin Long struct sctp_default_prinfo info; 7422f959fb44SXin Long struct sctp_association *asoc; 7423f959fb44SXin Long int retval = -EFAULT; 7424f959fb44SXin Long 7425f959fb44SXin Long if (len < sizeof(info)) { 7426f959fb44SXin Long retval = -EINVAL; 7427f959fb44SXin Long goto out; 7428f959fb44SXin Long } 7429f959fb44SXin Long 7430f959fb44SXin Long len = sizeof(info); 7431f959fb44SXin Long if (copy_from_user(&info, optval, len)) 7432f959fb44SXin Long goto out; 7433f959fb44SXin Long 7434f959fb44SXin Long asoc = sctp_id2assoc(sk, info.pr_assoc_id); 74353a583059SXin Long if (!asoc && info.pr_assoc_id != SCTP_FUTURE_ASSOC && 74363a583059SXin Long sctp_style(sk, UDP)) { 74373a583059SXin Long retval = -EINVAL; 74383a583059SXin Long goto out; 74393a583059SXin Long } 74403a583059SXin Long 7441f959fb44SXin Long if (asoc) { 7442f959fb44SXin Long info.pr_policy = SCTP_PR_POLICY(asoc->default_flags); 7443f959fb44SXin Long info.pr_value = asoc->default_timetolive; 74443a583059SXin Long } else { 7445f959fb44SXin Long struct sctp_sock *sp = sctp_sk(sk); 7446f959fb44SXin Long 7447f959fb44SXin Long info.pr_policy = SCTP_PR_POLICY(sp->default_flags); 7448f959fb44SXin Long info.pr_value = sp->default_timetolive; 7449f959fb44SXin Long } 7450f959fb44SXin Long 7451f959fb44SXin Long if (put_user(len, optlen)) 7452f959fb44SXin Long goto out; 7453f959fb44SXin Long 7454f959fb44SXin Long if (copy_to_user(optval, &info, len)) 7455f959fb44SXin Long goto out; 7456f959fb44SXin Long 7457f959fb44SXin Long retval = 0; 7458f959fb44SXin Long 7459f959fb44SXin Long out: 7460f959fb44SXin Long return retval; 7461f959fb44SXin Long } 7462f959fb44SXin Long 7463826d253dSXin Long static int sctp_getsockopt_pr_assocstatus(struct sock *sk, int len, 7464826d253dSXin Long char __user *optval, 7465826d253dSXin Long int __user *optlen) 7466826d253dSXin Long { 7467826d253dSXin Long struct sctp_prstatus params; 7468826d253dSXin Long struct sctp_association *asoc; 7469826d253dSXin Long int policy; 7470826d253dSXin Long int retval = -EINVAL; 7471826d253dSXin Long 7472826d253dSXin Long if (len < sizeof(params)) 7473826d253dSXin Long goto out; 7474826d253dSXin Long 7475826d253dSXin Long len = sizeof(params); 7476826d253dSXin Long if (copy_from_user(¶ms, optval, len)) { 7477826d253dSXin Long retval = -EFAULT; 7478826d253dSXin Long goto out; 7479826d253dSXin Long } 7480826d253dSXin Long 7481826d253dSXin Long policy = params.sprstat_policy; 748271335836SXin Long if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) || 748371335836SXin Long ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK))) 7484826d253dSXin Long goto out; 7485826d253dSXin Long 7486826d253dSXin Long asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); 7487826d253dSXin Long if (!asoc) 7488826d253dSXin Long goto out; 7489826d253dSXin Long 749071335836SXin Long if (policy == SCTP_PR_SCTP_ALL) { 7491826d253dSXin Long params.sprstat_abandoned_unsent = 0; 7492826d253dSXin Long params.sprstat_abandoned_sent = 0; 7493826d253dSXin Long for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { 7494826d253dSXin Long params.sprstat_abandoned_unsent += 7495826d253dSXin Long asoc->abandoned_unsent[policy]; 7496826d253dSXin Long params.sprstat_abandoned_sent += 7497826d253dSXin Long asoc->abandoned_sent[policy]; 7498826d253dSXin Long } 7499826d253dSXin Long } else { 7500826d253dSXin Long params.sprstat_abandoned_unsent = 7501826d253dSXin Long asoc->abandoned_unsent[__SCTP_PR_INDEX(policy)]; 7502826d253dSXin Long params.sprstat_abandoned_sent = 7503826d253dSXin Long asoc->abandoned_sent[__SCTP_PR_INDEX(policy)]; 7504826d253dSXin Long } 7505826d253dSXin Long 7506826d253dSXin Long if (put_user(len, optlen)) { 7507826d253dSXin Long retval = -EFAULT; 7508826d253dSXin Long goto out; 7509826d253dSXin Long } 7510826d253dSXin Long 7511826d253dSXin Long if (copy_to_user(optval, ¶ms, len)) { 7512826d253dSXin Long retval = -EFAULT; 7513826d253dSXin Long goto out; 7514826d253dSXin Long } 7515826d253dSXin Long 7516826d253dSXin Long retval = 0; 7517826d253dSXin Long 7518826d253dSXin Long out: 7519826d253dSXin Long return retval; 7520826d253dSXin Long } 7521826d253dSXin Long 7522d229d48dSXin Long static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len, 7523d229d48dSXin Long char __user *optval, 7524d229d48dSXin Long int __user *optlen) 7525d229d48dSXin Long { 7526f952be79SMarcelo Ricardo Leitner struct sctp_stream_out_ext *streamoute; 7527d229d48dSXin Long struct sctp_association *asoc; 7528d229d48dSXin Long struct sctp_prstatus params; 7529d229d48dSXin Long int retval = -EINVAL; 7530d229d48dSXin Long int policy; 7531d229d48dSXin Long 7532d229d48dSXin Long if (len < sizeof(params)) 7533d229d48dSXin Long goto out; 7534d229d48dSXin Long 7535d229d48dSXin Long len = sizeof(params); 7536d229d48dSXin Long if (copy_from_user(¶ms, optval, len)) { 7537d229d48dSXin Long retval = -EFAULT; 7538d229d48dSXin Long goto out; 7539d229d48dSXin Long } 7540d229d48dSXin Long 7541d229d48dSXin Long policy = params.sprstat_policy; 754271335836SXin Long if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) || 754371335836SXin Long ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK))) 7544d229d48dSXin Long goto out; 7545d229d48dSXin Long 7546d229d48dSXin Long asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); 7547cee360abSXin Long if (!asoc || params.sprstat_sid >= asoc->stream.outcnt) 7548d229d48dSXin Long goto out; 7549d229d48dSXin Long 755005364ca0SKonstantin Khorenko streamoute = SCTP_SO(&asoc->stream, params.sprstat_sid)->ext; 7551f952be79SMarcelo Ricardo Leitner if (!streamoute) { 7552f952be79SMarcelo Ricardo Leitner /* Not allocated yet, means all stats are 0 */ 7553f952be79SMarcelo Ricardo Leitner params.sprstat_abandoned_unsent = 0; 7554f952be79SMarcelo Ricardo Leitner params.sprstat_abandoned_sent = 0; 7555f952be79SMarcelo Ricardo Leitner retval = 0; 7556f952be79SMarcelo Ricardo Leitner goto out; 7557f952be79SMarcelo Ricardo Leitner } 7558f952be79SMarcelo Ricardo Leitner 75590ac1077eSXin Long if (policy == SCTP_PR_SCTP_ALL) { 7560d229d48dSXin Long params.sprstat_abandoned_unsent = 0; 7561d229d48dSXin Long params.sprstat_abandoned_sent = 0; 7562d229d48dSXin Long for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { 7563d229d48dSXin Long params.sprstat_abandoned_unsent += 7564f952be79SMarcelo Ricardo Leitner streamoute->abandoned_unsent[policy]; 7565d229d48dSXin Long params.sprstat_abandoned_sent += 7566f952be79SMarcelo Ricardo Leitner streamoute->abandoned_sent[policy]; 7567d229d48dSXin Long } 7568d229d48dSXin Long } else { 7569d229d48dSXin Long params.sprstat_abandoned_unsent = 7570f952be79SMarcelo Ricardo Leitner streamoute->abandoned_unsent[__SCTP_PR_INDEX(policy)]; 7571d229d48dSXin Long params.sprstat_abandoned_sent = 7572f952be79SMarcelo Ricardo Leitner streamoute->abandoned_sent[__SCTP_PR_INDEX(policy)]; 7573d229d48dSXin Long } 7574d229d48dSXin Long 7575d229d48dSXin Long if (put_user(len, optlen) || copy_to_user(optval, ¶ms, len)) { 7576d229d48dSXin Long retval = -EFAULT; 7577d229d48dSXin Long goto out; 7578d229d48dSXin Long } 7579d229d48dSXin Long 7580d229d48dSXin Long retval = 0; 7581d229d48dSXin Long 7582d229d48dSXin Long out: 7583d229d48dSXin Long return retval; 7584d229d48dSXin Long } 7585d229d48dSXin Long 7586c0d8bab6SXin Long static int sctp_getsockopt_reconfig_supported(struct sock *sk, int len, 7587c0d8bab6SXin Long char __user *optval, 7588c0d8bab6SXin Long int __user *optlen) 7589c0d8bab6SXin Long { 7590c0d8bab6SXin Long struct sctp_assoc_value params; 7591c0d8bab6SXin Long struct sctp_association *asoc; 7592c0d8bab6SXin Long int retval = -EFAULT; 7593c0d8bab6SXin Long 7594c0d8bab6SXin Long if (len < sizeof(params)) { 7595c0d8bab6SXin Long retval = -EINVAL; 7596c0d8bab6SXin Long goto out; 7597c0d8bab6SXin Long } 7598c0d8bab6SXin Long 7599c0d8bab6SXin Long len = sizeof(params); 7600c0d8bab6SXin Long if (copy_from_user(¶ms, optval, len)) 7601c0d8bab6SXin Long goto out; 7602c0d8bab6SXin Long 7603c0d8bab6SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7604acce7f3bSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 7605acce7f3bSXin Long sctp_style(sk, UDP)) { 7606c0d8bab6SXin Long retval = -EINVAL; 7607c0d8bab6SXin Long goto out; 7608c0d8bab6SXin Long } 7609c0d8bab6SXin Long 7610a96701fbSXin Long params.assoc_value = asoc ? asoc->peer.reconf_capable 7611acce7f3bSXin Long : sctp_sk(sk)->ep->reconf_enable; 7612acce7f3bSXin Long 7613c0d8bab6SXin Long if (put_user(len, optlen)) 7614c0d8bab6SXin Long goto out; 7615c0d8bab6SXin Long 7616c0d8bab6SXin Long if (copy_to_user(optval, ¶ms, len)) 7617c0d8bab6SXin Long goto out; 7618c0d8bab6SXin Long 7619c0d8bab6SXin Long retval = 0; 7620c0d8bab6SXin Long 7621c0d8bab6SXin Long out: 7622c0d8bab6SXin Long return retval; 7623c0d8bab6SXin Long } 7624c0d8bab6SXin Long 76259fb657aeSXin Long static int sctp_getsockopt_enable_strreset(struct sock *sk, int len, 76269fb657aeSXin Long char __user *optval, 76279fb657aeSXin Long int __user *optlen) 76289fb657aeSXin Long { 76299fb657aeSXin Long struct sctp_assoc_value params; 76309fb657aeSXin Long struct sctp_association *asoc; 76319fb657aeSXin Long int retval = -EFAULT; 76329fb657aeSXin Long 76339fb657aeSXin Long if (len < sizeof(params)) { 76349fb657aeSXin Long retval = -EINVAL; 76359fb657aeSXin Long goto out; 76369fb657aeSXin Long } 76379fb657aeSXin Long 76389fb657aeSXin Long len = sizeof(params); 76399fb657aeSXin Long if (copy_from_user(¶ms, optval, len)) 76409fb657aeSXin Long goto out; 76419fb657aeSXin Long 76429fb657aeSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 764399a62135SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 764499a62135SXin Long sctp_style(sk, UDP)) { 76459fb657aeSXin Long retval = -EINVAL; 76469fb657aeSXin Long goto out; 76479fb657aeSXin Long } 76489fb657aeSXin Long 764999a62135SXin Long params.assoc_value = asoc ? asoc->strreset_enable 765099a62135SXin Long : sctp_sk(sk)->ep->strreset_enable; 765199a62135SXin Long 76529fb657aeSXin Long if (put_user(len, optlen)) 76539fb657aeSXin Long goto out; 76549fb657aeSXin Long 76559fb657aeSXin Long if (copy_to_user(optval, ¶ms, len)) 76569fb657aeSXin Long goto out; 76579fb657aeSXin Long 76589fb657aeSXin Long retval = 0; 76599fb657aeSXin Long 76609fb657aeSXin Long out: 76619fb657aeSXin Long return retval; 76629fb657aeSXin Long } 76639fb657aeSXin Long 766413aa8770SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler(struct sock *sk, int len, 766513aa8770SMarcelo Ricardo Leitner char __user *optval, 766613aa8770SMarcelo Ricardo Leitner int __user *optlen) 766713aa8770SMarcelo Ricardo Leitner { 766813aa8770SMarcelo Ricardo Leitner struct sctp_assoc_value params; 766913aa8770SMarcelo Ricardo Leitner struct sctp_association *asoc; 767013aa8770SMarcelo Ricardo Leitner int retval = -EFAULT; 767113aa8770SMarcelo Ricardo Leitner 767213aa8770SMarcelo Ricardo Leitner if (len < sizeof(params)) { 767313aa8770SMarcelo Ricardo Leitner retval = -EINVAL; 767413aa8770SMarcelo Ricardo Leitner goto out; 767513aa8770SMarcelo Ricardo Leitner } 767613aa8770SMarcelo Ricardo Leitner 767713aa8770SMarcelo Ricardo Leitner len = sizeof(params); 767813aa8770SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, len)) 767913aa8770SMarcelo Ricardo Leitner goto out; 768013aa8770SMarcelo Ricardo Leitner 768113aa8770SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 76827efba10dSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 76837efba10dSXin Long sctp_style(sk, UDP)) { 768413aa8770SMarcelo Ricardo Leitner retval = -EINVAL; 768513aa8770SMarcelo Ricardo Leitner goto out; 768613aa8770SMarcelo Ricardo Leitner } 768713aa8770SMarcelo Ricardo Leitner 76887efba10dSXin Long params.assoc_value = asoc ? sctp_sched_get_sched(asoc) 76897efba10dSXin Long : sctp_sk(sk)->default_ss; 769013aa8770SMarcelo Ricardo Leitner 769113aa8770SMarcelo Ricardo Leitner if (put_user(len, optlen)) 769213aa8770SMarcelo Ricardo Leitner goto out; 769313aa8770SMarcelo Ricardo Leitner 769413aa8770SMarcelo Ricardo Leitner if (copy_to_user(optval, ¶ms, len)) 769513aa8770SMarcelo Ricardo Leitner goto out; 769613aa8770SMarcelo Ricardo Leitner 769713aa8770SMarcelo Ricardo Leitner retval = 0; 769813aa8770SMarcelo Ricardo Leitner 769913aa8770SMarcelo Ricardo Leitner out: 770013aa8770SMarcelo Ricardo Leitner return retval; 770113aa8770SMarcelo Ricardo Leitner } 770213aa8770SMarcelo Ricardo Leitner 77030ccdf3c7SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler_value(struct sock *sk, int len, 77040ccdf3c7SMarcelo Ricardo Leitner char __user *optval, 77050ccdf3c7SMarcelo Ricardo Leitner int __user *optlen) 77060ccdf3c7SMarcelo Ricardo Leitner { 77070ccdf3c7SMarcelo Ricardo Leitner struct sctp_stream_value params; 77080ccdf3c7SMarcelo Ricardo Leitner struct sctp_association *asoc; 77090ccdf3c7SMarcelo Ricardo Leitner int retval = -EFAULT; 77100ccdf3c7SMarcelo Ricardo Leitner 77110ccdf3c7SMarcelo Ricardo Leitner if (len < sizeof(params)) { 77120ccdf3c7SMarcelo Ricardo Leitner retval = -EINVAL; 77130ccdf3c7SMarcelo Ricardo Leitner goto out; 77140ccdf3c7SMarcelo Ricardo Leitner } 77150ccdf3c7SMarcelo Ricardo Leitner 77160ccdf3c7SMarcelo Ricardo Leitner len = sizeof(params); 77170ccdf3c7SMarcelo Ricardo Leitner if (copy_from_user(¶ms, optval, len)) 77180ccdf3c7SMarcelo Ricardo Leitner goto out; 77190ccdf3c7SMarcelo Ricardo Leitner 77200ccdf3c7SMarcelo Ricardo Leitner asoc = sctp_id2assoc(sk, params.assoc_id); 77210ccdf3c7SMarcelo Ricardo Leitner if (!asoc) { 77220ccdf3c7SMarcelo Ricardo Leitner retval = -EINVAL; 77230ccdf3c7SMarcelo Ricardo Leitner goto out; 77240ccdf3c7SMarcelo Ricardo Leitner } 77250ccdf3c7SMarcelo Ricardo Leitner 77260ccdf3c7SMarcelo Ricardo Leitner retval = sctp_sched_get_value(asoc, params.stream_id, 77270ccdf3c7SMarcelo Ricardo Leitner ¶ms.stream_value); 77280ccdf3c7SMarcelo Ricardo Leitner if (retval) 77290ccdf3c7SMarcelo Ricardo Leitner goto out; 77300ccdf3c7SMarcelo Ricardo Leitner 77310ccdf3c7SMarcelo Ricardo Leitner if (put_user(len, optlen)) { 77320ccdf3c7SMarcelo Ricardo Leitner retval = -EFAULT; 77330ccdf3c7SMarcelo Ricardo Leitner goto out; 77340ccdf3c7SMarcelo Ricardo Leitner } 77350ccdf3c7SMarcelo Ricardo Leitner 77360ccdf3c7SMarcelo Ricardo Leitner if (copy_to_user(optval, ¶ms, len)) { 77370ccdf3c7SMarcelo Ricardo Leitner retval = -EFAULT; 77380ccdf3c7SMarcelo Ricardo Leitner goto out; 77390ccdf3c7SMarcelo Ricardo Leitner } 77400ccdf3c7SMarcelo Ricardo Leitner 77410ccdf3c7SMarcelo Ricardo Leitner out: 77420ccdf3c7SMarcelo Ricardo Leitner return retval; 77430ccdf3c7SMarcelo Ricardo Leitner } 77440ccdf3c7SMarcelo Ricardo Leitner 7745772a5869SXin Long static int sctp_getsockopt_interleaving_supported(struct sock *sk, int len, 7746772a5869SXin Long char __user *optval, 7747772a5869SXin Long int __user *optlen) 7748772a5869SXin Long { 7749772a5869SXin Long struct sctp_assoc_value params; 7750772a5869SXin Long struct sctp_association *asoc; 7751772a5869SXin Long int retval = -EFAULT; 7752772a5869SXin Long 7753772a5869SXin Long if (len < sizeof(params)) { 7754772a5869SXin Long retval = -EINVAL; 7755772a5869SXin Long goto out; 7756772a5869SXin Long } 7757772a5869SXin Long 7758772a5869SXin Long len = sizeof(params); 7759772a5869SXin Long if (copy_from_user(¶ms, optval, len)) 7760772a5869SXin Long goto out; 7761772a5869SXin Long 7762772a5869SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 77632e7709d1SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 77642e7709d1SXin Long sctp_style(sk, UDP)) { 7765772a5869SXin Long retval = -EINVAL; 7766772a5869SXin Long goto out; 7767772a5869SXin Long } 7768772a5869SXin Long 7769da1f6d4dSXin Long params.assoc_value = asoc ? asoc->peer.intl_capable 7770e55f4b8bSXin Long : sctp_sk(sk)->ep->intl_enable; 77712e7709d1SXin Long 7772772a5869SXin Long if (put_user(len, optlen)) 7773772a5869SXin Long goto out; 7774772a5869SXin Long 7775772a5869SXin Long if (copy_to_user(optval, ¶ms, len)) 7776772a5869SXin Long goto out; 7777772a5869SXin Long 7778772a5869SXin Long retval = 0; 7779772a5869SXin Long 7780772a5869SXin Long out: 7781772a5869SXin Long return retval; 7782772a5869SXin Long } 7783772a5869SXin Long 7784b0e9a2feSXin Long static int sctp_getsockopt_reuse_port(struct sock *sk, int len, 7785b0e9a2feSXin Long char __user *optval, 7786b0e9a2feSXin Long int __user *optlen) 7787b0e9a2feSXin Long { 7788b0e9a2feSXin Long int val; 7789b0e9a2feSXin Long 7790b0e9a2feSXin Long if (len < sizeof(int)) 7791b0e9a2feSXin Long return -EINVAL; 7792b0e9a2feSXin Long 7793b0e9a2feSXin Long len = sizeof(int); 7794b0e9a2feSXin Long val = sctp_sk(sk)->reuse; 7795b0e9a2feSXin Long if (put_user(len, optlen)) 7796b0e9a2feSXin Long return -EFAULT; 7797b0e9a2feSXin Long 7798b0e9a2feSXin Long if (copy_to_user(optval, &val, len)) 7799b0e9a2feSXin Long return -EFAULT; 7800b0e9a2feSXin Long 7801b0e9a2feSXin Long return 0; 7802b0e9a2feSXin Long } 7803b0e9a2feSXin Long 7804480ba9c1SXin Long static int sctp_getsockopt_event(struct sock *sk, int len, char __user *optval, 7805480ba9c1SXin Long int __user *optlen) 7806480ba9c1SXin Long { 7807480ba9c1SXin Long struct sctp_association *asoc; 7808480ba9c1SXin Long struct sctp_event param; 7809480ba9c1SXin Long __u16 subscribe; 7810480ba9c1SXin Long 7811480ba9c1SXin Long if (len < sizeof(param)) 7812480ba9c1SXin Long return -EINVAL; 7813480ba9c1SXin Long 7814480ba9c1SXin Long len = sizeof(param); 7815480ba9c1SXin Long if (copy_from_user(¶m, optval, len)) 7816480ba9c1SXin Long return -EFAULT; 7817480ba9c1SXin Long 7818480ba9c1SXin Long if (param.se_type < SCTP_SN_TYPE_BASE || 7819480ba9c1SXin Long param.se_type > SCTP_SN_TYPE_MAX) 7820480ba9c1SXin Long return -EINVAL; 7821480ba9c1SXin Long 7822480ba9c1SXin Long asoc = sctp_id2assoc(sk, param.se_assoc_id); 7823d251f05eSXin Long if (!asoc && param.se_assoc_id != SCTP_FUTURE_ASSOC && 7824d251f05eSXin Long sctp_style(sk, UDP)) 7825d251f05eSXin Long return -EINVAL; 7826d251f05eSXin Long 7827480ba9c1SXin Long subscribe = asoc ? asoc->subscribe : sctp_sk(sk)->subscribe; 7828480ba9c1SXin Long param.se_on = sctp_ulpevent_type_enabled(subscribe, param.se_type); 7829480ba9c1SXin Long 7830480ba9c1SXin Long if (put_user(len, optlen)) 7831480ba9c1SXin Long return -EFAULT; 7832480ba9c1SXin Long 7833480ba9c1SXin Long if (copy_to_user(optval, ¶m, len)) 7834480ba9c1SXin Long return -EFAULT; 7835480ba9c1SXin Long 7836480ba9c1SXin Long return 0; 7837480ba9c1SXin Long } 7838480ba9c1SXin Long 7839df2c71ffSXin Long static int sctp_getsockopt_asconf_supported(struct sock *sk, int len, 7840df2c71ffSXin Long char __user *optval, 7841df2c71ffSXin Long int __user *optlen) 7842df2c71ffSXin Long { 7843df2c71ffSXin Long struct sctp_assoc_value params; 7844df2c71ffSXin Long struct sctp_association *asoc; 7845df2c71ffSXin Long int retval = -EFAULT; 7846df2c71ffSXin Long 7847df2c71ffSXin Long if (len < sizeof(params)) { 7848df2c71ffSXin Long retval = -EINVAL; 7849df2c71ffSXin Long goto out; 7850df2c71ffSXin Long } 7851df2c71ffSXin Long 7852df2c71ffSXin Long len = sizeof(params); 7853df2c71ffSXin Long if (copy_from_user(¶ms, optval, len)) 7854df2c71ffSXin Long goto out; 7855df2c71ffSXin Long 7856df2c71ffSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7857df2c71ffSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 7858df2c71ffSXin Long sctp_style(sk, UDP)) { 7859df2c71ffSXin Long retval = -EINVAL; 7860df2c71ffSXin Long goto out; 7861df2c71ffSXin Long } 7862df2c71ffSXin Long 7863df2c71ffSXin Long params.assoc_value = asoc ? asoc->peer.asconf_capable 7864df2c71ffSXin Long : sctp_sk(sk)->ep->asconf_enable; 7865df2c71ffSXin Long 7866df2c71ffSXin Long if (put_user(len, optlen)) 7867df2c71ffSXin Long goto out; 7868df2c71ffSXin Long 7869df2c71ffSXin Long if (copy_to_user(optval, ¶ms, len)) 7870df2c71ffSXin Long goto out; 7871df2c71ffSXin Long 7872df2c71ffSXin Long retval = 0; 7873df2c71ffSXin Long 7874df2c71ffSXin Long out: 7875df2c71ffSXin Long return retval; 7876df2c71ffSXin Long } 7877df2c71ffSXin Long 787856dd525aSXin Long static int sctp_getsockopt_auth_supported(struct sock *sk, int len, 787956dd525aSXin Long char __user *optval, 788056dd525aSXin Long int __user *optlen) 788156dd525aSXin Long { 788256dd525aSXin Long struct sctp_assoc_value params; 788356dd525aSXin Long struct sctp_association *asoc; 788456dd525aSXin Long int retval = -EFAULT; 788556dd525aSXin Long 788656dd525aSXin Long if (len < sizeof(params)) { 788756dd525aSXin Long retval = -EINVAL; 788856dd525aSXin Long goto out; 788956dd525aSXin Long } 789056dd525aSXin Long 789156dd525aSXin Long len = sizeof(params); 789256dd525aSXin Long if (copy_from_user(¶ms, optval, len)) 789356dd525aSXin Long goto out; 789456dd525aSXin Long 789556dd525aSXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 789656dd525aSXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 789756dd525aSXin Long sctp_style(sk, UDP)) { 789856dd525aSXin Long retval = -EINVAL; 789956dd525aSXin Long goto out; 790056dd525aSXin Long } 790156dd525aSXin Long 790256dd525aSXin Long params.assoc_value = asoc ? asoc->peer.auth_capable 790356dd525aSXin Long : sctp_sk(sk)->ep->auth_enable; 790456dd525aSXin Long 790556dd525aSXin Long if (put_user(len, optlen)) 790656dd525aSXin Long goto out; 790756dd525aSXin Long 790856dd525aSXin Long if (copy_to_user(optval, ¶ms, len)) 790956dd525aSXin Long goto out; 791056dd525aSXin Long 791156dd525aSXin Long retval = 0; 791256dd525aSXin Long 791356dd525aSXin Long out: 791456dd525aSXin Long return retval; 791556dd525aSXin Long } 791656dd525aSXin Long 7917d5886b91SXin Long static int sctp_getsockopt_ecn_supported(struct sock *sk, int len, 7918d5886b91SXin Long char __user *optval, 7919d5886b91SXin Long int __user *optlen) 7920d5886b91SXin Long { 7921d5886b91SXin Long struct sctp_assoc_value params; 7922d5886b91SXin Long struct sctp_association *asoc; 7923d5886b91SXin Long int retval = -EFAULT; 7924d5886b91SXin Long 7925d5886b91SXin Long if (len < sizeof(params)) { 7926d5886b91SXin Long retval = -EINVAL; 7927d5886b91SXin Long goto out; 7928d5886b91SXin Long } 7929d5886b91SXin Long 7930d5886b91SXin Long len = sizeof(params); 7931d5886b91SXin Long if (copy_from_user(¶ms, optval, len)) 7932d5886b91SXin Long goto out; 7933d5886b91SXin Long 7934d5886b91SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 7935d5886b91SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 7936d5886b91SXin Long sctp_style(sk, UDP)) { 7937d5886b91SXin Long retval = -EINVAL; 7938d5886b91SXin Long goto out; 7939d5886b91SXin Long } 7940d5886b91SXin Long 7941d5886b91SXin Long params.assoc_value = asoc ? asoc->peer.ecn_capable 7942d5886b91SXin Long : sctp_sk(sk)->ep->ecn_enable; 7943d5886b91SXin Long 7944d5886b91SXin Long if (put_user(len, optlen)) 7945d5886b91SXin Long goto out; 7946d5886b91SXin Long 7947d5886b91SXin Long if (copy_to_user(optval, ¶ms, len)) 7948d5886b91SXin Long goto out; 7949d5886b91SXin Long 7950d5886b91SXin Long retval = 0; 7951d5886b91SXin Long 7952d5886b91SXin Long out: 7953d5886b91SXin Long return retval; 7954d5886b91SXin Long } 7955d5886b91SXin Long 79568d2a6935SXin Long static int sctp_getsockopt_pf_expose(struct sock *sk, int len, 79578d2a6935SXin Long char __user *optval, 79588d2a6935SXin Long int __user *optlen) 79598d2a6935SXin Long { 79608d2a6935SXin Long struct sctp_assoc_value params; 79618d2a6935SXin Long struct sctp_association *asoc; 79628d2a6935SXin Long int retval = -EFAULT; 79638d2a6935SXin Long 79648d2a6935SXin Long if (len < sizeof(params)) { 79658d2a6935SXin Long retval = -EINVAL; 79668d2a6935SXin Long goto out; 79678d2a6935SXin Long } 79688d2a6935SXin Long 79698d2a6935SXin Long len = sizeof(params); 79708d2a6935SXin Long if (copy_from_user(¶ms, optval, len)) 79718d2a6935SXin Long goto out; 79728d2a6935SXin Long 79738d2a6935SXin Long asoc = sctp_id2assoc(sk, params.assoc_id); 79748d2a6935SXin Long if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && 79758d2a6935SXin Long sctp_style(sk, UDP)) { 79768d2a6935SXin Long retval = -EINVAL; 79778d2a6935SXin Long goto out; 79788d2a6935SXin Long } 79798d2a6935SXin Long 79808d2a6935SXin Long params.assoc_value = asoc ? asoc->pf_expose 79818d2a6935SXin Long : sctp_sk(sk)->pf_expose; 79828d2a6935SXin Long 79838d2a6935SXin Long if (put_user(len, optlen)) 79848d2a6935SXin Long goto out; 79858d2a6935SXin Long 79868d2a6935SXin Long if (copy_to_user(optval, ¶ms, len)) 79878d2a6935SXin Long goto out; 79888d2a6935SXin Long 79898d2a6935SXin Long retval = 0; 79908d2a6935SXin Long 79918d2a6935SXin Long out: 79928d2a6935SXin Long return retval; 79938d2a6935SXin Long } 79948d2a6935SXin Long 7995dda91928SDaniel Borkmann static int sctp_getsockopt(struct sock *sk, int level, int optname, 79961da177e4SLinus Torvalds char __user *optval, int __user *optlen) 79971da177e4SLinus Torvalds { 79981da177e4SLinus Torvalds int retval = 0; 79991da177e4SLinus Torvalds int len; 80001da177e4SLinus Torvalds 8001bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 80021da177e4SLinus Torvalds 80031da177e4SLinus Torvalds /* I can hardly begin to describe how wrong this is. This is 80041da177e4SLinus Torvalds * so broken as to be worse than useless. The API draft 80051da177e4SLinus Torvalds * REALLY is NOT helpful here... I am not convinced that the 80061da177e4SLinus Torvalds * semantics of getsockopt() with a level OTHER THAN SOL_SCTP 80071da177e4SLinus Torvalds * are at all well-founded. 80081da177e4SLinus Torvalds */ 80091da177e4SLinus Torvalds if (level != SOL_SCTP) { 80101da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 80111da177e4SLinus Torvalds 80121da177e4SLinus Torvalds retval = af->getsockopt(sk, level, optname, optval, optlen); 80131da177e4SLinus Torvalds return retval; 80141da177e4SLinus Torvalds } 80151da177e4SLinus Torvalds 80161da177e4SLinus Torvalds if (get_user(len, optlen)) 80171da177e4SLinus Torvalds return -EFAULT; 80181da177e4SLinus Torvalds 8019a4b8e71bSJiri Slaby if (len < 0) 8020a4b8e71bSJiri Slaby return -EINVAL; 8021a4b8e71bSJiri Slaby 8022048ed4b6Swangweidong lock_sock(sk); 80231da177e4SLinus Torvalds 80241da177e4SLinus Torvalds switch (optname) { 80251da177e4SLinus Torvalds case SCTP_STATUS: 80261da177e4SLinus Torvalds retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); 80271da177e4SLinus Torvalds break; 80281da177e4SLinus Torvalds case SCTP_DISABLE_FRAGMENTS: 80291da177e4SLinus Torvalds retval = sctp_getsockopt_disable_fragments(sk, len, optval, 80301da177e4SLinus Torvalds optlen); 80311da177e4SLinus Torvalds break; 80321da177e4SLinus Torvalds case SCTP_EVENTS: 80331da177e4SLinus Torvalds retval = sctp_getsockopt_events(sk, len, optval, optlen); 80341da177e4SLinus Torvalds break; 80351da177e4SLinus Torvalds case SCTP_AUTOCLOSE: 80361da177e4SLinus Torvalds retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); 80371da177e4SLinus Torvalds break; 80381da177e4SLinus Torvalds case SCTP_SOCKOPT_PEELOFF: 80391da177e4SLinus Torvalds retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); 80401da177e4SLinus Torvalds break; 80412cb5c8e3SNeil Horman case SCTP_SOCKOPT_PEELOFF_FLAGS: 80422cb5c8e3SNeil Horman retval = sctp_getsockopt_peeloff_flags(sk, len, optval, optlen); 80432cb5c8e3SNeil Horman break; 80441da177e4SLinus Torvalds case SCTP_PEER_ADDR_PARAMS: 80451da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addr_params(sk, len, optval, 80461da177e4SLinus Torvalds optlen); 80471da177e4SLinus Torvalds break; 80484580ccc0SShan Wei case SCTP_DELAYED_SACK: 8049d364d927SWei Yongjun retval = sctp_getsockopt_delayed_ack(sk, len, optval, 80507708610bSFrank Filz optlen); 80517708610bSFrank Filz break; 80521da177e4SLinus Torvalds case SCTP_INITMSG: 80531da177e4SLinus Torvalds retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); 80541da177e4SLinus Torvalds break; 80551da177e4SLinus Torvalds case SCTP_GET_PEER_ADDRS: 80561da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addrs(sk, len, optval, 80571da177e4SLinus Torvalds optlen); 80581da177e4SLinus Torvalds break; 80591da177e4SLinus Torvalds case SCTP_GET_LOCAL_ADDRS: 80601da177e4SLinus Torvalds retval = sctp_getsockopt_local_addrs(sk, len, optval, 80611da177e4SLinus Torvalds optlen); 80621da177e4SLinus Torvalds break; 8063c6ba68a2SVlad Yasevich case SCTP_SOCKOPT_CONNECTX3: 8064c6ba68a2SVlad Yasevich retval = sctp_getsockopt_connectx3(sk, len, optval, optlen); 8065c6ba68a2SVlad Yasevich break; 80661da177e4SLinus Torvalds case SCTP_DEFAULT_SEND_PARAM: 80671da177e4SLinus Torvalds retval = sctp_getsockopt_default_send_param(sk, len, 80681da177e4SLinus Torvalds optval, optlen); 80691da177e4SLinus Torvalds break; 80706b3fd5f3SGeir Ola Vaagland case SCTP_DEFAULT_SNDINFO: 80716b3fd5f3SGeir Ola Vaagland retval = sctp_getsockopt_default_sndinfo(sk, len, 80726b3fd5f3SGeir Ola Vaagland optval, optlen); 80736b3fd5f3SGeir Ola Vaagland break; 80741da177e4SLinus Torvalds case SCTP_PRIMARY_ADDR: 80751da177e4SLinus Torvalds retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); 80761da177e4SLinus Torvalds break; 80771da177e4SLinus Torvalds case SCTP_NODELAY: 80781da177e4SLinus Torvalds retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); 80791da177e4SLinus Torvalds break; 80801da177e4SLinus Torvalds case SCTP_RTOINFO: 80811da177e4SLinus Torvalds retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen); 80821da177e4SLinus Torvalds break; 80831da177e4SLinus Torvalds case SCTP_ASSOCINFO: 80841da177e4SLinus Torvalds retval = sctp_getsockopt_associnfo(sk, len, optval, optlen); 80851da177e4SLinus Torvalds break; 80861da177e4SLinus Torvalds case SCTP_I_WANT_MAPPED_V4_ADDR: 80871da177e4SLinus Torvalds retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); 80881da177e4SLinus Torvalds break; 80891da177e4SLinus Torvalds case SCTP_MAXSEG: 80901da177e4SLinus Torvalds retval = sctp_getsockopt_maxseg(sk, len, optval, optlen); 80911da177e4SLinus Torvalds break; 80921da177e4SLinus Torvalds case SCTP_GET_PEER_ADDR_INFO: 80931da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addr_info(sk, len, optval, 80941da177e4SLinus Torvalds optlen); 80951da177e4SLinus Torvalds break; 80960f3fffd8SIvan Skytte Jorgensen case SCTP_ADAPTATION_LAYER: 80970f3fffd8SIvan Skytte Jorgensen retval = sctp_getsockopt_adaptation_layer(sk, len, optval, 80981da177e4SLinus Torvalds optlen); 80991da177e4SLinus Torvalds break; 81006ab792f5SIvan Skytte Jorgensen case SCTP_CONTEXT: 81016ab792f5SIvan Skytte Jorgensen retval = sctp_getsockopt_context(sk, len, optval, optlen); 81026ab792f5SIvan Skytte Jorgensen break; 8103b6e1331fSVlad Yasevich case SCTP_FRAGMENT_INTERLEAVE: 8104b6e1331fSVlad Yasevich retval = sctp_getsockopt_fragment_interleave(sk, len, optval, 8105b6e1331fSVlad Yasevich optlen); 8106b6e1331fSVlad Yasevich break; 8107d49d91d7SVlad Yasevich case SCTP_PARTIAL_DELIVERY_POINT: 8108d49d91d7SVlad Yasevich retval = sctp_getsockopt_partial_delivery_point(sk, len, optval, 8109d49d91d7SVlad Yasevich optlen); 8110d49d91d7SVlad Yasevich break; 811170331571SVlad Yasevich case SCTP_MAX_BURST: 811270331571SVlad Yasevich retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); 811370331571SVlad Yasevich break; 811465b07e5dSVlad Yasevich case SCTP_AUTH_KEY: 811565b07e5dSVlad Yasevich case SCTP_AUTH_CHUNK: 811665b07e5dSVlad Yasevich case SCTP_AUTH_DELETE_KEY: 8117601590ecSXin Long case SCTP_AUTH_DEACTIVATE_KEY: 811865b07e5dSVlad Yasevich retval = -EOPNOTSUPP; 811965b07e5dSVlad Yasevich break; 812065b07e5dSVlad Yasevich case SCTP_HMAC_IDENT: 812165b07e5dSVlad Yasevich retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen); 812265b07e5dSVlad Yasevich break; 812365b07e5dSVlad Yasevich case SCTP_AUTH_ACTIVE_KEY: 812465b07e5dSVlad Yasevich retval = sctp_getsockopt_active_key(sk, len, optval, optlen); 812565b07e5dSVlad Yasevich break; 812665b07e5dSVlad Yasevich case SCTP_PEER_AUTH_CHUNKS: 812765b07e5dSVlad Yasevich retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval, 812865b07e5dSVlad Yasevich optlen); 812965b07e5dSVlad Yasevich break; 813065b07e5dSVlad Yasevich case SCTP_LOCAL_AUTH_CHUNKS: 813165b07e5dSVlad Yasevich retval = sctp_getsockopt_local_auth_chunks(sk, len, optval, 813265b07e5dSVlad Yasevich optlen); 813365b07e5dSVlad Yasevich break; 8134aea3c5c0SWei Yongjun case SCTP_GET_ASSOC_NUMBER: 8135aea3c5c0SWei Yongjun retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); 8136aea3c5c0SWei Yongjun break; 8137209ba424SWei Yongjun case SCTP_GET_ASSOC_ID_LIST: 8138209ba424SWei Yongjun retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); 8139209ba424SWei Yongjun break; 81407dc04d71SMichio Honda case SCTP_AUTO_ASCONF: 81417dc04d71SMichio Honda retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); 81427dc04d71SMichio Honda break; 81435aa93bcfSNeil Horman case SCTP_PEER_ADDR_THLDS: 8144d467ac0aSXin Long retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, 8145d467ac0aSXin Long optlen, false); 8146d467ac0aSXin Long break; 8147d467ac0aSXin Long case SCTP_PEER_ADDR_THLDS_V2: 8148d467ac0aSXin Long retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, 8149d467ac0aSXin Long optlen, true); 81505aa93bcfSNeil Horman break; 8151196d6759SMichele Baldessari case SCTP_GET_ASSOC_STATS: 8152196d6759SMichele Baldessari retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); 8153196d6759SMichele Baldessari break; 81540d3a421dSGeir Ola Vaagland case SCTP_RECVRCVINFO: 81550d3a421dSGeir Ola Vaagland retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); 81560d3a421dSGeir Ola Vaagland break; 81572347c80fSGeir Ola Vaagland case SCTP_RECVNXTINFO: 81582347c80fSGeir Ola Vaagland retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen); 81592347c80fSGeir Ola Vaagland break; 816028aa4c26SXin Long case SCTP_PR_SUPPORTED: 816128aa4c26SXin Long retval = sctp_getsockopt_pr_supported(sk, len, optval, optlen); 816228aa4c26SXin Long break; 8163f959fb44SXin Long case SCTP_DEFAULT_PRINFO: 8164f959fb44SXin Long retval = sctp_getsockopt_default_prinfo(sk, len, optval, 8165f959fb44SXin Long optlen); 8166f959fb44SXin Long break; 8167826d253dSXin Long case SCTP_PR_ASSOC_STATUS: 8168826d253dSXin Long retval = sctp_getsockopt_pr_assocstatus(sk, len, optval, 8169826d253dSXin Long optlen); 8170826d253dSXin Long break; 8171d229d48dSXin Long case SCTP_PR_STREAM_STATUS: 8172d229d48dSXin Long retval = sctp_getsockopt_pr_streamstatus(sk, len, optval, 8173d229d48dSXin Long optlen); 8174d229d48dSXin Long break; 8175c0d8bab6SXin Long case SCTP_RECONFIG_SUPPORTED: 8176c0d8bab6SXin Long retval = sctp_getsockopt_reconfig_supported(sk, len, optval, 8177c0d8bab6SXin Long optlen); 8178c0d8bab6SXin Long break; 81799fb657aeSXin Long case SCTP_ENABLE_STREAM_RESET: 81809fb657aeSXin Long retval = sctp_getsockopt_enable_strreset(sk, len, optval, 81819fb657aeSXin Long optlen); 81829fb657aeSXin Long break; 818313aa8770SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER: 818413aa8770SMarcelo Ricardo Leitner retval = sctp_getsockopt_scheduler(sk, len, optval, 818513aa8770SMarcelo Ricardo Leitner optlen); 818613aa8770SMarcelo Ricardo Leitner break; 81870ccdf3c7SMarcelo Ricardo Leitner case SCTP_STREAM_SCHEDULER_VALUE: 81880ccdf3c7SMarcelo Ricardo Leitner retval = sctp_getsockopt_scheduler_value(sk, len, optval, 81890ccdf3c7SMarcelo Ricardo Leitner optlen); 81900ccdf3c7SMarcelo Ricardo Leitner break; 8191772a5869SXin Long case SCTP_INTERLEAVING_SUPPORTED: 8192772a5869SXin Long retval = sctp_getsockopt_interleaving_supported(sk, len, optval, 8193772a5869SXin Long optlen); 8194772a5869SXin Long break; 8195b0e9a2feSXin Long case SCTP_REUSE_PORT: 8196b0e9a2feSXin Long retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen); 8197b0e9a2feSXin Long break; 8198480ba9c1SXin Long case SCTP_EVENT: 8199480ba9c1SXin Long retval = sctp_getsockopt_event(sk, len, optval, optlen); 8200480ba9c1SXin Long break; 8201df2c71ffSXin Long case SCTP_ASCONF_SUPPORTED: 8202df2c71ffSXin Long retval = sctp_getsockopt_asconf_supported(sk, len, optval, 8203df2c71ffSXin Long optlen); 8204df2c71ffSXin Long break; 820556dd525aSXin Long case SCTP_AUTH_SUPPORTED: 820656dd525aSXin Long retval = sctp_getsockopt_auth_supported(sk, len, optval, 820756dd525aSXin Long optlen); 820856dd525aSXin Long break; 8209d5886b91SXin Long case SCTP_ECN_SUPPORTED: 8210d5886b91SXin Long retval = sctp_getsockopt_ecn_supported(sk, len, optval, optlen); 8211d5886b91SXin Long break; 82128d2a6935SXin Long case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: 82138d2a6935SXin Long retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen); 82148d2a6935SXin Long break; 82151da177e4SLinus Torvalds default: 82161da177e4SLinus Torvalds retval = -ENOPROTOOPT; 82171da177e4SLinus Torvalds break; 82183ff50b79SStephen Hemminger } 82191da177e4SLinus Torvalds 8220048ed4b6Swangweidong release_sock(sk); 82211da177e4SLinus Torvalds return retval; 82221da177e4SLinus Torvalds } 82231da177e4SLinus Torvalds 8224086c653fSCraig Gallek static int sctp_hash(struct sock *sk) 82251da177e4SLinus Torvalds { 82261da177e4SLinus Torvalds /* STUB */ 8227086c653fSCraig Gallek return 0; 82281da177e4SLinus Torvalds } 82291da177e4SLinus Torvalds 82301da177e4SLinus Torvalds static void sctp_unhash(struct sock *sk) 82311da177e4SLinus Torvalds { 82321da177e4SLinus Torvalds /* STUB */ 82331da177e4SLinus Torvalds } 82341da177e4SLinus Torvalds 82351da177e4SLinus Torvalds /* Check if port is acceptable. Possibly find first available port. 82361da177e4SLinus Torvalds * 82371da177e4SLinus Torvalds * The port hash table (contained in the 'global' SCTP protocol storage 82381da177e4SLinus Torvalds * returned by struct sctp_protocol *sctp_get_protocol()). The hash 82391da177e4SLinus Torvalds * table is an array of 4096 lists (sctp_bind_hashbucket). Each 82401da177e4SLinus Torvalds * list (the list number is the port number hashed out, so as you 82411da177e4SLinus Torvalds * would expect from a hash function, all the ports in a given list have 82421da177e4SLinus Torvalds * such a number that hashes out to the same list number; you were 82431da177e4SLinus Torvalds * expecting that, right?); so each list has a set of ports, with a 82441da177e4SLinus Torvalds * link to the socket (struct sock) that uses it, the port number and 82451da177e4SLinus Torvalds * a fastreuse flag (FIXME: NPI ipg). 82461da177e4SLinus Torvalds */ 82471da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create( 8248f1f43763SEric W. Biederman struct sctp_bind_hashbucket *head, struct net *, unsigned short snum); 82491da177e4SLinus Torvalds 82508e2ef6abSMao Wenan static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr) 82511da177e4SLinus Torvalds { 82526ba84574SXin Long struct sctp_sock *sp = sctp_sk(sk); 82536ba84574SXin Long bool reuse = (sk->sk_reuse || sp->reuse); 82541da177e4SLinus Torvalds struct sctp_bind_hashbucket *head; /* hash list */ 8255fb822388SMaciej Żenczykowski struct net *net = sock_net(sk); 82566ba84574SXin Long kuid_t uid = sock_i_uid(sk); 8257b67bfe0dSSasha Levin struct sctp_bind_bucket *pp; 82581da177e4SLinus Torvalds unsigned short snum; 82591da177e4SLinus Torvalds int ret; 82601da177e4SLinus Torvalds 826104afd8b2SAl Viro snum = ntohs(addr->v4.sin_port); 82621da177e4SLinus Torvalds 8263bb33381dSDaniel Borkmann pr_debug("%s: begins, snum:%d\n", __func__, snum); 8264bb33381dSDaniel Borkmann 826579b91130Swangweidong local_bh_disable(); 82661da177e4SLinus Torvalds 82671da177e4SLinus Torvalds if (snum == 0) { 826806393009SStephen Hemminger /* Search for an available port. */ 8269227b60f5SStephen Hemminger int low, high, remaining, index; 8270227b60f5SStephen Hemminger unsigned int rover; 8271227b60f5SStephen Hemminger 8272122ff243SWANG Cong inet_get_local_port_range(net, &low, &high); 8273227b60f5SStephen Hemminger remaining = (high - low) + 1; 827463862b5bSAruna-Hewapathirane rover = prandom_u32() % remaining + low; 82751da177e4SLinus Torvalds 82761da177e4SLinus Torvalds do { 82771da177e4SLinus Torvalds rover++; 82781da177e4SLinus Torvalds if ((rover < low) || (rover > high)) 82791da177e4SLinus Torvalds rover = low; 8280122ff243SWANG Cong if (inet_is_local_reserved_port(net, rover)) 8281e3826f1eSAmerigo Wang continue; 8282fb822388SMaciej Żenczykowski index = sctp_phashfn(net, rover); 82831da177e4SLinus Torvalds head = &sctp_port_hashtable[index]; 82843c8e43baSwangweidong spin_lock(&head->lock); 8285b67bfe0dSSasha Levin sctp_for_each_hentry(pp, &head->chain) 8286f1f43763SEric W. Biederman if ((pp->port == rover) && 8287fb822388SMaciej Żenczykowski net_eq(net, pp->net)) 82881da177e4SLinus Torvalds goto next; 82891da177e4SLinus Torvalds break; 82901da177e4SLinus Torvalds next: 82913c8e43baSwangweidong spin_unlock(&head->lock); 82921da177e4SLinus Torvalds } while (--remaining > 0); 82931da177e4SLinus Torvalds 82941da177e4SLinus Torvalds /* Exhausted local port range during search? */ 82951da177e4SLinus Torvalds ret = 1; 82961da177e4SLinus Torvalds if (remaining <= 0) 82971da177e4SLinus Torvalds goto fail; 82981da177e4SLinus Torvalds 82991da177e4SLinus Torvalds /* OK, here is the one we will use. HEAD (the port 83001da177e4SLinus Torvalds * hash table list entry) is non-NULL and we hold it's 83011da177e4SLinus Torvalds * mutex. 83021da177e4SLinus Torvalds */ 83031da177e4SLinus Torvalds snum = rover; 83041da177e4SLinus Torvalds } else { 83051da177e4SLinus Torvalds /* We are given an specific port number; we verify 83061da177e4SLinus Torvalds * that it is not being used. If it is used, we will 83071da177e4SLinus Torvalds * exahust the search in the hash list corresponding 83081da177e4SLinus Torvalds * to the port number (snum) - we detect that with the 83091da177e4SLinus Torvalds * port iterator, pp being NULL. 83101da177e4SLinus Torvalds */ 8311fb822388SMaciej Żenczykowski head = &sctp_port_hashtable[sctp_phashfn(net, snum)]; 83123c8e43baSwangweidong spin_lock(&head->lock); 8313b67bfe0dSSasha Levin sctp_for_each_hentry(pp, &head->chain) { 8314fb822388SMaciej Żenczykowski if ((pp->port == snum) && net_eq(pp->net, net)) 83151da177e4SLinus Torvalds goto pp_found; 83161da177e4SLinus Torvalds } 83171da177e4SLinus Torvalds } 83181da177e4SLinus Torvalds pp = NULL; 83191da177e4SLinus Torvalds goto pp_not_found; 83201da177e4SLinus Torvalds pp_found: 83211da177e4SLinus Torvalds if (!hlist_empty(&pp->owner)) { 83221da177e4SLinus Torvalds /* We had a port hash table hit - there is an 83231da177e4SLinus Torvalds * available port (pp != NULL) and it is being 83241da177e4SLinus Torvalds * used by other socket (pp->owner not empty); that other 83251da177e4SLinus Torvalds * socket is going to be sk2. 83261da177e4SLinus Torvalds */ 83271da177e4SLinus Torvalds struct sock *sk2; 83281da177e4SLinus Torvalds 8329bb33381dSDaniel Borkmann pr_debug("%s: found a possible match\n", __func__); 8330bb33381dSDaniel Borkmann 83316ba84574SXin Long if ((pp->fastreuse && reuse && 83326ba84574SXin Long sk->sk_state != SCTP_SS_LISTENING) || 83336ba84574SXin Long (pp->fastreuseport && sk->sk_reuseport && 83346ba84574SXin Long uid_eq(pp->fastuid, uid))) 83351da177e4SLinus Torvalds goto success; 83361da177e4SLinus Torvalds 83371da177e4SLinus Torvalds /* Run through the list of sockets bound to the port 83381da177e4SLinus Torvalds * (pp->port) [via the pointers bind_next and 83391da177e4SLinus Torvalds * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one, 83401da177e4SLinus Torvalds * we get the endpoint they describe and run through 83411da177e4SLinus Torvalds * the endpoint's list of IP (v4 or v6) addresses, 83421da177e4SLinus Torvalds * comparing each of the addresses with the address of 83431da177e4SLinus Torvalds * the socket sk. If we find a match, then that means 83441da177e4SLinus Torvalds * that this port/socket (sk) combination are already 83451da177e4SLinus Torvalds * in an endpoint. 83461da177e4SLinus Torvalds */ 8347b67bfe0dSSasha Levin sk_for_each_bound(sk2, &pp->owner) { 83486ba84574SXin Long struct sctp_sock *sp2 = sctp_sk(sk2); 83496ba84574SXin Long struct sctp_endpoint *ep2 = sp2->ep; 83501da177e4SLinus Torvalds 83514e54064eSVlad Yasevich if (sk == sk2 || 83526ba84574SXin Long (reuse && (sk2->sk_reuse || sp2->reuse) && 83536ba84574SXin Long sk2->sk_state != SCTP_SS_LISTENING) || 83546ba84574SXin Long (sk->sk_reuseport && sk2->sk_reuseport && 83556ba84574SXin Long uid_eq(uid, sock_i_uid(sk2)))) 83561da177e4SLinus Torvalds continue; 83571da177e4SLinus Torvalds 83586ba84574SXin Long if (sctp_bind_addr_conflict(&ep2->base.bind_addr, 83596ba84574SXin Long addr, sp2, sp)) { 83608e2ef6abSMao Wenan ret = 1; 83611da177e4SLinus Torvalds goto fail_unlock; 83621da177e4SLinus Torvalds } 83631da177e4SLinus Torvalds } 8364bb33381dSDaniel Borkmann 8365bb33381dSDaniel Borkmann pr_debug("%s: found a match\n", __func__); 83661da177e4SLinus Torvalds } 83671da177e4SLinus Torvalds pp_not_found: 83681da177e4SLinus Torvalds /* If there was a hash table miss, create a new port. */ 83691da177e4SLinus Torvalds ret = 1; 8370fb822388SMaciej Żenczykowski if (!pp && !(pp = sctp_bucket_create(head, net, snum))) 83711da177e4SLinus Torvalds goto fail_unlock; 83721da177e4SLinus Torvalds 83731da177e4SLinus Torvalds /* In either case (hit or miss), make sure fastreuse is 1 only 83741da177e4SLinus Torvalds * if sk->sk_reuse is too (that is, if the caller requested 83751da177e4SLinus Torvalds * SO_REUSEADDR on this socket -sk-). 83761da177e4SLinus Torvalds */ 8377ce5325c1SVlad Yasevich if (hlist_empty(&pp->owner)) { 8378b0e9a2feSXin Long if (reuse && sk->sk_state != SCTP_SS_LISTENING) 8379ce5325c1SVlad Yasevich pp->fastreuse = 1; 8380ce5325c1SVlad Yasevich else 8381ce5325c1SVlad Yasevich pp->fastreuse = 0; 83826ba84574SXin Long 83836ba84574SXin Long if (sk->sk_reuseport) { 83846ba84574SXin Long pp->fastreuseport = 1; 83856ba84574SXin Long pp->fastuid = uid; 83866ba84574SXin Long } else { 83876ba84574SXin Long pp->fastreuseport = 0; 83886ba84574SXin Long } 83896ba84574SXin Long } else { 83906ba84574SXin Long if (pp->fastreuse && 8391b0e9a2feSXin Long (!reuse || sk->sk_state == SCTP_SS_LISTENING)) 83921da177e4SLinus Torvalds pp->fastreuse = 0; 83931da177e4SLinus Torvalds 83946ba84574SXin Long if (pp->fastreuseport && 83956ba84574SXin Long (!sk->sk_reuseport || !uid_eq(pp->fastuid, uid))) 83966ba84574SXin Long pp->fastreuseport = 0; 83976ba84574SXin Long } 83986ba84574SXin Long 83991da177e4SLinus Torvalds /* We are set, so fill up all the data in the hash table 84001da177e4SLinus Torvalds * entry, tie the socket list information with the rest of the 84011da177e4SLinus Torvalds * sockets FIXME: Blurry, NPI (ipg). 84021da177e4SLinus Torvalds */ 84031da177e4SLinus Torvalds success: 84046ba84574SXin Long if (!sp->bind_hash) { 8405c720c7e8SEric Dumazet inet_sk(sk)->inet_num = snum; 84061da177e4SLinus Torvalds sk_add_bind_node(sk, &pp->owner); 84076ba84574SXin Long sp->bind_hash = pp; 84081da177e4SLinus Torvalds } 84091da177e4SLinus Torvalds ret = 0; 84101da177e4SLinus Torvalds 84111da177e4SLinus Torvalds fail_unlock: 84123c8e43baSwangweidong spin_unlock(&head->lock); 84131da177e4SLinus Torvalds 84141da177e4SLinus Torvalds fail: 841579b91130Swangweidong local_bh_enable(); 84161da177e4SLinus Torvalds return ret; 84171da177e4SLinus Torvalds } 84181da177e4SLinus Torvalds 84191da177e4SLinus Torvalds /* Assign a 'snum' port to the socket. If snum == 0, an ephemeral 84201da177e4SLinus Torvalds * port is requested. 84211da177e4SLinus Torvalds */ 84221da177e4SLinus Torvalds static int sctp_get_port(struct sock *sk, unsigned short snum) 84231da177e4SLinus Torvalds { 84241da177e4SLinus Torvalds union sctp_addr addr; 84251da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 84261da177e4SLinus Torvalds 84271da177e4SLinus Torvalds /* Set up a dummy address struct from the sk. */ 84281da177e4SLinus Torvalds af->from_sk(&addr, sk); 84291da177e4SLinus Torvalds addr.v4.sin_port = htons(snum); 84301da177e4SLinus Torvalds 84311da177e4SLinus Torvalds /* Note: sk->sk_num gets filled in if ephemeral port request. */ 84328e2ef6abSMao Wenan return sctp_get_port_local(sk, &addr); 84331da177e4SLinus Torvalds } 84341da177e4SLinus Torvalds 84351da177e4SLinus Torvalds /* 84361da177e4SLinus Torvalds * Move a socket to LISTENING state. 84371da177e4SLinus Torvalds */ 8438dda91928SDaniel Borkmann static int sctp_listen_start(struct sock *sk, int backlog) 84391da177e4SLinus Torvalds { 84405e8f3f70SVlad Yasevich struct sctp_sock *sp = sctp_sk(sk); 84415e8f3f70SVlad Yasevich struct sctp_endpoint *ep = sp->ep; 84425821c769SHerbert Xu struct crypto_shash *tfm = NULL; 84433c68198eSNeil Horman char alg[32]; 84441da177e4SLinus Torvalds 84451da177e4SLinus Torvalds /* Allocate HMAC for generating cookie. */ 84463c68198eSNeil Horman if (!sp->hmac && sp->sctp_hmac_alg) { 84473c68198eSNeil Horman sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg); 84485821c769SHerbert Xu tfm = crypto_alloc_shash(alg, 0, 0); 84498dc4984aSVlad Yasevich if (IS_ERR(tfm)) { 8450e87cc472SJoe Perches net_info_ratelimited("failed to load transform for %s: %ld\n", 84513c68198eSNeil Horman sp->sctp_hmac_alg, PTR_ERR(tfm)); 84525e8f3f70SVlad Yasevich return -ENOSYS; 84535e8f3f70SVlad Yasevich } 84545e8f3f70SVlad Yasevich sctp_sk(sk)->hmac = tfm; 84555e8f3f70SVlad Yasevich } 84565e8f3f70SVlad Yasevich 84575e8f3f70SVlad Yasevich /* 84585e8f3f70SVlad Yasevich * If a bind() or sctp_bindx() is not called prior to a listen() 84595e8f3f70SVlad Yasevich * call that allows new associations to be accepted, the system 84605e8f3f70SVlad Yasevich * picks an ephemeral port and will choose an address set equivalent 84615e8f3f70SVlad Yasevich * to binding with a wildcard address. 84625e8f3f70SVlad Yasevich * 84635e8f3f70SVlad Yasevich * This is not currently spelled out in the SCTP sockets 84645e8f3f70SVlad Yasevich * extensions draft, but follows the practice as seen in TCP 84655e8f3f70SVlad Yasevich * sockets. 84665e8f3f70SVlad Yasevich * 84675e8f3f70SVlad Yasevich */ 8468cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_LISTENING); 84695e8f3f70SVlad Yasevich if (!ep->base.bind_addr.port) { 84705e8f3f70SVlad Yasevich if (sctp_autobind(sk)) 84715e8f3f70SVlad Yasevich return -EAGAIN; 84725e8f3f70SVlad Yasevich } else { 8473c720c7e8SEric Dumazet if (sctp_get_port(sk, inet_sk(sk)->inet_num)) { 8474cbabf463SYafang Shao inet_sk_set_state(sk, SCTP_SS_CLOSED); 84755e8f3f70SVlad Yasevich return -EADDRINUSE; 84765e8f3f70SVlad Yasevich } 84775e8f3f70SVlad Yasevich } 84785e8f3f70SVlad Yasevich 8479099ecf59SEric Dumazet WRITE_ONCE(sk->sk_max_ack_backlog, backlog); 848076c6d988SXin Long return sctp_hash_endpoint(ep); 84815e8f3f70SVlad Yasevich } 84825e8f3f70SVlad Yasevich 84835e8f3f70SVlad Yasevich /* 84845e8f3f70SVlad Yasevich * 4.1.3 / 5.1.3 listen() 84855e8f3f70SVlad Yasevich * 84865e8f3f70SVlad Yasevich * By default, new associations are not accepted for UDP style sockets. 84875e8f3f70SVlad Yasevich * An application uses listen() to mark a socket as being able to 84885e8f3f70SVlad Yasevich * accept new associations. 84895e8f3f70SVlad Yasevich * 84905e8f3f70SVlad Yasevich * On TCP style sockets, applications use listen() to ready the SCTP 84915e8f3f70SVlad Yasevich * endpoint for accepting inbound associations. 84925e8f3f70SVlad Yasevich * 84935e8f3f70SVlad Yasevich * On both types of endpoints a backlog of '0' disables listening. 84945e8f3f70SVlad Yasevich * 84955e8f3f70SVlad Yasevich * Move a socket to LISTENING state. 84965e8f3f70SVlad Yasevich */ 84975e8f3f70SVlad Yasevich int sctp_inet_listen(struct socket *sock, int backlog) 84985e8f3f70SVlad Yasevich { 84995e8f3f70SVlad Yasevich struct sock *sk = sock->sk; 85005e8f3f70SVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 85015e8f3f70SVlad Yasevich int err = -EINVAL; 85025e8f3f70SVlad Yasevich 85035e8f3f70SVlad Yasevich if (unlikely(backlog < 0)) 85045e8f3f70SVlad Yasevich return err; 85055e8f3f70SVlad Yasevich 8506048ed4b6Swangweidong lock_sock(sk); 85075e8f3f70SVlad Yasevich 85085e8f3f70SVlad Yasevich /* Peeled-off sockets are not allowed to listen(). */ 85095e8f3f70SVlad Yasevich if (sctp_style(sk, UDP_HIGH_BANDWIDTH)) 85105e8f3f70SVlad Yasevich goto out; 85115e8f3f70SVlad Yasevich 85125e8f3f70SVlad Yasevich if (sock->state != SS_UNCONNECTED) 85135e8f3f70SVlad Yasevich goto out; 85145e8f3f70SVlad Yasevich 851534b2789fSXin Long if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED)) 851634b2789fSXin Long goto out; 851734b2789fSXin Long 85185e8f3f70SVlad Yasevich /* If backlog is zero, disable listening. */ 85195e8f3f70SVlad Yasevich if (!backlog) { 85205e8f3f70SVlad Yasevich if (sctp_sstate(sk, CLOSED)) 85215e8f3f70SVlad Yasevich goto out; 85225e8f3f70SVlad Yasevich 85235e8f3f70SVlad Yasevich err = 0; 85245e8f3f70SVlad Yasevich sctp_unhash_endpoint(ep); 85255e8f3f70SVlad Yasevich sk->sk_state = SCTP_SS_CLOSED; 8526b0e9a2feSXin Long if (sk->sk_reuse || sctp_sk(sk)->reuse) 85275e8f3f70SVlad Yasevich sctp_sk(sk)->bind_hash->fastreuse = 1; 85281da177e4SLinus Torvalds goto out; 85291da177e4SLinus Torvalds } 85301da177e4SLinus Torvalds 85315e8f3f70SVlad Yasevich /* If we are already listening, just update the backlog */ 85325e8f3f70SVlad Yasevich if (sctp_sstate(sk, LISTENING)) 8533099ecf59SEric Dumazet WRITE_ONCE(sk->sk_max_ack_backlog, backlog); 85345e8f3f70SVlad Yasevich else { 85355e8f3f70SVlad Yasevich err = sctp_listen_start(sk, backlog); 85361da177e4SLinus Torvalds if (err) 85375e8f3f70SVlad Yasevich goto out; 85385e8f3f70SVlad Yasevich } 85391da177e4SLinus Torvalds 85405e8f3f70SVlad Yasevich err = 0; 85411da177e4SLinus Torvalds out: 8542048ed4b6Swangweidong release_sock(sk); 85431da177e4SLinus Torvalds return err; 85441da177e4SLinus Torvalds } 85451da177e4SLinus Torvalds 85461da177e4SLinus Torvalds /* 85471da177e4SLinus Torvalds * This function is done by modeling the current datagram_poll() and the 85481da177e4SLinus Torvalds * tcp_poll(). Note that, based on these implementations, we don't 85491da177e4SLinus Torvalds * lock the socket in this function, even though it seems that, 85501da177e4SLinus Torvalds * ideally, locking or some other mechanisms can be used to ensure 85519bffc4acSNeil Horman * the integrity of the counters (sndbuf and wmem_alloc) used 85521da177e4SLinus Torvalds * in this place. We assume that we don't need locks either until proven 85531da177e4SLinus Torvalds * otherwise. 85541da177e4SLinus Torvalds * 85551da177e4SLinus Torvalds * Another thing to note is that we include the Async I/O support 85561da177e4SLinus Torvalds * here, again, by modeling the current TCP/UDP code. We don't have 85571da177e4SLinus Torvalds * a good way to test with it yet. 85581da177e4SLinus Torvalds */ 8559a11e1d43SLinus Torvalds __poll_t sctp_poll(struct file *file, struct socket *sock, poll_table *wait) 85601da177e4SLinus Torvalds { 85611da177e4SLinus Torvalds struct sock *sk = sock->sk; 85621da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 8563ade994f4SAl Viro __poll_t mask; 85641da177e4SLinus Torvalds 8565a11e1d43SLinus Torvalds poll_wait(file, sk_sleep(sk), wait); 8566a11e1d43SLinus Torvalds 8567486bdee0SMarcelo Ricardo Leitner sock_rps_record_flow(sk); 8568486bdee0SMarcelo Ricardo Leitner 85691da177e4SLinus Torvalds /* A TCP-style listening socket becomes readable when the accept queue 85701da177e4SLinus Torvalds * is not empty. 85711da177e4SLinus Torvalds */ 85721da177e4SLinus Torvalds if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 85731da177e4SLinus Torvalds return (!list_empty(&sp->ep->asocs)) ? 8574a9a08845SLinus Torvalds (EPOLLIN | EPOLLRDNORM) : 0; 85751da177e4SLinus Torvalds 85761da177e4SLinus Torvalds mask = 0; 85771da177e4SLinus Torvalds 85781da177e4SLinus Torvalds /* Is there any exceptional events? */ 85793ef7cf57SEric Dumazet if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue)) 8580a9a08845SLinus Torvalds mask |= EPOLLERR | 8581a9a08845SLinus Torvalds (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0); 8582f348d70aSDavide Libenzi if (sk->sk_shutdown & RCV_SHUTDOWN) 8583a9a08845SLinus Torvalds mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; 85841da177e4SLinus Torvalds if (sk->sk_shutdown == SHUTDOWN_MASK) 8585a9a08845SLinus Torvalds mask |= EPOLLHUP; 85861da177e4SLinus Torvalds 85871da177e4SLinus Torvalds /* Is it readable? Reconsider this code with TCP-style support. */ 85883ef7cf57SEric Dumazet if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 8589a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 85901da177e4SLinus Torvalds 85911da177e4SLinus Torvalds /* The association is either gone or not ready. */ 85921da177e4SLinus Torvalds if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED)) 85931da177e4SLinus Torvalds return mask; 85941da177e4SLinus Torvalds 85951da177e4SLinus Torvalds /* Is it writable? */ 85961da177e4SLinus Torvalds if (sctp_writeable(sk)) { 8597a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 85981da177e4SLinus Torvalds } else { 85999cd3e072SEric Dumazet sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 86001da177e4SLinus Torvalds /* 86011da177e4SLinus Torvalds * Since the socket is not locked, the buffer 86021da177e4SLinus Torvalds * might be made available after the writeable check and 86031da177e4SLinus Torvalds * before the bit is set. This could cause a lost I/O 86041da177e4SLinus Torvalds * signal. tcp_poll() has a race breaker for this race 86051da177e4SLinus Torvalds * condition. Based on their implementation, we put 86061da177e4SLinus Torvalds * in the following code to cover it as well. 86071da177e4SLinus Torvalds */ 86081da177e4SLinus Torvalds if (sctp_writeable(sk)) 8609a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 86101da177e4SLinus Torvalds } 86111da177e4SLinus Torvalds return mask; 86121da177e4SLinus Torvalds } 86131da177e4SLinus Torvalds 86141da177e4SLinus Torvalds /******************************************************************** 86151da177e4SLinus Torvalds * 2nd Level Abstractions 86161da177e4SLinus Torvalds ********************************************************************/ 86171da177e4SLinus Torvalds 86181da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create( 8619f1f43763SEric W. Biederman struct sctp_bind_hashbucket *head, struct net *net, unsigned short snum) 86201da177e4SLinus Torvalds { 86211da177e4SLinus Torvalds struct sctp_bind_bucket *pp; 86221da177e4SLinus Torvalds 862354e6ecb2SChristoph Lameter pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC); 86241da177e4SLinus Torvalds if (pp) { 8625935a7f6eSLi Zefan SCTP_DBG_OBJCNT_INC(bind_bucket); 86261da177e4SLinus Torvalds pp->port = snum; 86271da177e4SLinus Torvalds pp->fastreuse = 0; 86281da177e4SLinus Torvalds INIT_HLIST_HEAD(&pp->owner); 8629f1f43763SEric W. Biederman pp->net = net; 8630d970dbf8SVlad Yasevich hlist_add_head(&pp->node, &head->chain); 86311da177e4SLinus Torvalds } 86321da177e4SLinus Torvalds return pp; 86331da177e4SLinus Torvalds } 86341da177e4SLinus Torvalds 86351da177e4SLinus Torvalds /* Caller must hold hashbucket lock for this tb with local BH disabled */ 86361da177e4SLinus Torvalds static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) 86371da177e4SLinus Torvalds { 863837fa6878SSridhar Samudrala if (pp && hlist_empty(&pp->owner)) { 8639d970dbf8SVlad Yasevich __hlist_del(&pp->node); 86401da177e4SLinus Torvalds kmem_cache_free(sctp_bucket_cachep, pp); 86411da177e4SLinus Torvalds SCTP_DBG_OBJCNT_DEC(bind_bucket); 86421da177e4SLinus Torvalds } 86431da177e4SLinus Torvalds } 86441da177e4SLinus Torvalds 86451da177e4SLinus Torvalds /* Release this socket's reference to a local port. */ 86461da177e4SLinus Torvalds static inline void __sctp_put_port(struct sock *sk) 86471da177e4SLinus Torvalds { 86481da177e4SLinus Torvalds struct sctp_bind_hashbucket *head = 8649f1f43763SEric W. Biederman &sctp_port_hashtable[sctp_phashfn(sock_net(sk), 8650f1f43763SEric W. Biederman inet_sk(sk)->inet_num)]; 86511da177e4SLinus Torvalds struct sctp_bind_bucket *pp; 86521da177e4SLinus Torvalds 86533c8e43baSwangweidong spin_lock(&head->lock); 86541da177e4SLinus Torvalds pp = sctp_sk(sk)->bind_hash; 86551da177e4SLinus Torvalds __sk_del_bind_node(sk); 86561da177e4SLinus Torvalds sctp_sk(sk)->bind_hash = NULL; 8657c720c7e8SEric Dumazet inet_sk(sk)->inet_num = 0; 86581da177e4SLinus Torvalds sctp_bucket_destroy(pp); 86593c8e43baSwangweidong spin_unlock(&head->lock); 86601da177e4SLinus Torvalds } 86611da177e4SLinus Torvalds 86621da177e4SLinus Torvalds void sctp_put_port(struct sock *sk) 86631da177e4SLinus Torvalds { 866479b91130Swangweidong local_bh_disable(); 86651da177e4SLinus Torvalds __sctp_put_port(sk); 866679b91130Swangweidong local_bh_enable(); 86671da177e4SLinus Torvalds } 86681da177e4SLinus Torvalds 86691da177e4SLinus Torvalds /* 86701da177e4SLinus Torvalds * The system picks an ephemeral port and choose an address set equivalent 86711da177e4SLinus Torvalds * to binding with a wildcard address. 86721da177e4SLinus Torvalds * One of those addresses will be the primary address for the association. 86731da177e4SLinus Torvalds * This automatically enables the multihoming capability of SCTP. 86741da177e4SLinus Torvalds */ 86751da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk) 86761da177e4SLinus Torvalds { 86771da177e4SLinus Torvalds union sctp_addr autoaddr; 86781da177e4SLinus Torvalds struct sctp_af *af; 86796fbfa9f9SAl Viro __be16 port; 86801da177e4SLinus Torvalds 86811da177e4SLinus Torvalds /* Initialize a local sockaddr structure to INADDR_ANY. */ 86821da177e4SLinus Torvalds af = sctp_sk(sk)->pf->af; 86831da177e4SLinus Torvalds 8684c720c7e8SEric Dumazet port = htons(inet_sk(sk)->inet_num); 86851da177e4SLinus Torvalds af->inaddr_any(&autoaddr, port); 86861da177e4SLinus Torvalds 86871da177e4SLinus Torvalds return sctp_do_bind(sk, &autoaddr, af->sockaddr_len); 86881da177e4SLinus Torvalds } 86891da177e4SLinus Torvalds 86901da177e4SLinus Torvalds /* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. 86911da177e4SLinus Torvalds * 86921da177e4SLinus Torvalds * From RFC 2292 86931da177e4SLinus Torvalds * 4.2 The cmsghdr Structure * 86941da177e4SLinus Torvalds * 86951da177e4SLinus Torvalds * When ancillary data is sent or received, any number of ancillary data 86961da177e4SLinus Torvalds * objects can be specified by the msg_control and msg_controllen members of 86971da177e4SLinus Torvalds * the msghdr structure, because each object is preceded by 86981da177e4SLinus Torvalds * a cmsghdr structure defining the object's length (the cmsg_len member). 86991da177e4SLinus Torvalds * Historically Berkeley-derived implementations have passed only one object 87001da177e4SLinus Torvalds * at a time, but this API allows multiple objects to be 87011da177e4SLinus Torvalds * passed in a single call to sendmsg() or recvmsg(). The following example 87021da177e4SLinus Torvalds * shows two ancillary data objects in a control buffer. 87031da177e4SLinus Torvalds * 87041da177e4SLinus Torvalds * |<--------------------------- msg_controllen -------------------------->| 87051da177e4SLinus Torvalds * | | 87061da177e4SLinus Torvalds * 87071da177e4SLinus Torvalds * |<----- ancillary data object ----->|<----- ancillary data object ----->| 87081da177e4SLinus Torvalds * 87091da177e4SLinus Torvalds * |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->| 87101da177e4SLinus Torvalds * | | | 87111da177e4SLinus Torvalds * 87121da177e4SLinus Torvalds * |<---------- cmsg_len ---------->| |<--------- cmsg_len ----------->| | 87131da177e4SLinus Torvalds * 87141da177e4SLinus Torvalds * |<--------- CMSG_LEN() --------->| |<-------- CMSG_LEN() ---------->| | 87151da177e4SLinus Torvalds * | | | | | 87161da177e4SLinus Torvalds * 87171da177e4SLinus Torvalds * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 87181da177e4SLinus Torvalds * |cmsg_|cmsg_|cmsg_|XX| |XX|cmsg_|cmsg_|cmsg_|XX| |XX| 87191da177e4SLinus Torvalds * 87201da177e4SLinus Torvalds * |len |level|type |XX|cmsg_data[]|XX|len |level|type |XX|cmsg_data[]|XX| 87211da177e4SLinus Torvalds * 87221da177e4SLinus Torvalds * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 87231da177e4SLinus Torvalds * ^ 87241da177e4SLinus Torvalds * | 87251da177e4SLinus Torvalds * 87261da177e4SLinus Torvalds * msg_control 87271da177e4SLinus Torvalds * points here 87281da177e4SLinus Torvalds */ 8729a05437acSXin Long static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs) 87301da177e4SLinus Torvalds { 8731ab38fb04SVlad Yasevich struct msghdr *my_msg = (struct msghdr *)msg; 8732a05437acSXin Long struct cmsghdr *cmsg; 87331da177e4SLinus Torvalds 8734f95b414eSGu Zheng for_each_cmsghdr(cmsg, my_msg) { 8735ab38fb04SVlad Yasevich if (!CMSG_OK(my_msg, cmsg)) 87361da177e4SLinus Torvalds return -EINVAL; 87371da177e4SLinus Torvalds 87381da177e4SLinus Torvalds /* Should we parse this header or ignore? */ 87391da177e4SLinus Torvalds if (cmsg->cmsg_level != IPPROTO_SCTP) 87401da177e4SLinus Torvalds continue; 87411da177e4SLinus Torvalds 87421da177e4SLinus Torvalds /* Strictly check lengths following example in SCM code. */ 87431da177e4SLinus Torvalds switch (cmsg->cmsg_type) { 87441da177e4SLinus Torvalds case SCTP_INIT: 87451da177e4SLinus Torvalds /* SCTP Socket API Extension 874663b94938SGeir Ola Vaagland * 5.3.1 SCTP Initiation Structure (SCTP_INIT) 87471da177e4SLinus Torvalds * 87481da177e4SLinus Torvalds * This cmsghdr structure provides information for 87491da177e4SLinus Torvalds * initializing new SCTP associations with sendmsg(). 87501da177e4SLinus Torvalds * The SCTP_INITMSG socket option uses this same data 87511da177e4SLinus Torvalds * structure. This structure is not used for 87521da177e4SLinus Torvalds * recvmsg(). 87531da177e4SLinus Torvalds * 87541da177e4SLinus Torvalds * cmsg_level cmsg_type cmsg_data[] 87551da177e4SLinus Torvalds * ------------ ------------ ---------------------- 87561da177e4SLinus Torvalds * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg 87571da177e4SLinus Torvalds */ 875863b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg))) 87591da177e4SLinus Torvalds return -EINVAL; 876063b94938SGeir Ola Vaagland 876163b94938SGeir Ola Vaagland cmsgs->init = CMSG_DATA(cmsg); 87621da177e4SLinus Torvalds break; 87631da177e4SLinus Torvalds 87641da177e4SLinus Torvalds case SCTP_SNDRCV: 87651da177e4SLinus Torvalds /* SCTP Socket API Extension 876663b94938SGeir Ola Vaagland * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV) 87671da177e4SLinus Torvalds * 87681da177e4SLinus Torvalds * This cmsghdr structure specifies SCTP options for 87691da177e4SLinus Torvalds * sendmsg() and describes SCTP header information 87701da177e4SLinus Torvalds * about a received message through recvmsg(). 87711da177e4SLinus Torvalds * 87721da177e4SLinus Torvalds * cmsg_level cmsg_type cmsg_data[] 87731da177e4SLinus Torvalds * ------------ ------------ ---------------------- 87741da177e4SLinus Torvalds * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo 87751da177e4SLinus Torvalds */ 877663b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) 87771da177e4SLinus Torvalds return -EINVAL; 87781da177e4SLinus Torvalds 877963b94938SGeir Ola Vaagland cmsgs->srinfo = CMSG_DATA(cmsg); 87801da177e4SLinus Torvalds 878163b94938SGeir Ola Vaagland if (cmsgs->srinfo->sinfo_flags & 8782eaa5c54dSIvan Skytte Jorgensen ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 878349102805SXin Long SCTP_SACK_IMMEDIATELY | SCTP_SENDALL | 878449102805SXin Long SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF)) 87851da177e4SLinus Torvalds return -EINVAL; 87861da177e4SLinus Torvalds break; 87871da177e4SLinus Torvalds 878863b94938SGeir Ola Vaagland case SCTP_SNDINFO: 878963b94938SGeir Ola Vaagland /* SCTP Socket API Extension 879063b94938SGeir Ola Vaagland * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) 879163b94938SGeir Ola Vaagland * 879263b94938SGeir Ola Vaagland * This cmsghdr structure specifies SCTP options for 879363b94938SGeir Ola Vaagland * sendmsg(). This structure and SCTP_RCVINFO replaces 879463b94938SGeir Ola Vaagland * SCTP_SNDRCV which has been deprecated. 879563b94938SGeir Ola Vaagland * 879663b94938SGeir Ola Vaagland * cmsg_level cmsg_type cmsg_data[] 879763b94938SGeir Ola Vaagland * ------------ ------------ --------------------- 879863b94938SGeir Ola Vaagland * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo 879963b94938SGeir Ola Vaagland */ 880063b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo))) 880163b94938SGeir Ola Vaagland return -EINVAL; 880263b94938SGeir Ola Vaagland 880363b94938SGeir Ola Vaagland cmsgs->sinfo = CMSG_DATA(cmsg); 880463b94938SGeir Ola Vaagland 880563b94938SGeir Ola Vaagland if (cmsgs->sinfo->snd_flags & 880663b94938SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 880749102805SXin Long SCTP_SACK_IMMEDIATELY | SCTP_SENDALL | 880849102805SXin Long SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF)) 880963b94938SGeir Ola Vaagland return -EINVAL; 881063b94938SGeir Ola Vaagland break; 8811ed63afb8SXin Long case SCTP_PRINFO: 8812ed63afb8SXin Long /* SCTP Socket API Extension 8813ed63afb8SXin Long * 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO) 8814ed63afb8SXin Long * 8815ed63afb8SXin Long * This cmsghdr structure specifies SCTP options for sendmsg(). 8816ed63afb8SXin Long * 8817ed63afb8SXin Long * cmsg_level cmsg_type cmsg_data[] 8818ed63afb8SXin Long * ------------ ------------ --------------------- 8819ed63afb8SXin Long * IPPROTO_SCTP SCTP_PRINFO struct sctp_prinfo 8820ed63afb8SXin Long */ 8821ed63afb8SXin Long if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_prinfo))) 8822ed63afb8SXin Long return -EINVAL; 8823ed63afb8SXin Long 8824ed63afb8SXin Long cmsgs->prinfo = CMSG_DATA(cmsg); 8825ed63afb8SXin Long if (cmsgs->prinfo->pr_policy & ~SCTP_PR_SCTP_MASK) 8826ed63afb8SXin Long return -EINVAL; 8827ed63afb8SXin Long 8828ed63afb8SXin Long if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE) 8829ed63afb8SXin Long cmsgs->prinfo->pr_value = 0; 8830ed63afb8SXin Long break; 88313ff547c0SXin Long case SCTP_AUTHINFO: 88323ff547c0SXin Long /* SCTP Socket API Extension 88333ff547c0SXin Long * 5.3.8 SCTP AUTH Information Structure (SCTP_AUTHINFO) 88343ff547c0SXin Long * 88353ff547c0SXin Long * This cmsghdr structure specifies SCTP options for sendmsg(). 88363ff547c0SXin Long * 88373ff547c0SXin Long * cmsg_level cmsg_type cmsg_data[] 88383ff547c0SXin Long * ------------ ------------ --------------------- 88393ff547c0SXin Long * IPPROTO_SCTP SCTP_AUTHINFO struct sctp_authinfo 88403ff547c0SXin Long */ 88413ff547c0SXin Long if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_authinfo))) 88423ff547c0SXin Long return -EINVAL; 88433ff547c0SXin Long 88443ff547c0SXin Long cmsgs->authinfo = CMSG_DATA(cmsg); 88453ff547c0SXin Long break; 88462c0dbaa0SXin Long case SCTP_DSTADDRV4: 88472c0dbaa0SXin Long case SCTP_DSTADDRV6: 88482c0dbaa0SXin Long /* SCTP Socket API Extension 88492c0dbaa0SXin Long * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6) 88502c0dbaa0SXin Long * 88512c0dbaa0SXin Long * This cmsghdr structure specifies SCTP options for sendmsg(). 88522c0dbaa0SXin Long * 88532c0dbaa0SXin Long * cmsg_level cmsg_type cmsg_data[] 88542c0dbaa0SXin Long * ------------ ------------ --------------------- 88552c0dbaa0SXin Long * IPPROTO_SCTP SCTP_DSTADDRV4 struct in_addr 88562c0dbaa0SXin Long * ------------ ------------ --------------------- 88572c0dbaa0SXin Long * IPPROTO_SCTP SCTP_DSTADDRV6 struct in6_addr 88582c0dbaa0SXin Long */ 88592c0dbaa0SXin Long cmsgs->addrs_msg = my_msg; 88602c0dbaa0SXin Long break; 88611da177e4SLinus Torvalds default: 88621da177e4SLinus Torvalds return -EINVAL; 88633ff50b79SStephen Hemminger } 88641da177e4SLinus Torvalds } 886563b94938SGeir Ola Vaagland 88661da177e4SLinus Torvalds return 0; 88671da177e4SLinus Torvalds } 88681da177e4SLinus Torvalds 88691da177e4SLinus Torvalds /* 88701da177e4SLinus Torvalds * Wait for a packet.. 88711da177e4SLinus Torvalds * Note: This function is the same function as in core/datagram.c 88721da177e4SLinus Torvalds * with a few modifications to make lksctp work. 88731da177e4SLinus Torvalds */ 88741da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p) 88751da177e4SLinus Torvalds { 88761da177e4SLinus Torvalds int error; 88771da177e4SLinus Torvalds DEFINE_WAIT(wait); 88781da177e4SLinus Torvalds 8879aa395145SEric Dumazet prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 88801da177e4SLinus Torvalds 88811da177e4SLinus Torvalds /* Socket errors? */ 88821da177e4SLinus Torvalds error = sock_error(sk); 88831da177e4SLinus Torvalds if (error) 88841da177e4SLinus Torvalds goto out; 88851da177e4SLinus Torvalds 88861da177e4SLinus Torvalds if (!skb_queue_empty(&sk->sk_receive_queue)) 88871da177e4SLinus Torvalds goto ready; 88881da177e4SLinus Torvalds 88891da177e4SLinus Torvalds /* Socket shut down? */ 88901da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 88911da177e4SLinus Torvalds goto out; 88921da177e4SLinus Torvalds 88931da177e4SLinus Torvalds /* Sequenced packets can come disconnected. If so we report the 88941da177e4SLinus Torvalds * problem. 88951da177e4SLinus Torvalds */ 88961da177e4SLinus Torvalds error = -ENOTCONN; 88971da177e4SLinus Torvalds 88981da177e4SLinus Torvalds /* Is there a good reason to think that we may receive some data? */ 88991da177e4SLinus Torvalds if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING)) 89001da177e4SLinus Torvalds goto out; 89011da177e4SLinus Torvalds 89021da177e4SLinus Torvalds /* Handle signals. */ 89031da177e4SLinus Torvalds if (signal_pending(current)) 89041da177e4SLinus Torvalds goto interrupted; 89051da177e4SLinus Torvalds 89061da177e4SLinus Torvalds /* Let another process have a go. Since we are going to sleep 89071da177e4SLinus Torvalds * anyway. Note: This may cause odd behaviors if the message 89081da177e4SLinus Torvalds * does not fit in the user's buffer, but this seems to be the 89091da177e4SLinus Torvalds * only way to honor MSG_DONTWAIT realistically. 89101da177e4SLinus Torvalds */ 8911048ed4b6Swangweidong release_sock(sk); 89121da177e4SLinus Torvalds *timeo_p = schedule_timeout(*timeo_p); 8913048ed4b6Swangweidong lock_sock(sk); 89141da177e4SLinus Torvalds 89151da177e4SLinus Torvalds ready: 8916aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 89171da177e4SLinus Torvalds return 0; 89181da177e4SLinus Torvalds 89191da177e4SLinus Torvalds interrupted: 89201da177e4SLinus Torvalds error = sock_intr_errno(*timeo_p); 89211da177e4SLinus Torvalds 89221da177e4SLinus Torvalds out: 8923aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 89241da177e4SLinus Torvalds *err = error; 89251da177e4SLinus Torvalds return error; 89261da177e4SLinus Torvalds } 89271da177e4SLinus Torvalds 89281da177e4SLinus Torvalds /* Receive a datagram. 89291da177e4SLinus Torvalds * Note: This is pretty much the same routine as in core/datagram.c 89301da177e4SLinus Torvalds * with a few changes to make lksctp work. 89311da177e4SLinus Torvalds */ 89322347c80fSGeir Ola Vaagland struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, 89331da177e4SLinus Torvalds int noblock, int *err) 89341da177e4SLinus Torvalds { 89351da177e4SLinus Torvalds int error; 89361da177e4SLinus Torvalds struct sk_buff *skb; 89371da177e4SLinus Torvalds long timeo; 89381da177e4SLinus Torvalds 89391da177e4SLinus Torvalds timeo = sock_rcvtimeo(sk, noblock); 89401da177e4SLinus Torvalds 8941bb33381dSDaniel Borkmann pr_debug("%s: timeo:%ld, max:%ld\n", __func__, timeo, 8942bb33381dSDaniel Borkmann MAX_SCHEDULE_TIMEOUT); 89431da177e4SLinus Torvalds 89441da177e4SLinus Torvalds do { 89451da177e4SLinus Torvalds /* Again only user level code calls this function, 89461da177e4SLinus Torvalds * so nothing interrupt level 89471da177e4SLinus Torvalds * will suddenly eat the receive_queue. 89481da177e4SLinus Torvalds * 89491da177e4SLinus Torvalds * Look at current nfs client by the way... 89508917a3c0SDavid Shwatrz * However, this function was correct in any case. 8) 89511da177e4SLinus Torvalds */ 89521da177e4SLinus Torvalds if (flags & MSG_PEEK) { 89531da177e4SLinus Torvalds skb = skb_peek(&sk->sk_receive_queue); 89541da177e4SLinus Torvalds if (skb) 895563354797SReshetova, Elena refcount_inc(&skb->users); 89561da177e4SLinus Torvalds } else { 8957311b2177SMarcelo Ricardo Leitner skb = __skb_dequeue(&sk->sk_receive_queue); 89581da177e4SLinus Torvalds } 89591da177e4SLinus Torvalds 89601da177e4SLinus Torvalds if (skb) 89611da177e4SLinus Torvalds return skb; 89621da177e4SLinus Torvalds 89636736dc35SNeil Horman /* Caller is allowed not to check sk->sk_err before calling. */ 89646736dc35SNeil Horman error = sock_error(sk); 89656736dc35SNeil Horman if (error) 89666736dc35SNeil Horman goto no_packet; 89676736dc35SNeil Horman 89681da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 89691da177e4SLinus Torvalds break; 89701da177e4SLinus Torvalds 89712b5cd0dfSAlexander Duyck if (sk_can_busy_loop(sk)) { 89722b5cd0dfSAlexander Duyck sk_busy_loop(sk, noblock); 89732b5cd0dfSAlexander Duyck 89743f926af3SEric Dumazet if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 89758465a5fcSNeil Horman continue; 89762b5cd0dfSAlexander Duyck } 89778465a5fcSNeil Horman 89781da177e4SLinus Torvalds /* User doesn't want to wait. */ 89791da177e4SLinus Torvalds error = -EAGAIN; 89801da177e4SLinus Torvalds if (!timeo) 89811da177e4SLinus Torvalds goto no_packet; 89821da177e4SLinus Torvalds } while (sctp_wait_for_packet(sk, err, &timeo) == 0); 89831da177e4SLinus Torvalds 89841da177e4SLinus Torvalds return NULL; 89851da177e4SLinus Torvalds 89861da177e4SLinus Torvalds no_packet: 89871da177e4SLinus Torvalds *err = error; 89881da177e4SLinus Torvalds return NULL; 89891da177e4SLinus Torvalds } 89901da177e4SLinus Torvalds 89911da177e4SLinus Torvalds /* If sndbuf has changed, wake up per association sndbuf waiters. */ 89921da177e4SLinus Torvalds static void __sctp_write_space(struct sctp_association *asoc) 89931da177e4SLinus Torvalds { 89941da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 89951da177e4SLinus Torvalds 8996ceb5d58bSEric Dumazet if (sctp_wspace(asoc) <= 0) 8997ceb5d58bSEric Dumazet return; 8998ceb5d58bSEric Dumazet 89991da177e4SLinus Torvalds if (waitqueue_active(&asoc->wait)) 90001da177e4SLinus Torvalds wake_up_interruptible(&asoc->wait); 90011da177e4SLinus Torvalds 90021da177e4SLinus Torvalds if (sctp_writeable(sk)) { 9003ceb5d58bSEric Dumazet struct socket_wq *wq; 9004eaefd110SEric Dumazet 9005ceb5d58bSEric Dumazet rcu_read_lock(); 9006ceb5d58bSEric Dumazet wq = rcu_dereference(sk->sk_wq); 9007ceb5d58bSEric Dumazet if (wq) { 9008ceb5d58bSEric Dumazet if (waitqueue_active(&wq->wait)) 9009ceb5d58bSEric Dumazet wake_up_interruptible(&wq->wait); 90101da177e4SLinus Torvalds 90111da177e4SLinus Torvalds /* Note that we try to include the Async I/O support 90121da177e4SLinus Torvalds * here by modeling from the current TCP/UDP code. 90131da177e4SLinus Torvalds * We have not tested with it yet. 90141da177e4SLinus Torvalds */ 9015eaefd110SEric Dumazet if (!(sk->sk_shutdown & SEND_SHUTDOWN)) 9016ceb5d58bSEric Dumazet sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT); 90171da177e4SLinus Torvalds } 9018ceb5d58bSEric Dumazet rcu_read_unlock(); 90191da177e4SLinus Torvalds } 90201da177e4SLinus Torvalds } 90211da177e4SLinus Torvalds 902252c35befSDaniel Borkmann static void sctp_wake_up_waiters(struct sock *sk, 902352c35befSDaniel Borkmann struct sctp_association *asoc) 902452c35befSDaniel Borkmann { 902552c35befSDaniel Borkmann struct sctp_association *tmp = asoc; 902652c35befSDaniel Borkmann 902752c35befSDaniel Borkmann /* We do accounting for the sndbuf space per association, 902852c35befSDaniel Borkmann * so we only need to wake our own association. 902952c35befSDaniel Borkmann */ 903052c35befSDaniel Borkmann if (asoc->ep->sndbuf_policy) 903152c35befSDaniel Borkmann return __sctp_write_space(asoc); 903252c35befSDaniel Borkmann 90331e1cdf8aSDaniel Borkmann /* If association goes down and is just flushing its 90341e1cdf8aSDaniel Borkmann * outq, then just normally notify others. 90351e1cdf8aSDaniel Borkmann */ 90361e1cdf8aSDaniel Borkmann if (asoc->base.dead) 90371e1cdf8aSDaniel Borkmann return sctp_write_space(sk); 90381e1cdf8aSDaniel Borkmann 903952c35befSDaniel Borkmann /* Accounting for the sndbuf space is per socket, so we 904052c35befSDaniel Borkmann * need to wake up others, try to be fair and in case of 904152c35befSDaniel Borkmann * other associations, let them have a go first instead 904252c35befSDaniel Borkmann * of just doing a sctp_write_space() call. 904352c35befSDaniel Borkmann * 904452c35befSDaniel Borkmann * Note that we reach sctp_wake_up_waiters() only when 904552c35befSDaniel Borkmann * associations free up queued chunks, thus we are under 904652c35befSDaniel Borkmann * lock and the list of associations on a socket is 904752c35befSDaniel Borkmann * guaranteed not to change. 904852c35befSDaniel Borkmann */ 904952c35befSDaniel Borkmann for (tmp = list_next_entry(tmp, asocs); 1; 905052c35befSDaniel Borkmann tmp = list_next_entry(tmp, asocs)) { 905152c35befSDaniel Borkmann /* Manually skip the head element. */ 905252c35befSDaniel Borkmann if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs)) 905352c35befSDaniel Borkmann continue; 905452c35befSDaniel Borkmann /* Wake up association. */ 905552c35befSDaniel Borkmann __sctp_write_space(tmp); 905652c35befSDaniel Borkmann /* We've reached the end. */ 905752c35befSDaniel Borkmann if (tmp == asoc) 905852c35befSDaniel Borkmann break; 905952c35befSDaniel Borkmann } 906052c35befSDaniel Borkmann } 906152c35befSDaniel Borkmann 90621da177e4SLinus Torvalds /* Do accounting for the sndbuf space. 90631da177e4SLinus Torvalds * Decrement the used sndbuf space of the corresponding association by the 90641da177e4SLinus Torvalds * data size which was just transmitted(freed). 90651da177e4SLinus Torvalds */ 90661da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb) 90671da177e4SLinus Torvalds { 9068f869c912SDaniel Borkmann struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg; 9069f869c912SDaniel Borkmann struct sctp_association *asoc = chunk->asoc; 9070f869c912SDaniel Borkmann struct sock *sk = asoc->base.sk; 90711da177e4SLinus Torvalds 90723ab224beSHideo Aoki sk_mem_uncharge(sk, skb->truesize); 9073605c0ac1SXin Long sk->sk_wmem_queued -= skb->truesize + sizeof(struct sctp_chunk); 9074605c0ac1SXin Long asoc->sndbuf_used -= skb->truesize + sizeof(struct sctp_chunk); 9075605c0ac1SXin Long WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), 9076605c0ac1SXin Long &sk->sk_wmem_alloc)); 90774d93df0aSNeil Horman 9078ec2e506cSXin Long if (chunk->shkey) { 9079ec2e506cSXin Long struct sctp_shared_key *shkey = chunk->shkey; 9080ec2e506cSXin Long 9081ec2e506cSXin Long /* refcnt == 2 and !list_empty mean after this release, it's 9082ec2e506cSXin Long * not being used anywhere, and it's time to notify userland 9083ec2e506cSXin Long * that this shkey can be freed if it's been deactivated. 9084ec2e506cSXin Long */ 9085ec2e506cSXin Long if (shkey->deactivated && !list_empty(&shkey->key_list) && 9086ec2e506cSXin Long refcount_read(&shkey->refcnt) == 2) { 9087ec2e506cSXin Long struct sctp_ulpevent *ev; 9088ec2e506cSXin Long 9089ec2e506cSXin Long ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id, 9090ec2e506cSXin Long SCTP_AUTH_FREE_KEY, 9091ec2e506cSXin Long GFP_KERNEL); 9092ec2e506cSXin Long if (ev) 9093ec2e506cSXin Long asoc->stream.si->enqueue_event(&asoc->ulpq, ev); 9094ec2e506cSXin Long } 90951b1e0bc9SXin Long sctp_auth_shkey_release(chunk->shkey); 9096ec2e506cSXin Long } 90971b1e0bc9SXin Long 90984eb701dfSNeil Horman sock_wfree(skb); 909952c35befSDaniel Borkmann sctp_wake_up_waiters(sk, asoc); 91001da177e4SLinus Torvalds 91011da177e4SLinus Torvalds sctp_association_put(asoc); 91021da177e4SLinus Torvalds } 91031da177e4SLinus Torvalds 9104331c4ee7SVlad Yasevich /* Do accounting for the receive space on the socket. 9105331c4ee7SVlad Yasevich * Accounting for the association is done in ulpevent.c 9106331c4ee7SVlad Yasevich * We set this as a destructor for the cloned data skbs so that 9107331c4ee7SVlad Yasevich * accounting is done at the correct time. 9108331c4ee7SVlad Yasevich */ 9109331c4ee7SVlad Yasevich void sctp_sock_rfree(struct sk_buff *skb) 9110331c4ee7SVlad Yasevich { 9111331c4ee7SVlad Yasevich struct sock *sk = skb->sk; 9112331c4ee7SVlad Yasevich struct sctp_ulpevent *event = sctp_skb2event(skb); 9113331c4ee7SVlad Yasevich 9114331c4ee7SVlad Yasevich atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); 91154d93df0aSNeil Horman 91164d93df0aSNeil Horman /* 91173ab224beSHideo Aoki * Mimic the behavior of sock_rfree 91184d93df0aSNeil Horman */ 91193ab224beSHideo Aoki sk_mem_uncharge(sk, event->rmem_len); 9120331c4ee7SVlad Yasevich } 9121331c4ee7SVlad Yasevich 9122331c4ee7SVlad Yasevich 91231da177e4SLinus Torvalds /* Helper function to wait for space in the sndbuf. */ 91241da177e4SLinus Torvalds static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 9125a0ff6600SXin Long size_t msg_len) 91261da177e4SLinus Torvalds { 91271da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 91281da177e4SLinus Torvalds long current_timeo = *timeo_p; 91291da177e4SLinus Torvalds DEFINE_WAIT(wait); 9130a0ff6600SXin Long int err = 0; 91311da177e4SLinus Torvalds 9132bb33381dSDaniel Borkmann pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc, 9133bb33381dSDaniel Borkmann *timeo_p, msg_len); 91341da177e4SLinus Torvalds 91351da177e4SLinus Torvalds /* Increment the association's refcnt. */ 91361da177e4SLinus Torvalds sctp_association_hold(asoc); 91371da177e4SLinus Torvalds 91381da177e4SLinus Torvalds /* Wait on the association specific sndbuf space. */ 91391da177e4SLinus Torvalds for (;;) { 91401da177e4SLinus Torvalds prepare_to_wait_exclusive(&asoc->wait, &wait, 91411da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 9142ca3af4ddSXin Long if (asoc->base.dead) 9143ca3af4ddSXin Long goto do_dead; 91441da177e4SLinus Torvalds if (!*timeo_p) 91451da177e4SLinus Torvalds goto do_nonblock; 9146ca3af4ddSXin Long if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING) 91471da177e4SLinus Torvalds goto do_error; 91481da177e4SLinus Torvalds if (signal_pending(current)) 91491da177e4SLinus Torvalds goto do_interrupted; 91501033990aSXin Long if (sk_under_memory_pressure(sk)) 91511033990aSXin Long sk_mem_reclaim(sk); 91521033990aSXin Long if ((int)msg_len <= sctp_wspace(asoc) && 91531033990aSXin Long sk_wmem_schedule(sk, msg_len)) 91541da177e4SLinus Torvalds break; 91551da177e4SLinus Torvalds 91561da177e4SLinus Torvalds /* Let another process have a go. Since we are going 91571da177e4SLinus Torvalds * to sleep anyway. 91581da177e4SLinus Torvalds */ 9159048ed4b6Swangweidong release_sock(sk); 91601da177e4SLinus Torvalds current_timeo = schedule_timeout(current_timeo); 9161048ed4b6Swangweidong lock_sock(sk); 9162a0ff6600SXin Long if (sk != asoc->base.sk) 9163a0ff6600SXin Long goto do_error; 91641da177e4SLinus Torvalds 91651da177e4SLinus Torvalds *timeo_p = current_timeo; 91661da177e4SLinus Torvalds } 91671da177e4SLinus Torvalds 91681da177e4SLinus Torvalds out: 91691da177e4SLinus Torvalds finish_wait(&asoc->wait, &wait); 91701da177e4SLinus Torvalds 91711da177e4SLinus Torvalds /* Release the association's refcnt. */ 91721da177e4SLinus Torvalds sctp_association_put(asoc); 91731da177e4SLinus Torvalds 91741da177e4SLinus Torvalds return err; 91751da177e4SLinus Torvalds 9176ca3af4ddSXin Long do_dead: 9177ca3af4ddSXin Long err = -ESRCH; 9178ca3af4ddSXin Long goto out; 9179ca3af4ddSXin Long 91801da177e4SLinus Torvalds do_error: 91811da177e4SLinus Torvalds err = -EPIPE; 91821da177e4SLinus Torvalds goto out; 91831da177e4SLinus Torvalds 91841da177e4SLinus Torvalds do_interrupted: 91851da177e4SLinus Torvalds err = sock_intr_errno(*timeo_p); 91861da177e4SLinus Torvalds goto out; 91871da177e4SLinus Torvalds 91881da177e4SLinus Torvalds do_nonblock: 91891da177e4SLinus Torvalds err = -EAGAIN; 91901da177e4SLinus Torvalds goto out; 91911da177e4SLinus Torvalds } 91921da177e4SLinus Torvalds 9193676d2369SDavid S. Miller void sctp_data_ready(struct sock *sk) 9194561b1733SWei Yongjun { 91957ef52737SDavid S. Miller struct socket_wq *wq; 91967ef52737SDavid S. Miller 91977ef52737SDavid S. Miller rcu_read_lock(); 91987ef52737SDavid S. Miller wq = rcu_dereference(sk->sk_wq); 91991ce0bf50SHerbert Xu if (skwq_has_sleeper(wq)) 9200a9a08845SLinus Torvalds wake_up_interruptible_sync_poll(&wq->wait, EPOLLIN | 9201a9a08845SLinus Torvalds EPOLLRDNORM | EPOLLRDBAND); 9202561b1733SWei Yongjun sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); 92037ef52737SDavid S. Miller rcu_read_unlock(); 9204561b1733SWei Yongjun } 9205561b1733SWei Yongjun 92061da177e4SLinus Torvalds /* If socket sndbuf has changed, wake up all per association waiters. */ 92071da177e4SLinus Torvalds void sctp_write_space(struct sock *sk) 92081da177e4SLinus Torvalds { 92091da177e4SLinus Torvalds struct sctp_association *asoc; 92101da177e4SLinus Torvalds 92111da177e4SLinus Torvalds /* Wake up the tasks in each wait queue. */ 92129dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) { 92131da177e4SLinus Torvalds __sctp_write_space(asoc); 92141da177e4SLinus Torvalds } 92151da177e4SLinus Torvalds } 92161da177e4SLinus Torvalds 92171da177e4SLinus Torvalds /* Is there any sndbuf space available on the socket? 92181da177e4SLinus Torvalds * 92199bffc4acSNeil Horman * Note that sk_wmem_alloc is the sum of the send buffers on all of the 92201da177e4SLinus Torvalds * associations on the same socket. For a UDP-style socket with 92211da177e4SLinus Torvalds * multiple associations, it is possible for it to be "unwriteable" 92221da177e4SLinus Torvalds * prematurely. I assume that this is acceptable because 92231da177e4SLinus Torvalds * a premature "unwriteable" is better than an accidental "writeable" which 92241da177e4SLinus Torvalds * would cause an unwanted block under certain circumstances. For the 1-1 92251da177e4SLinus Torvalds * UDP-style sockets or TCP-style sockets, this code should work. 92261da177e4SLinus Torvalds * - Daisy 92271da177e4SLinus Torvalds */ 9228cd305c74SXin Long static bool sctp_writeable(struct sock *sk) 92291da177e4SLinus Torvalds { 9230cd305c74SXin Long return sk->sk_sndbuf > sk->sk_wmem_queued; 92311da177e4SLinus Torvalds } 92321da177e4SLinus Torvalds 92331da177e4SLinus Torvalds /* Wait for an association to go into ESTABLISHED state. If timeout is 0, 92341da177e4SLinus Torvalds * returns immediately with EINPROGRESS. 92351da177e4SLinus Torvalds */ 92361da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) 92371da177e4SLinus Torvalds { 92381da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 92391da177e4SLinus Torvalds int err = 0; 92401da177e4SLinus Torvalds long current_timeo = *timeo_p; 92411da177e4SLinus Torvalds DEFINE_WAIT(wait); 92421da177e4SLinus Torvalds 9243bb33381dSDaniel Borkmann pr_debug("%s: asoc:%p, timeo:%ld\n", __func__, asoc, *timeo_p); 92441da177e4SLinus Torvalds 92451da177e4SLinus Torvalds /* Increment the association's refcnt. */ 92461da177e4SLinus Torvalds sctp_association_hold(asoc); 92471da177e4SLinus Torvalds 92481da177e4SLinus Torvalds for (;;) { 92491da177e4SLinus Torvalds prepare_to_wait_exclusive(&asoc->wait, &wait, 92501da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 92511da177e4SLinus Torvalds if (!*timeo_p) 92521da177e4SLinus Torvalds goto do_nonblock; 92531da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 92541da177e4SLinus Torvalds break; 92551da177e4SLinus Torvalds if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || 92561da177e4SLinus Torvalds asoc->base.dead) 92571da177e4SLinus Torvalds goto do_error; 92581da177e4SLinus Torvalds if (signal_pending(current)) 92591da177e4SLinus Torvalds goto do_interrupted; 92601da177e4SLinus Torvalds 92611da177e4SLinus Torvalds if (sctp_state(asoc, ESTABLISHED)) 92621da177e4SLinus Torvalds break; 92631da177e4SLinus Torvalds 92641da177e4SLinus Torvalds /* Let another process have a go. Since we are going 92651da177e4SLinus Torvalds * to sleep anyway. 92661da177e4SLinus Torvalds */ 9267048ed4b6Swangweidong release_sock(sk); 92681da177e4SLinus Torvalds current_timeo = schedule_timeout(current_timeo); 9269048ed4b6Swangweidong lock_sock(sk); 92701da177e4SLinus Torvalds 92711da177e4SLinus Torvalds *timeo_p = current_timeo; 92721da177e4SLinus Torvalds } 92731da177e4SLinus Torvalds 92741da177e4SLinus Torvalds out: 92751da177e4SLinus Torvalds finish_wait(&asoc->wait, &wait); 92761da177e4SLinus Torvalds 92771da177e4SLinus Torvalds /* Release the association's refcnt. */ 92781da177e4SLinus Torvalds sctp_association_put(asoc); 92791da177e4SLinus Torvalds 92801da177e4SLinus Torvalds return err; 92811da177e4SLinus Torvalds 92821da177e4SLinus Torvalds do_error: 928381845c21SVlad Yasevich if (asoc->init_err_counter + 1 > asoc->max_init_attempts) 92841da177e4SLinus Torvalds err = -ETIMEDOUT; 92851da177e4SLinus Torvalds else 92861da177e4SLinus Torvalds err = -ECONNREFUSED; 92871da177e4SLinus Torvalds goto out; 92881da177e4SLinus Torvalds 92891da177e4SLinus Torvalds do_interrupted: 92901da177e4SLinus Torvalds err = sock_intr_errno(*timeo_p); 92911da177e4SLinus Torvalds goto out; 92921da177e4SLinus Torvalds 92931da177e4SLinus Torvalds do_nonblock: 92941da177e4SLinus Torvalds err = -EINPROGRESS; 92951da177e4SLinus Torvalds goto out; 92961da177e4SLinus Torvalds } 92971da177e4SLinus Torvalds 92981da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo) 92991da177e4SLinus Torvalds { 93001da177e4SLinus Torvalds struct sctp_endpoint *ep; 93011da177e4SLinus Torvalds int err = 0; 93021da177e4SLinus Torvalds DEFINE_WAIT(wait); 93031da177e4SLinus Torvalds 93041da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 93051da177e4SLinus Torvalds 93061da177e4SLinus Torvalds 93071da177e4SLinus Torvalds for (;;) { 9308aa395145SEric Dumazet prepare_to_wait_exclusive(sk_sleep(sk), &wait, 93091da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 93101da177e4SLinus Torvalds 93111da177e4SLinus Torvalds if (list_empty(&ep->asocs)) { 9312048ed4b6Swangweidong release_sock(sk); 93131da177e4SLinus Torvalds timeo = schedule_timeout(timeo); 9314048ed4b6Swangweidong lock_sock(sk); 93151da177e4SLinus Torvalds } 93161da177e4SLinus Torvalds 93171da177e4SLinus Torvalds err = -EINVAL; 93181da177e4SLinus Torvalds if (!sctp_sstate(sk, LISTENING)) 93191da177e4SLinus Torvalds break; 93201da177e4SLinus Torvalds 93211da177e4SLinus Torvalds err = 0; 93221da177e4SLinus Torvalds if (!list_empty(&ep->asocs)) 93231da177e4SLinus Torvalds break; 93241da177e4SLinus Torvalds 93251da177e4SLinus Torvalds err = sock_intr_errno(timeo); 93261da177e4SLinus Torvalds if (signal_pending(current)) 93271da177e4SLinus Torvalds break; 93281da177e4SLinus Torvalds 93291da177e4SLinus Torvalds err = -EAGAIN; 93301da177e4SLinus Torvalds if (!timeo) 93311da177e4SLinus Torvalds break; 93321da177e4SLinus Torvalds } 93331da177e4SLinus Torvalds 9334aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 93351da177e4SLinus Torvalds 93361da177e4SLinus Torvalds return err; 93371da177e4SLinus Torvalds } 93381da177e4SLinus Torvalds 933904675210Ssebastian@breakpoint.cc static void sctp_wait_for_close(struct sock *sk, long timeout) 93401da177e4SLinus Torvalds { 93411da177e4SLinus Torvalds DEFINE_WAIT(wait); 93421da177e4SLinus Torvalds 93431da177e4SLinus Torvalds do { 9344aa395145SEric Dumazet prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 93451da177e4SLinus Torvalds if (list_empty(&sctp_sk(sk)->ep->asocs)) 93461da177e4SLinus Torvalds break; 9347048ed4b6Swangweidong release_sock(sk); 93481da177e4SLinus Torvalds timeout = schedule_timeout(timeout); 9349048ed4b6Swangweidong lock_sock(sk); 93501da177e4SLinus Torvalds } while (!signal_pending(current) && timeout); 93511da177e4SLinus Torvalds 9352aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 93531da177e4SLinus Torvalds } 93541da177e4SLinus Torvalds 9355ea2bc483STsutomu Fujii static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) 9356ea2bc483STsutomu Fujii { 9357ea2bc483STsutomu Fujii struct sk_buff *frag; 9358ea2bc483STsutomu Fujii 9359ea2bc483STsutomu Fujii if (!skb->data_len) 9360ea2bc483STsutomu Fujii goto done; 9361ea2bc483STsutomu Fujii 9362ea2bc483STsutomu Fujii /* Don't forget the fragments. */ 93631b003be3SDavid S. Miller skb_walk_frags(skb, frag) 9364ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(frag, sk); 9365ea2bc483STsutomu Fujii 9366ea2bc483STsutomu Fujii done: 9367ea2bc483STsutomu Fujii sctp_skb_set_owner_r(skb, sk); 9368ea2bc483STsutomu Fujii } 9369ea2bc483STsutomu Fujii 9370914e1c8bSVlad Yasevich void sctp_copy_sock(struct sock *newsk, struct sock *sk, 9371914e1c8bSVlad Yasevich struct sctp_association *asoc) 9372914e1c8bSVlad Yasevich { 9373914e1c8bSVlad Yasevich struct inet_sock *inet = inet_sk(sk); 937409cb47a2SJulia Lawall struct inet_sock *newinet; 93752277c7cdSRichard Haines struct sctp_sock *sp = sctp_sk(sk); 93762277c7cdSRichard Haines struct sctp_endpoint *ep = sp->ep; 9377914e1c8bSVlad Yasevich 9378914e1c8bSVlad Yasevich newsk->sk_type = sk->sk_type; 9379914e1c8bSVlad Yasevich newsk->sk_bound_dev_if = sk->sk_bound_dev_if; 9380914e1c8bSVlad Yasevich newsk->sk_flags = sk->sk_flags; 938150a5ffb1SMarcelo Ricardo Leitner newsk->sk_tsflags = sk->sk_tsflags; 938228448b80STom Herbert newsk->sk_no_check_tx = sk->sk_no_check_tx; 938328448b80STom Herbert newsk->sk_no_check_rx = sk->sk_no_check_rx; 9384914e1c8bSVlad Yasevich newsk->sk_reuse = sk->sk_reuse; 9385b0e9a2feSXin Long sctp_sk(newsk)->reuse = sp->reuse; 9386914e1c8bSVlad Yasevich 9387914e1c8bSVlad Yasevich newsk->sk_shutdown = sk->sk_shutdown; 93880a2fbac1SDaniel Borkmann newsk->sk_destruct = sctp_destruct_sock; 9389914e1c8bSVlad Yasevich newsk->sk_family = sk->sk_family; 9390914e1c8bSVlad Yasevich newsk->sk_protocol = IPPROTO_SCTP; 9391914e1c8bSVlad Yasevich newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; 9392914e1c8bSVlad Yasevich newsk->sk_sndbuf = sk->sk_sndbuf; 9393914e1c8bSVlad Yasevich newsk->sk_rcvbuf = sk->sk_rcvbuf; 9394914e1c8bSVlad Yasevich newsk->sk_lingertime = sk->sk_lingertime; 9395914e1c8bSVlad Yasevich newsk->sk_rcvtimeo = sk->sk_rcvtimeo; 9396914e1c8bSVlad Yasevich newsk->sk_sndtimeo = sk->sk_sndtimeo; 9397486bdee0SMarcelo Ricardo Leitner newsk->sk_rxhash = sk->sk_rxhash; 9398914e1c8bSVlad Yasevich 9399914e1c8bSVlad Yasevich newinet = inet_sk(newsk); 9400914e1c8bSVlad Yasevich 9401914e1c8bSVlad Yasevich /* Initialize sk's sport, dport, rcv_saddr and daddr for 9402914e1c8bSVlad Yasevich * getsockname() and getpeername() 9403914e1c8bSVlad Yasevich */ 9404c720c7e8SEric Dumazet newinet->inet_sport = inet->inet_sport; 9405c720c7e8SEric Dumazet newinet->inet_saddr = inet->inet_saddr; 9406c720c7e8SEric Dumazet newinet->inet_rcv_saddr = inet->inet_rcv_saddr; 9407c720c7e8SEric Dumazet newinet->inet_dport = htons(asoc->peer.port); 9408914e1c8bSVlad Yasevich newinet->pmtudisc = inet->pmtudisc; 9409a904a069SEric Dumazet newinet->inet_id = prandom_u32(); 9410914e1c8bSVlad Yasevich 9411914e1c8bSVlad Yasevich newinet->uc_ttl = inet->uc_ttl; 9412914e1c8bSVlad Yasevich newinet->mc_loop = 1; 9413914e1c8bSVlad Yasevich newinet->mc_ttl = 1; 9414914e1c8bSVlad Yasevich newinet->mc_index = 0; 9415914e1c8bSVlad Yasevich newinet->mc_list = NULL; 941601ce63c9SMarcelo Ricardo Leitner 941701ce63c9SMarcelo Ricardo Leitner if (newsk->sk_flags & SK_FLAGS_TIMESTAMP) 941801ce63c9SMarcelo Ricardo Leitner net_enable_timestamp(); 94193538a5c8SMarcelo Ricardo Leitner 94202277c7cdSRichard Haines /* Set newsk security attributes from orginal sk and connection 94212277c7cdSRichard Haines * security attribute from ep. 94222277c7cdSRichard Haines */ 94232277c7cdSRichard Haines security_sctp_sk_clone(ep, sk, newsk); 9424914e1c8bSVlad Yasevich } 9425914e1c8bSVlad Yasevich 94262d45a02dSMarcelo Ricardo Leitner static inline void sctp_copy_descendant(struct sock *sk_to, 94272d45a02dSMarcelo Ricardo Leitner const struct sock *sk_from) 94282d45a02dSMarcelo Ricardo Leitner { 94292d45a02dSMarcelo Ricardo Leitner int ancestor_size = sizeof(struct inet_sock) + 94302d45a02dSMarcelo Ricardo Leitner sizeof(struct sctp_sock) - 9431636d25d5SXin Long offsetof(struct sctp_sock, pd_lobby); 94322d45a02dSMarcelo Ricardo Leitner 94332d45a02dSMarcelo Ricardo Leitner if (sk_from->sk_family == PF_INET6) 94342d45a02dSMarcelo Ricardo Leitner ancestor_size += sizeof(struct ipv6_pinfo); 94352d45a02dSMarcelo Ricardo Leitner 94362d45a02dSMarcelo Ricardo Leitner __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); 94372d45a02dSMarcelo Ricardo Leitner } 94382d45a02dSMarcelo Ricardo Leitner 94391da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the assoc 94401da177e4SLinus Torvalds * and its messages to the newsk. 94411da177e4SLinus Torvalds */ 944289664c62SXin Long static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, 94431da177e4SLinus Torvalds struct sctp_association *assoc, 9444b7ef2618SXin Long enum sctp_socket_type type) 94451da177e4SLinus Torvalds { 94461da177e4SLinus Torvalds struct sctp_sock *oldsp = sctp_sk(oldsk); 94471da177e4SLinus Torvalds struct sctp_sock *newsp = sctp_sk(newsk); 94481da177e4SLinus Torvalds struct sctp_bind_bucket *pp; /* hash list port iterator */ 94491da177e4SLinus Torvalds struct sctp_endpoint *newep = newsp->ep; 94501da177e4SLinus Torvalds struct sk_buff *skb, *tmp; 94511da177e4SLinus Torvalds struct sctp_ulpevent *event; 9452f26f7c48SVlad Yasevich struct sctp_bind_hashbucket *head; 945389664c62SXin Long int err; 94541da177e4SLinus Torvalds 94551da177e4SLinus Torvalds /* Migrate socket buffer sizes and all the socket level options to the 94561da177e4SLinus Torvalds * new socket. 94571da177e4SLinus Torvalds */ 94581da177e4SLinus Torvalds newsk->sk_sndbuf = oldsk->sk_sndbuf; 94591da177e4SLinus Torvalds newsk->sk_rcvbuf = oldsk->sk_rcvbuf; 94601da177e4SLinus Torvalds /* Brute force copy old sctp opt. */ 94612d45a02dSMarcelo Ricardo Leitner sctp_copy_descendant(newsk, oldsk); 94621da177e4SLinus Torvalds 94631da177e4SLinus Torvalds /* Restore the ep value that was overwritten with the above structure 94641da177e4SLinus Torvalds * copy. 94651da177e4SLinus Torvalds */ 94661da177e4SLinus Torvalds newsp->ep = newep; 94671da177e4SLinus Torvalds newsp->hmac = NULL; 94681da177e4SLinus Torvalds 94691da177e4SLinus Torvalds /* Hook this new socket in to the bind_hash list. */ 9470f1f43763SEric W. Biederman head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk), 9471f1f43763SEric W. Biederman inet_sk(oldsk)->inet_num)]; 9472489ce5f4SNicholas Mc Guire spin_lock_bh(&head->lock); 94731da177e4SLinus Torvalds pp = sctp_sk(oldsk)->bind_hash; 94741da177e4SLinus Torvalds sk_add_bind_node(newsk, &pp->owner); 94751da177e4SLinus Torvalds sctp_sk(newsk)->bind_hash = pp; 9476c720c7e8SEric Dumazet inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num; 9477489ce5f4SNicholas Mc Guire spin_unlock_bh(&head->lock); 94781da177e4SLinus Torvalds 94794243cac1SVladislav Yasevich /* Copy the bind_addr list from the original endpoint to the new 94804243cac1SVladislav Yasevich * endpoint so that we can handle restarts properly 94814243cac1SVladislav Yasevich */ 948289664c62SXin Long err = sctp_bind_addr_dup(&newsp->ep->base.bind_addr, 94838e71a11cSVlad Yasevich &oldsp->ep->base.bind_addr, GFP_KERNEL); 948489664c62SXin Long if (err) 948589664c62SXin Long return err; 94864243cac1SVladislav Yasevich 9487c6f33e05SXin Long /* New ep's auth_hmacs should be set if old ep's is set, in case 9488c6f33e05SXin Long * that net->sctp.auth_enable has been changed to 0 by users and 9489c6f33e05SXin Long * new ep's auth_hmacs couldn't be set in sctp_endpoint_init(). 9490c6f33e05SXin Long */ 9491c6f33e05SXin Long if (oldsp->ep->auth_hmacs) { 9492c6f33e05SXin Long err = sctp_auth_init_hmacs(newsp->ep, GFP_KERNEL); 9493c6f33e05SXin Long if (err) 9494c6f33e05SXin Long return err; 9495c6f33e05SXin Long } 9496c6f33e05SXin Long 94971da177e4SLinus Torvalds /* Move any messages in the old socket's receive queue that are for the 94981da177e4SLinus Torvalds * peeled off association to the new socket's receive queue. 94991da177e4SLinus Torvalds */ 95001da177e4SLinus Torvalds sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { 95011da177e4SLinus Torvalds event = sctp_skb2event(skb); 95021da177e4SLinus Torvalds if (event->asoc == assoc) { 95038728b834SDavid S. Miller __skb_unlink(skb, &oldsk->sk_receive_queue); 95041da177e4SLinus Torvalds __skb_queue_tail(&newsk->sk_receive_queue, skb); 9505ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 95061da177e4SLinus Torvalds } 95071da177e4SLinus Torvalds } 95081da177e4SLinus Torvalds 95091da177e4SLinus Torvalds /* Clean up any messages pending delivery due to partial 95101da177e4SLinus Torvalds * delivery. Three cases: 95111da177e4SLinus Torvalds * 1) No partial deliver; no work. 95121da177e4SLinus Torvalds * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby. 95131da177e4SLinus Torvalds * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue. 95141da177e4SLinus Torvalds */ 9515b6e1331fSVlad Yasevich atomic_set(&sctp_sk(newsk)->pd_mode, assoc->ulpq.pd_mode); 95161da177e4SLinus Torvalds 9517b6e1331fSVlad Yasevich if (atomic_read(&sctp_sk(oldsk)->pd_mode)) { 95181da177e4SLinus Torvalds struct sk_buff_head *queue; 95191da177e4SLinus Torvalds 95201da177e4SLinus Torvalds /* Decide which queue to move pd_lobby skbs to. */ 95211da177e4SLinus Torvalds if (assoc->ulpq.pd_mode) { 95221da177e4SLinus Torvalds queue = &newsp->pd_lobby; 95231da177e4SLinus Torvalds } else 95241da177e4SLinus Torvalds queue = &newsk->sk_receive_queue; 95251da177e4SLinus Torvalds 95261da177e4SLinus Torvalds /* Walk through the pd_lobby, looking for skbs that 95271da177e4SLinus Torvalds * need moved to the new socket. 95281da177e4SLinus Torvalds */ 95291da177e4SLinus Torvalds sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { 95301da177e4SLinus Torvalds event = sctp_skb2event(skb); 95311da177e4SLinus Torvalds if (event->asoc == assoc) { 95328728b834SDavid S. Miller __skb_unlink(skb, &oldsp->pd_lobby); 95331da177e4SLinus Torvalds __skb_queue_tail(queue, skb); 9534ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 95351da177e4SLinus Torvalds } 95361da177e4SLinus Torvalds } 95371da177e4SLinus Torvalds 95381da177e4SLinus Torvalds /* Clear up any skbs waiting for the partial 95391da177e4SLinus Torvalds * delivery to finish. 95401da177e4SLinus Torvalds */ 95411da177e4SLinus Torvalds if (assoc->ulpq.pd_mode) 9542b6e1331fSVlad Yasevich sctp_clear_pd(oldsk, NULL); 95431da177e4SLinus Torvalds 95441da177e4SLinus Torvalds } 95451da177e4SLinus Torvalds 954613228238SXin Long sctp_for_each_rx_skb(assoc, newsk, sctp_skb_set_owner_r_frag); 9547ea2bc483STsutomu Fujii 95481da177e4SLinus Torvalds /* Set the type of socket to indicate that it is peeled off from the 95491da177e4SLinus Torvalds * original UDP-style socket or created with the accept() call on a 95501da177e4SLinus Torvalds * TCP-style socket.. 95511da177e4SLinus Torvalds */ 95521da177e4SLinus Torvalds newsp->type = type; 95531da177e4SLinus Torvalds 955461c9fed4SVladislav Yasevich /* Mark the new socket "in-use" by the user so that any packets 955561c9fed4SVladislav Yasevich * that may arrive on the association after we've moved it are 955661c9fed4SVladislav Yasevich * queued to the backlog. This prevents a potential race between 955761c9fed4SVladislav Yasevich * backlog processing on the old socket and new-packet processing 955861c9fed4SVladislav Yasevich * on the new socket. 95595131a184SZach Brown * 95605131a184SZach Brown * The caller has just allocated newsk so we can guarantee that other 95615131a184SZach Brown * paths won't try to lock it and then oldsk. 956261c9fed4SVladislav Yasevich */ 95635131a184SZach Brown lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); 95645c3e82feSQiujun Huang sctp_for_each_tx_datachunk(assoc, true, sctp_clear_owner_w); 95651da177e4SLinus Torvalds sctp_assoc_migrate(assoc, newsk); 95665c3e82feSQiujun Huang sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w); 95671da177e4SLinus Torvalds 95681da177e4SLinus Torvalds /* If the association on the newsk is already closed before accept() 95691da177e4SLinus Torvalds * is called, set RCV_SHUTDOWN flag. 95701da177e4SLinus Torvalds */ 9571d46e416cSXin Long if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) { 9572cbabf463SYafang Shao inet_sk_set_state(newsk, SCTP_SS_CLOSED); 95731da177e4SLinus Torvalds newsk->sk_shutdown |= RCV_SHUTDOWN; 9574d46e416cSXin Long } else { 9575cbabf463SYafang Shao inet_sk_set_state(newsk, SCTP_SS_ESTABLISHED); 9576d46e416cSXin Long } 9577d46e416cSXin Long 9578048ed4b6Swangweidong release_sock(newsk); 957989664c62SXin Long 958089664c62SXin Long return 0; 95811da177e4SLinus Torvalds } 95821da177e4SLinus Torvalds 95834d93df0aSNeil Horman 95841da177e4SLinus Torvalds /* This proto struct describes the ULP interface for SCTP. */ 95851da177e4SLinus Torvalds struct proto sctp_prot = { 95861da177e4SLinus Torvalds .name = "SCTP", 95871da177e4SLinus Torvalds .owner = THIS_MODULE, 95881da177e4SLinus Torvalds .close = sctp_close, 95891da177e4SLinus Torvalds .disconnect = sctp_disconnect, 95901da177e4SLinus Torvalds .accept = sctp_accept, 95911da177e4SLinus Torvalds .ioctl = sctp_ioctl, 95921da177e4SLinus Torvalds .init = sctp_init_sock, 95931da177e4SLinus Torvalds .destroy = sctp_destroy_sock, 95941da177e4SLinus Torvalds .shutdown = sctp_shutdown, 95951da177e4SLinus Torvalds .setsockopt = sctp_setsockopt, 95961da177e4SLinus Torvalds .getsockopt = sctp_getsockopt, 95971da177e4SLinus Torvalds .sendmsg = sctp_sendmsg, 95981da177e4SLinus Torvalds .recvmsg = sctp_recvmsg, 95991da177e4SLinus Torvalds .bind = sctp_bind, 9600c0425a42SChristoph Hellwig .bind_add = sctp_bind_add, 96011da177e4SLinus Torvalds .backlog_rcv = sctp_backlog_rcv, 96021da177e4SLinus Torvalds .hash = sctp_hash, 96031da177e4SLinus Torvalds .unhash = sctp_unhash, 960463dfb793SXin Long .no_autobind = true, 96051da177e4SLinus Torvalds .obj_size = sizeof(struct sctp_sock), 9606ab9ee8e3SDavid Windsor .useroffset = offsetof(struct sctp_sock, subscribe), 9607ab9ee8e3SDavid Windsor .usersize = offsetof(struct sctp_sock, initmsg) - 9608ab9ee8e3SDavid Windsor offsetof(struct sctp_sock, subscribe) + 9609ab9ee8e3SDavid Windsor sizeof_field(struct sctp_sock, initmsg), 96104d93df0aSNeil Horman .sysctl_mem = sysctl_sctp_mem, 96114d93df0aSNeil Horman .sysctl_rmem = sysctl_sctp_rmem, 96124d93df0aSNeil Horman .sysctl_wmem = sysctl_sctp_wmem, 96134d93df0aSNeil Horman .memory_pressure = &sctp_memory_pressure, 96144d93df0aSNeil Horman .enter_memory_pressure = sctp_enter_memory_pressure, 96154d93df0aSNeil Horman .memory_allocated = &sctp_memory_allocated, 96165f31886fSPavel Emelyanov .sockets_allocated = &sctp_sockets_allocated, 96171da177e4SLinus Torvalds }; 96181da177e4SLinus Torvalds 9619dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 96208295b6d9SEric Dumazet 9621602dd62dSEric Dumazet #include <net/transp_v6.h> 9622602dd62dSEric Dumazet static void sctp_v6_destroy_sock(struct sock *sk) 9623602dd62dSEric Dumazet { 9624602dd62dSEric Dumazet sctp_destroy_sock(sk); 9625602dd62dSEric Dumazet inet6_destroy_sock(sk); 9626602dd62dSEric Dumazet } 9627602dd62dSEric Dumazet 96281da177e4SLinus Torvalds struct proto sctpv6_prot = { 96291da177e4SLinus Torvalds .name = "SCTPv6", 96301da177e4SLinus Torvalds .owner = THIS_MODULE, 96311da177e4SLinus Torvalds .close = sctp_close, 96321da177e4SLinus Torvalds .disconnect = sctp_disconnect, 96331da177e4SLinus Torvalds .accept = sctp_accept, 96341da177e4SLinus Torvalds .ioctl = sctp_ioctl, 96351da177e4SLinus Torvalds .init = sctp_init_sock, 9636602dd62dSEric Dumazet .destroy = sctp_v6_destroy_sock, 96371da177e4SLinus Torvalds .shutdown = sctp_shutdown, 96381da177e4SLinus Torvalds .setsockopt = sctp_setsockopt, 96391da177e4SLinus Torvalds .getsockopt = sctp_getsockopt, 96401da177e4SLinus Torvalds .sendmsg = sctp_sendmsg, 96411da177e4SLinus Torvalds .recvmsg = sctp_recvmsg, 96421da177e4SLinus Torvalds .bind = sctp_bind, 9643c0425a42SChristoph Hellwig .bind_add = sctp_bind_add, 96441da177e4SLinus Torvalds .backlog_rcv = sctp_backlog_rcv, 96451da177e4SLinus Torvalds .hash = sctp_hash, 96461da177e4SLinus Torvalds .unhash = sctp_unhash, 964763dfb793SXin Long .no_autobind = true, 96481da177e4SLinus Torvalds .obj_size = sizeof(struct sctp6_sock), 9649ab9ee8e3SDavid Windsor .useroffset = offsetof(struct sctp6_sock, sctp.subscribe), 9650ab9ee8e3SDavid Windsor .usersize = offsetof(struct sctp6_sock, sctp.initmsg) - 9651ab9ee8e3SDavid Windsor offsetof(struct sctp6_sock, sctp.subscribe) + 9652ab9ee8e3SDavid Windsor sizeof_field(struct sctp6_sock, sctp.initmsg), 96534d93df0aSNeil Horman .sysctl_mem = sysctl_sctp_mem, 96544d93df0aSNeil Horman .sysctl_rmem = sysctl_sctp_rmem, 96554d93df0aSNeil Horman .sysctl_wmem = sysctl_sctp_wmem, 96564d93df0aSNeil Horman .memory_pressure = &sctp_memory_pressure, 96574d93df0aSNeil Horman .enter_memory_pressure = sctp_enter_memory_pressure, 96584d93df0aSNeil Horman .memory_allocated = &sctp_memory_allocated, 96595f31886fSPavel Emelyanov .sockets_allocated = &sctp_sockets_allocated, 96601da177e4SLinus Torvalds }; 9661dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */ 9662