160c778b2SVlad Yasevich /* SCTP kernel implementation 21da177e4SLinus Torvalds * (C) Copyright IBM Corp. 2001, 2004 31da177e4SLinus Torvalds * Copyright (c) 1999-2000 Cisco, Inc. 41da177e4SLinus Torvalds * Copyright (c) 1999-2001 Motorola, Inc. 51da177e4SLinus Torvalds * Copyright (c) 2001-2003 Intel Corp. 61da177e4SLinus Torvalds * Copyright (c) 2001-2002 Nokia, Inc. 71da177e4SLinus Torvalds * Copyright (c) 2001 La Monte H.P. Yarroll 81da177e4SLinus Torvalds * 960c778b2SVlad Yasevich * This file is part of the SCTP kernel implementation 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * These functions interface with the sockets layer to implement the 121da177e4SLinus Torvalds * SCTP Extensions for the Sockets API. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * Note that the descriptions from the specification are USER level 151da177e4SLinus Torvalds * functions--this file is the functions which populate the struct proto 161da177e4SLinus Torvalds * for SCTP which is the BOTTOM of the sockets interface. 171da177e4SLinus Torvalds * 1860c778b2SVlad Yasevich * This SCTP implementation is free software; 191da177e4SLinus Torvalds * you can redistribute it and/or modify it under the terms of 201da177e4SLinus Torvalds * the GNU General Public License as published by 211da177e4SLinus Torvalds * the Free Software Foundation; either version 2, or (at your option) 221da177e4SLinus Torvalds * any later version. 231da177e4SLinus Torvalds * 2460c778b2SVlad Yasevich * This SCTP implementation is distributed in the hope that it 251da177e4SLinus Torvalds * will be useful, but WITHOUT ANY WARRANTY; without even the implied 261da177e4SLinus Torvalds * ************************ 271da177e4SLinus Torvalds * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 281da177e4SLinus Torvalds * See the GNU General Public License for more details. 291da177e4SLinus Torvalds * 301da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 314b2f13a2SJeff Kirsher * along with GNU CC; see the file COPYING. If not, see 324b2f13a2SJeff Kirsher * <http://www.gnu.org/licenses/>. 331da177e4SLinus Torvalds * 341da177e4SLinus Torvalds * Please send any bug reports or fixes you make to the 351da177e4SLinus Torvalds * email address(es): 3691705c61SDaniel Borkmann * lksctp developers <linux-sctp@vger.kernel.org> 371da177e4SLinus Torvalds * 381da177e4SLinus Torvalds * Written or modified by: 391da177e4SLinus Torvalds * La Monte H.P. Yarroll <piggy@acm.org> 401da177e4SLinus Torvalds * Narasimha Budihal <narsi@refcode.org> 411da177e4SLinus Torvalds * Karl Knutson <karl@athena.chicago.il.us> 421da177e4SLinus Torvalds * Jon Grimm <jgrimm@us.ibm.com> 431da177e4SLinus Torvalds * Xingang Guo <xingang.guo@intel.com> 441da177e4SLinus Torvalds * Daisy Chang <daisyc@us.ibm.com> 451da177e4SLinus Torvalds * Sridhar Samudrala <samudrala@us.ibm.com> 461da177e4SLinus Torvalds * Inaky Perez-Gonzalez <inaky.gonzalez@intel.com> 471da177e4SLinus Torvalds * Ardelle Fan <ardelle.fan@intel.com> 481da177e4SLinus Torvalds * Ryan Layer <rmlayer@us.ibm.com> 491da177e4SLinus Torvalds * Anup Pemmaiah <pemmaiah@cc.usu.edu> 501da177e4SLinus Torvalds * Kevin Gao <kevin.gao@intel.com> 511da177e4SLinus Torvalds */ 521da177e4SLinus Torvalds 53145ce502SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 54145ce502SJoe Perches 551da177e4SLinus Torvalds #include <linux/types.h> 561da177e4SLinus Torvalds #include <linux/kernel.h> 571da177e4SLinus Torvalds #include <linux/wait.h> 581da177e4SLinus Torvalds #include <linux/time.h> 591da177e4SLinus Torvalds #include <linux/ip.h> 604fc268d2SRandy Dunlap #include <linux/capability.h> 611da177e4SLinus Torvalds #include <linux/fcntl.h> 621da177e4SLinus Torvalds #include <linux/poll.h> 631da177e4SLinus Torvalds #include <linux/init.h> 641da177e4SLinus Torvalds #include <linux/crypto.h> 655a0e3ad6STejun Heo #include <linux/slab.h> 6656b31d1cSAl Viro #include <linux/file.h> 67ffd59393SDaniel Borkmann #include <linux/compat.h> 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds #include <net/ip.h> 701da177e4SLinus Torvalds #include <net/icmp.h> 711da177e4SLinus Torvalds #include <net/route.h> 721da177e4SLinus Torvalds #include <net/ipv6.h> 731da177e4SLinus Torvalds #include <net/inet_common.h> 748465a5fcSNeil Horman #include <net/busy_poll.h> 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds #include <linux/socket.h> /* for sa_family_t */ 77bc3b2d7fSPaul Gortmaker #include <linux/export.h> 781da177e4SLinus Torvalds #include <net/sock.h> 791da177e4SLinus Torvalds #include <net/sctp/sctp.h> 801da177e4SLinus Torvalds #include <net/sctp/sm.h> 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* Forward declarations for internal helper functions. */ 831da177e4SLinus Torvalds static int sctp_writeable(struct sock *sk); 841da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb); 851da177e4SLinus Torvalds static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, 861da177e4SLinus Torvalds size_t msg_len); 871da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p); 881da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); 891da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo); 901da177e4SLinus Torvalds static void sctp_wait_for_close(struct sock *sk, long timeo); 910a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk); 921da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, 931da177e4SLinus Torvalds union sctp_addr *addr, int len); 941da177e4SLinus Torvalds static int sctp_bindx_add(struct sock *, struct sockaddr *, int); 951da177e4SLinus Torvalds static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); 961da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); 971da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int); 981da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc, 991da177e4SLinus Torvalds struct sctp_chunk *chunk); 1001da177e4SLinus Torvalds static int sctp_do_bind(struct sock *, union sctp_addr *, int); 1011da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk); 1021da177e4SLinus Torvalds static void sctp_sock_migrate(struct sock *, struct sock *, 1031da177e4SLinus Torvalds struct sctp_association *, sctp_socket_type_t); 1041da177e4SLinus Torvalds 105b6fa1a4dSAdrian Bunk static int sctp_memory_pressure; 1068d987e5cSEric Dumazet static atomic_long_t sctp_memory_allocated; 1071748376bSEric Dumazet struct percpu_counter sctp_sockets_allocated; 1084d93df0aSNeil Horman 1095c52ba17SPavel Emelyanov static void sctp_enter_memory_pressure(struct sock *sk) 1104d93df0aSNeil Horman { 1114d93df0aSNeil Horman sctp_memory_pressure = 1; 1124d93df0aSNeil Horman } 1134d93df0aSNeil Horman 1144d93df0aSNeil Horman 1151da177e4SLinus Torvalds /* Get the sndbuf space available at the time on the association. */ 1161da177e4SLinus Torvalds static inline int sctp_wspace(struct sctp_association *asoc) 1171da177e4SLinus Torvalds { 1184d93df0aSNeil Horman int amt; 1191da177e4SLinus Torvalds 1204d93df0aSNeil Horman if (asoc->ep->sndbuf_policy) 1214d93df0aSNeil Horman amt = asoc->sndbuf_used; 1224d93df0aSNeil Horman else 12331e6d363SEric Dumazet amt = sk_wmem_alloc_get(asoc->base.sk); 1244eb701dfSNeil Horman 1254d93df0aSNeil Horman if (amt >= asoc->base.sk->sk_sndbuf) { 1264d93df0aSNeil Horman if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK) 1274d93df0aSNeil Horman amt = 0; 1284d93df0aSNeil Horman else { 1294d93df0aSNeil Horman amt = sk_stream_wspace(asoc->base.sk); 1301da177e4SLinus Torvalds if (amt < 0) 1311da177e4SLinus Torvalds amt = 0; 1324d93df0aSNeil Horman } 1334d93df0aSNeil Horman } else { 1344d93df0aSNeil Horman amt = asoc->base.sk->sk_sndbuf - amt; 1354d93df0aSNeil Horman } 1361da177e4SLinus Torvalds return amt; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds /* Increment the used sndbuf space count of the corresponding association by 1401da177e4SLinus Torvalds * the size of the outgoing data chunk. 1411da177e4SLinus Torvalds * Also, set the skb destructor for sndbuf accounting later. 1421da177e4SLinus Torvalds * 1431da177e4SLinus Torvalds * Since it is always 1-1 between chunk and skb, and also a new skb is always 1441da177e4SLinus Torvalds * allocated for chunk bundling in sctp_packet_transmit(), we can use the 1451da177e4SLinus Torvalds * destructor in the data chunk skb for the purpose of the sndbuf space 1461da177e4SLinus Torvalds * tracking. 1471da177e4SLinus Torvalds */ 1481da177e4SLinus Torvalds static inline void sctp_set_owner_w(struct sctp_chunk *chunk) 1491da177e4SLinus Torvalds { 1501da177e4SLinus Torvalds struct sctp_association *asoc = chunk->asoc; 1511da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds /* The sndbuf space is tracked per association. */ 1541da177e4SLinus Torvalds sctp_association_hold(asoc); 1551da177e4SLinus Torvalds 1564eb701dfSNeil Horman skb_set_owner_w(chunk->skb, sk); 1574eb701dfSNeil Horman 1581da177e4SLinus Torvalds chunk->skb->destructor = sctp_wfree; 1591da177e4SLinus Torvalds /* Save the chunk pointer in skb for sctp_wfree to use later. */ 160f869c912SDaniel Borkmann skb_shinfo(chunk->skb)->destructor_arg = chunk; 1611da177e4SLinus Torvalds 1624eb701dfSNeil Horman asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) + 1634eb701dfSNeil Horman sizeof(struct sk_buff) + 1644eb701dfSNeil Horman sizeof(struct sctp_chunk); 1654eb701dfSNeil Horman 1664eb701dfSNeil Horman atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); 1673ab224beSHideo Aoki sk->sk_wmem_queued += chunk->skb->truesize; 1683ab224beSHideo Aoki sk_mem_charge(sk, chunk->skb->truesize); 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds /* Verify that this is a valid address. */ 1721da177e4SLinus Torvalds static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, 1731da177e4SLinus Torvalds int len) 1741da177e4SLinus Torvalds { 1751da177e4SLinus Torvalds struct sctp_af *af; 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds /* Verify basic sockaddr. */ 1781da177e4SLinus Torvalds af = sctp_sockaddr_af(sctp_sk(sk), addr, len); 1791da177e4SLinus Torvalds if (!af) 1801da177e4SLinus Torvalds return -EINVAL; 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds /* Is this a valid SCTP address? */ 1835636bef7SVlad Yasevich if (!af->addr_valid(addr, sctp_sk(sk), NULL)) 1841da177e4SLinus Torvalds return -EINVAL; 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) 1871da177e4SLinus Torvalds return -EINVAL; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds return 0; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds /* Look up the association by its id. If this is not a UDP-style 1931da177e4SLinus Torvalds * socket, the ID field is always ignored. 1941da177e4SLinus Torvalds */ 1951da177e4SLinus Torvalds struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds /* If this is not a UDP-style socket, assoc id should be ignored. */ 2001da177e4SLinus Torvalds if (!sctp_style(sk, UDP)) { 2011da177e4SLinus Torvalds /* Return NULL if the socket state is not ESTABLISHED. It 2021da177e4SLinus Torvalds * could be a TCP-style listening socket or a socket which 2031da177e4SLinus Torvalds * hasn't yet called connect() to establish an association. 2041da177e4SLinus Torvalds */ 2051da177e4SLinus Torvalds if (!sctp_sstate(sk, ESTABLISHED)) 2061da177e4SLinus Torvalds return NULL; 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* Get the first and the only association from the list. */ 2091da177e4SLinus Torvalds if (!list_empty(&sctp_sk(sk)->ep->asocs)) 2101da177e4SLinus Torvalds asoc = list_entry(sctp_sk(sk)->ep->asocs.next, 2111da177e4SLinus Torvalds struct sctp_association, asocs); 2121da177e4SLinus Torvalds return asoc; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds /* Otherwise this is a UDP-style socket. */ 2161da177e4SLinus Torvalds if (!id || (id == (sctp_assoc_t)-1)) 2171da177e4SLinus Torvalds return NULL; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds spin_lock_bh(&sctp_assocs_id_lock); 2201da177e4SLinus Torvalds asoc = (struct sctp_association *)idr_find(&sctp_assocs_id, (int)id); 2211da177e4SLinus Torvalds spin_unlock_bh(&sctp_assocs_id_lock); 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds if (!asoc || (asoc->base.sk != sk) || asoc->base.dead) 2241da177e4SLinus Torvalds return NULL; 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds return asoc; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /* Look up the transport from an address and an assoc id. If both address and 2301da177e4SLinus Torvalds * id are specified, the associations matching the address and the id should be 2311da177e4SLinus Torvalds * the same. 2321da177e4SLinus Torvalds */ 2331da177e4SLinus Torvalds static struct sctp_transport *sctp_addr_id2transport(struct sock *sk, 2341da177e4SLinus Torvalds struct sockaddr_storage *addr, 2351da177e4SLinus Torvalds sctp_assoc_t id) 2361da177e4SLinus Torvalds { 2371da177e4SLinus Torvalds struct sctp_association *addr_asoc = NULL, *id_asoc = NULL; 2381da177e4SLinus Torvalds struct sctp_transport *transport; 2391da177e4SLinus Torvalds union sctp_addr *laddr = (union sctp_addr *)addr; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep, 242cd4ff034SAl Viro laddr, 2431da177e4SLinus Torvalds &transport); 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds if (!addr_asoc) 2461da177e4SLinus Torvalds return NULL; 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds id_asoc = sctp_id2assoc(sk, id); 2491da177e4SLinus Torvalds if (id_asoc && (id_asoc != addr_asoc)) 2501da177e4SLinus Torvalds return NULL; 2511da177e4SLinus Torvalds 252299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), 2531da177e4SLinus Torvalds (union sctp_addr *)addr); 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds return transport; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds /* API 3.1.2 bind() - UDP Style Syntax 2591da177e4SLinus Torvalds * The syntax of bind() is, 2601da177e4SLinus Torvalds * 2611da177e4SLinus Torvalds * ret = bind(int sd, struct sockaddr *addr, int addrlen); 2621da177e4SLinus Torvalds * 2631da177e4SLinus Torvalds * sd - the socket descriptor returned by socket(). 2641da177e4SLinus Torvalds * addr - the address structure (struct sockaddr_in or struct 2651da177e4SLinus Torvalds * sockaddr_in6 [RFC 2553]), 2661da177e4SLinus Torvalds * addr_len - the size of the address structure. 2671da177e4SLinus Torvalds */ 268dda91928SDaniel Borkmann static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len) 2691da177e4SLinus Torvalds { 2701da177e4SLinus Torvalds int retval = 0; 2711da177e4SLinus Torvalds 272048ed4b6Swangweidong lock_sock(sk); 2731da177e4SLinus Torvalds 274bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addr:%p, addr_len:%d\n", __func__, sk, 275bb33381dSDaniel Borkmann addr, addr_len); 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds /* Disallow binding twice. */ 2781da177e4SLinus Torvalds if (!sctp_sk(sk)->ep->base.bind_addr.port) 2793f7a87d2SFrank Filz retval = sctp_do_bind(sk, (union sctp_addr *)addr, 2801da177e4SLinus Torvalds addr_len); 2811da177e4SLinus Torvalds else 2821da177e4SLinus Torvalds retval = -EINVAL; 2831da177e4SLinus Torvalds 284048ed4b6Swangweidong release_sock(sk); 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds return retval; 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds static long sctp_get_port_local(struct sock *, union sctp_addr *); 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* Verify this is a valid sockaddr. */ 2921da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, 2931da177e4SLinus Torvalds union sctp_addr *addr, int len) 2941da177e4SLinus Torvalds { 2951da177e4SLinus Torvalds struct sctp_af *af; 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds /* Check minimum size. */ 2981da177e4SLinus Torvalds if (len < sizeof (struct sockaddr)) 2991da177e4SLinus Torvalds return NULL; 3001da177e4SLinus Torvalds 3017dab83deSVlad Yasevich /* V4 mapped address are really of AF_INET family */ 3027dab83deSVlad Yasevich if (addr->sa.sa_family == AF_INET6 && 3037dab83deSVlad Yasevich ipv6_addr_v4mapped(&addr->v6.sin6_addr)) { 3047dab83deSVlad Yasevich if (!opt->pf->af_supported(AF_INET, opt)) 3057dab83deSVlad Yasevich return NULL; 3067dab83deSVlad Yasevich } else { 3071da177e4SLinus Torvalds /* Does this PF support this AF? */ 3081da177e4SLinus Torvalds if (!opt->pf->af_supported(addr->sa.sa_family, opt)) 3091da177e4SLinus Torvalds return NULL; 3107dab83deSVlad Yasevich } 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds /* If we get this far, af is valid. */ 3131da177e4SLinus Torvalds af = sctp_get_af_specific(addr->sa.sa_family); 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds if (len < af->sockaddr_len) 3161da177e4SLinus Torvalds return NULL; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds return af; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds /* Bind a local address either to an endpoint or to an association. */ 322dda91928SDaniel Borkmann static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) 3231da177e4SLinus Torvalds { 3243594698aSEric W. Biederman struct net *net = sock_net(sk); 3251da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 3261da177e4SLinus Torvalds struct sctp_endpoint *ep = sp->ep; 3271da177e4SLinus Torvalds struct sctp_bind_addr *bp = &ep->base.bind_addr; 3281da177e4SLinus Torvalds struct sctp_af *af; 3291da177e4SLinus Torvalds unsigned short snum; 3301da177e4SLinus Torvalds int ret = 0; 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds /* Common sockaddr verification. */ 3331da177e4SLinus Torvalds af = sctp_sockaddr_af(sp, addr, len); 3343f7a87d2SFrank Filz if (!af) { 335bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, newaddr:%p, len:%d EINVAL\n", 336bb33381dSDaniel Borkmann __func__, sk, addr, len); 3371da177e4SLinus Torvalds return -EINVAL; 3383f7a87d2SFrank Filz } 3393f7a87d2SFrank Filz 3403f7a87d2SFrank Filz snum = ntohs(addr->v4.sin_port); 3413f7a87d2SFrank Filz 342bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, new addr:%pISc, port:%d, new port:%d, len:%d\n", 343bb33381dSDaniel Borkmann __func__, sk, &addr->sa, bp->port, snum, len); 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* PF specific bind() address verification. */ 3461da177e4SLinus Torvalds if (!sp->pf->bind_verify(sp, addr)) 3471da177e4SLinus Torvalds return -EADDRNOTAVAIL; 3481da177e4SLinus Torvalds 3498b358056SVlad Yasevich /* We must either be unbound, or bind to the same port. 3508b358056SVlad Yasevich * It's OK to allow 0 ports if we are already bound. 3518b358056SVlad Yasevich * We'll just inhert an already bound port in this case 3528b358056SVlad Yasevich */ 3538b358056SVlad Yasevich if (bp->port) { 3548b358056SVlad Yasevich if (!snum) 3558b358056SVlad Yasevich snum = bp->port; 3568b358056SVlad Yasevich else if (snum != bp->port) { 357bb33381dSDaniel Borkmann pr_debug("%s: new port %d doesn't match existing port " 358bb33381dSDaniel Borkmann "%d\n", __func__, snum, bp->port); 3591da177e4SLinus Torvalds return -EINVAL; 3601da177e4SLinus Torvalds } 3618b358056SVlad Yasevich } 3621da177e4SLinus Torvalds 3633594698aSEric W. Biederman if (snum && snum < PROT_SOCK && 3643594698aSEric W. Biederman !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 3651da177e4SLinus Torvalds return -EACCES; 3661da177e4SLinus Torvalds 3674e54064eSVlad Yasevich /* See if the address matches any of the addresses we may have 3684e54064eSVlad Yasevich * already bound before checking against other endpoints. 3694e54064eSVlad Yasevich */ 3704e54064eSVlad Yasevich if (sctp_bind_addr_match(bp, addr, sp)) 3714e54064eSVlad Yasevich return -EINVAL; 3724e54064eSVlad Yasevich 3731da177e4SLinus Torvalds /* Make sure we are allowed to bind here. 3741da177e4SLinus Torvalds * The function sctp_get_port_local() does duplicate address 3751da177e4SLinus Torvalds * detection. 3761da177e4SLinus Torvalds */ 3772772b495SVlad Yasevich addr->v4.sin_port = htons(snum); 3781da177e4SLinus Torvalds if ((ret = sctp_get_port_local(sk, addr))) { 3791da177e4SLinus Torvalds return -EADDRINUSE; 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds /* Refresh ephemeral port. */ 3831da177e4SLinus Torvalds if (!bp->port) 384c720c7e8SEric Dumazet bp->port = inet_sk(sk)->inet_num; 3851da177e4SLinus Torvalds 386559cf710SVlad Yasevich /* Add the address to the bind address list. 387559cf710SVlad Yasevich * Use GFP_ATOMIC since BHs will be disabled. 388559cf710SVlad Yasevich */ 389f57d96b2SVlad Yasevich ret = sctp_add_bind_addr(bp, addr, SCTP_ADDR_SRC, GFP_ATOMIC); 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds /* Copy back into socket for getsockname() use. */ 3921da177e4SLinus Torvalds if (!ret) { 393c720c7e8SEric Dumazet inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num); 394299ee123SJason Gunthorpe sp->pf->to_sk_saddr(addr, sk); 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds return ret; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks 4011da177e4SLinus Torvalds * 4021da177e4SLinus Torvalds * R1) One and only one ASCONF Chunk MAY be in transit and unacknowledged 4031da177e4SLinus Torvalds * at any one time. If a sender, after sending an ASCONF chunk, decides 4041da177e4SLinus Torvalds * it needs to transfer another ASCONF Chunk, it MUST wait until the 4051da177e4SLinus Torvalds * ASCONF-ACK Chunk returns from the previous ASCONF Chunk before sending a 4061da177e4SLinus Torvalds * subsequent ASCONF. Note this restriction binds each side, so at any 4071da177e4SLinus Torvalds * time two ASCONF may be in-transit on any given association (one sent 4081da177e4SLinus Torvalds * from each endpoint). 4091da177e4SLinus Torvalds */ 4101da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc, 4111da177e4SLinus Torvalds struct sctp_chunk *chunk) 4121da177e4SLinus Torvalds { 41355e26eb9SEric W. Biederman struct net *net = sock_net(asoc->base.sk); 4141da177e4SLinus Torvalds int retval = 0; 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds /* If there is an outstanding ASCONF chunk, queue it for later 4171da177e4SLinus Torvalds * transmission. 4181da177e4SLinus Torvalds */ 4191da177e4SLinus Torvalds if (asoc->addip_last_asconf) { 42079af02c2SDavid S. Miller list_add_tail(&chunk->list, &asoc->addip_chunk_list); 4211da177e4SLinus Torvalds goto out; 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds /* Hold the chunk until an ASCONF_ACK is received. */ 4251da177e4SLinus Torvalds sctp_chunk_hold(chunk); 42655e26eb9SEric W. Biederman retval = sctp_primitive_ASCONF(net, asoc, chunk); 4271da177e4SLinus Torvalds if (retval) 4281da177e4SLinus Torvalds sctp_chunk_free(chunk); 4291da177e4SLinus Torvalds else 4301da177e4SLinus Torvalds asoc->addip_last_asconf = chunk; 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds out: 4331da177e4SLinus Torvalds return retval; 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds /* Add a list of addresses as bind addresses to local endpoint or 4371da177e4SLinus Torvalds * association. 4381da177e4SLinus Torvalds * 4391da177e4SLinus Torvalds * Basically run through each address specified in the addrs/addrcnt 4401da177e4SLinus Torvalds * array/length pair, determine if it is IPv6 or IPv4 and call 4411da177e4SLinus Torvalds * sctp_do_bind() on it. 4421da177e4SLinus Torvalds * 4431da177e4SLinus Torvalds * If any of them fails, then the operation will be reversed and the 4441da177e4SLinus Torvalds * ones that were added will be removed. 4451da177e4SLinus Torvalds * 4461da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 4471da177e4SLinus Torvalds */ 44804675210Ssebastian@breakpoint.cc static int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt) 4491da177e4SLinus Torvalds { 4501da177e4SLinus Torvalds int cnt; 4511da177e4SLinus Torvalds int retval = 0; 4521da177e4SLinus Torvalds void *addr_buf; 4531da177e4SLinus Torvalds struct sockaddr *sa_addr; 4541da177e4SLinus Torvalds struct sctp_af *af; 4551da177e4SLinus Torvalds 456bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", __func__, sk, 457bb33381dSDaniel Borkmann addrs, addrcnt); 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds addr_buf = addrs; 4601da177e4SLinus Torvalds for (cnt = 0; cnt < addrcnt; cnt++) { 4611da177e4SLinus Torvalds /* The list may contain either IPv4 or IPv6 address; 4621da177e4SLinus Torvalds * determine the address length for walking thru the list. 4631da177e4SLinus Torvalds */ 464ea110733SJoe Perches sa_addr = addr_buf; 4651da177e4SLinus Torvalds af = sctp_get_af_specific(sa_addr->sa_family); 4661da177e4SLinus Torvalds if (!af) { 4671da177e4SLinus Torvalds retval = -EINVAL; 4681da177e4SLinus Torvalds goto err_bindx_add; 4691da177e4SLinus Torvalds } 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds retval = sctp_do_bind(sk, (union sctp_addr *)sa_addr, 4721da177e4SLinus Torvalds af->sockaddr_len); 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 4751da177e4SLinus Torvalds 4761da177e4SLinus Torvalds err_bindx_add: 4771da177e4SLinus Torvalds if (retval < 0) { 4781da177e4SLinus Torvalds /* Failed. Cleanup the ones that have been added */ 4791da177e4SLinus Torvalds if (cnt > 0) 4801da177e4SLinus Torvalds sctp_bindx_rem(sk, addrs, cnt); 4811da177e4SLinus Torvalds return retval; 4821da177e4SLinus Torvalds } 4831da177e4SLinus Torvalds } 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds return retval; 4861da177e4SLinus Torvalds } 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds /* Send an ASCONF chunk with Add IP address parameters to all the peers of the 4891da177e4SLinus Torvalds * associations that are part of the endpoint indicating that a list of local 4901da177e4SLinus Torvalds * addresses are added to the endpoint. 4911da177e4SLinus Torvalds * 4921da177e4SLinus Torvalds * If any of the addresses is already in the bind address list of the 4931da177e4SLinus Torvalds * association, we do not send the chunk for that association. But it will not 4941da177e4SLinus Torvalds * affect other associations. 4951da177e4SLinus Torvalds * 4961da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 4971da177e4SLinus Torvalds */ 4981da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock *sk, 4991da177e4SLinus Torvalds struct sockaddr *addrs, 5001da177e4SLinus Torvalds int addrcnt) 5011da177e4SLinus Torvalds { 502e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 5031da177e4SLinus Torvalds struct sctp_sock *sp; 5041da177e4SLinus Torvalds struct sctp_endpoint *ep; 5051da177e4SLinus Torvalds struct sctp_association *asoc; 5061da177e4SLinus Torvalds struct sctp_bind_addr *bp; 5071da177e4SLinus Torvalds struct sctp_chunk *chunk; 5081da177e4SLinus Torvalds struct sctp_sockaddr_entry *laddr; 5091da177e4SLinus Torvalds union sctp_addr *addr; 510dc022a98SSridhar Samudrala union sctp_addr saveaddr; 5111da177e4SLinus Torvalds void *addr_buf; 5121da177e4SLinus Torvalds struct sctp_af *af; 5131da177e4SLinus Torvalds struct list_head *p; 5141da177e4SLinus Torvalds int i; 5151da177e4SLinus Torvalds int retval = 0; 5161da177e4SLinus Torvalds 517e1fc3b14SEric W. Biederman if (!net->sctp.addip_enable) 5181da177e4SLinus Torvalds return retval; 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds sp = sctp_sk(sk); 5211da177e4SLinus Torvalds ep = sp->ep; 5221da177e4SLinus Torvalds 523bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 5240dc47877SHarvey Harrison __func__, sk, addrs, addrcnt); 5251da177e4SLinus Torvalds 5269dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &ep->asocs, asocs) { 5271da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 5281da177e4SLinus Torvalds continue; 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_ADD_IP) 5311da177e4SLinus Torvalds continue; 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 5341da177e4SLinus Torvalds continue; 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds /* Check if any address in the packed array of addresses is 5371da177e4SLinus Torvalds * in the bind address list of the association. If so, 5381da177e4SLinus Torvalds * do not send the asconf chunk to its peer, but continue with 5391da177e4SLinus Torvalds * other associations. 5401da177e4SLinus Torvalds */ 5411da177e4SLinus Torvalds addr_buf = addrs; 5421da177e4SLinus Torvalds for (i = 0; i < addrcnt; i++) { 543ea110733SJoe Perches addr = addr_buf; 5441da177e4SLinus Torvalds af = sctp_get_af_specific(addr->v4.sin_family); 5451da177e4SLinus Torvalds if (!af) { 5461da177e4SLinus Torvalds retval = -EINVAL; 5471da177e4SLinus Torvalds goto out; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds if (sctp_assoc_lookup_laddr(asoc, addr)) 5511da177e4SLinus Torvalds break; 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds if (i < addrcnt) 5561da177e4SLinus Torvalds continue; 5571da177e4SLinus Torvalds 558559cf710SVlad Yasevich /* Use the first valid address in bind addr list of 559559cf710SVlad Yasevich * association as Address Parameter of ASCONF CHUNK. 5601da177e4SLinus Torvalds */ 5611da177e4SLinus Torvalds bp = &asoc->base.bind_addr; 5621da177e4SLinus Torvalds p = bp->address_list.next; 5631da177e4SLinus Torvalds laddr = list_entry(p, struct sctp_sockaddr_entry, list); 5645ae955cfSAl Viro chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs, 5651da177e4SLinus Torvalds addrcnt, SCTP_PARAM_ADD_IP); 5661da177e4SLinus Torvalds if (!chunk) { 5671da177e4SLinus Torvalds retval = -ENOMEM; 5681da177e4SLinus Torvalds goto out; 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 571dc022a98SSridhar Samudrala /* Add the new addresses to the bind address list with 572dc022a98SSridhar Samudrala * use_as_src set to 0. 5731da177e4SLinus Torvalds */ 574dc022a98SSridhar Samudrala addr_buf = addrs; 575dc022a98SSridhar Samudrala for (i = 0; i < addrcnt; i++) { 576ea110733SJoe Perches addr = addr_buf; 577dc022a98SSridhar Samudrala af = sctp_get_af_specific(addr->v4.sin_family); 578dc022a98SSridhar Samudrala memcpy(&saveaddr, addr, af->sockaddr_len); 579f57d96b2SVlad Yasevich retval = sctp_add_bind_addr(bp, &saveaddr, 580f57d96b2SVlad Yasevich SCTP_ADDR_NEW, GFP_ATOMIC); 581dc022a98SSridhar Samudrala addr_buf += af->sockaddr_len; 582dc022a98SSridhar Samudrala } 5838a07eb0aSMichio Honda if (asoc->src_out_of_asoc_ok) { 5848a07eb0aSMichio Honda struct sctp_transport *trans; 5858a07eb0aSMichio Honda 5868a07eb0aSMichio Honda list_for_each_entry(trans, 5878a07eb0aSMichio Honda &asoc->peer.transport_addr_list, transports) { 5888a07eb0aSMichio Honda /* Clear the source and route cache */ 5898a07eb0aSMichio Honda dst_release(trans->dst); 5908a07eb0aSMichio Honda trans->cwnd = min(4*asoc->pathmtu, max_t(__u32, 5918a07eb0aSMichio Honda 2*asoc->pathmtu, 4380)); 5928a07eb0aSMichio Honda trans->ssthresh = asoc->peer.i.a_rwnd; 5938a07eb0aSMichio Honda trans->rto = asoc->rto_initial; 594196d6759SMichele Baldessari sctp_max_rto(asoc, trans); 5958a07eb0aSMichio Honda trans->rtt = trans->srtt = trans->rttvar = 0; 5968a07eb0aSMichio Honda sctp_transport_route(trans, NULL, 5978a07eb0aSMichio Honda sctp_sk(asoc->base.sk)); 5988a07eb0aSMichio Honda } 5998a07eb0aSMichio Honda } 6008a07eb0aSMichio Honda retval = sctp_send_asconf(asoc, chunk); 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds out: 6041da177e4SLinus Torvalds return retval; 6051da177e4SLinus Torvalds } 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds /* Remove a list of addresses from bind addresses list. Do not remove the 6081da177e4SLinus Torvalds * last address. 6091da177e4SLinus Torvalds * 6101da177e4SLinus Torvalds * Basically run through each address specified in the addrs/addrcnt 6111da177e4SLinus Torvalds * array/length pair, determine if it is IPv6 or IPv4 and call 6121da177e4SLinus Torvalds * sctp_del_bind() on it. 6131da177e4SLinus Torvalds * 6141da177e4SLinus Torvalds * If any of them fails, then the operation will be reversed and the 6151da177e4SLinus Torvalds * ones that were removed will be added back. 6161da177e4SLinus Torvalds * 6171da177e4SLinus Torvalds * At least one address has to be left; if only one address is 6181da177e4SLinus Torvalds * available, the operation will return -EBUSY. 6191da177e4SLinus Torvalds * 6201da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 6211da177e4SLinus Torvalds */ 62204675210Ssebastian@breakpoint.cc static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) 6231da177e4SLinus Torvalds { 6241da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 6251da177e4SLinus Torvalds struct sctp_endpoint *ep = sp->ep; 6261da177e4SLinus Torvalds int cnt; 6271da177e4SLinus Torvalds struct sctp_bind_addr *bp = &ep->base.bind_addr; 6281da177e4SLinus Torvalds int retval = 0; 6291da177e4SLinus Torvalds void *addr_buf; 630c9a08505SAl Viro union sctp_addr *sa_addr; 6311da177e4SLinus Torvalds struct sctp_af *af; 6321da177e4SLinus Torvalds 633bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 634bb33381dSDaniel Borkmann __func__, sk, addrs, addrcnt); 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds addr_buf = addrs; 6371da177e4SLinus Torvalds for (cnt = 0; cnt < addrcnt; cnt++) { 6381da177e4SLinus Torvalds /* If the bind address list is empty or if there is only one 6391da177e4SLinus Torvalds * bind address, there is nothing more to be removed (we need 6401da177e4SLinus Torvalds * at least one address here). 6411da177e4SLinus Torvalds */ 6421da177e4SLinus Torvalds if (list_empty(&bp->address_list) || 6431da177e4SLinus Torvalds (sctp_list_single_entry(&bp->address_list))) { 6441da177e4SLinus Torvalds retval = -EBUSY; 6451da177e4SLinus Torvalds goto err_bindx_rem; 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds 648ea110733SJoe Perches sa_addr = addr_buf; 649c9a08505SAl Viro af = sctp_get_af_specific(sa_addr->sa.sa_family); 6501da177e4SLinus Torvalds if (!af) { 6511da177e4SLinus Torvalds retval = -EINVAL; 6521da177e4SLinus Torvalds goto err_bindx_rem; 6531da177e4SLinus Torvalds } 6540304ff8aSPaolo Galtieri 6550304ff8aSPaolo Galtieri if (!af->addr_valid(sa_addr, sp, NULL)) { 6560304ff8aSPaolo Galtieri retval = -EADDRNOTAVAIL; 6570304ff8aSPaolo Galtieri goto err_bindx_rem; 6580304ff8aSPaolo Galtieri } 6590304ff8aSPaolo Galtieri 660ee9cbacaSVlad Yasevich if (sa_addr->v4.sin_port && 661ee9cbacaSVlad Yasevich sa_addr->v4.sin_port != htons(bp->port)) { 6621da177e4SLinus Torvalds retval = -EINVAL; 6631da177e4SLinus Torvalds goto err_bindx_rem; 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 666ee9cbacaSVlad Yasevich if (!sa_addr->v4.sin_port) 667ee9cbacaSVlad Yasevich sa_addr->v4.sin_port = htons(bp->port); 668ee9cbacaSVlad Yasevich 6691da177e4SLinus Torvalds /* FIXME - There is probably a need to check if sk->sk_saddr and 6701da177e4SLinus Torvalds * sk->sk_rcv_addr are currently set to one of the addresses to 6711da177e4SLinus Torvalds * be removed. This is something which needs to be looked into 6721da177e4SLinus Torvalds * when we are fixing the outstanding issues with multi-homing 6731da177e4SLinus Torvalds * socket routing and failover schemes. Refer to comments in 6741da177e4SLinus Torvalds * sctp_do_bind(). -daisy 6751da177e4SLinus Torvalds */ 6760ed90fb0SVlad Yasevich retval = sctp_del_bind_addr(bp, sa_addr); 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 6791da177e4SLinus Torvalds err_bindx_rem: 6801da177e4SLinus Torvalds if (retval < 0) { 6811da177e4SLinus Torvalds /* Failed. Add the ones that has been removed back */ 6821da177e4SLinus Torvalds if (cnt > 0) 6831da177e4SLinus Torvalds sctp_bindx_add(sk, addrs, cnt); 6841da177e4SLinus Torvalds return retval; 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds return retval; 6891da177e4SLinus Torvalds } 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds /* Send an ASCONF chunk with Delete IP address parameters to all the peers of 6921da177e4SLinus Torvalds * the associations that are part of the endpoint indicating that a list of 6931da177e4SLinus Torvalds * local addresses are removed from the endpoint. 6941da177e4SLinus Torvalds * 6951da177e4SLinus Torvalds * If any of the addresses is already in the bind address list of the 6961da177e4SLinus Torvalds * association, we do not send the chunk for that association. But it will not 6971da177e4SLinus Torvalds * affect other associations. 6981da177e4SLinus Torvalds * 6991da177e4SLinus Torvalds * Only sctp_setsockopt_bindx() is supposed to call this function. 7001da177e4SLinus Torvalds */ 7011da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock *sk, 7021da177e4SLinus Torvalds struct sockaddr *addrs, 7031da177e4SLinus Torvalds int addrcnt) 7041da177e4SLinus Torvalds { 705e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 7061da177e4SLinus Torvalds struct sctp_sock *sp; 7071da177e4SLinus Torvalds struct sctp_endpoint *ep; 7081da177e4SLinus Torvalds struct sctp_association *asoc; 709dc022a98SSridhar Samudrala struct sctp_transport *transport; 7101da177e4SLinus Torvalds struct sctp_bind_addr *bp; 7111da177e4SLinus Torvalds struct sctp_chunk *chunk; 7121da177e4SLinus Torvalds union sctp_addr *laddr; 7131da177e4SLinus Torvalds void *addr_buf; 7141da177e4SLinus Torvalds struct sctp_af *af; 715dc022a98SSridhar Samudrala struct sctp_sockaddr_entry *saddr; 7161da177e4SLinus Torvalds int i; 7171da177e4SLinus Torvalds int retval = 0; 7188a07eb0aSMichio Honda int stored = 0; 7191da177e4SLinus Torvalds 7208a07eb0aSMichio Honda chunk = NULL; 721e1fc3b14SEric W. Biederman if (!net->sctp.addip_enable) 7221da177e4SLinus Torvalds return retval; 7231da177e4SLinus Torvalds 7241da177e4SLinus Torvalds sp = sctp_sk(sk); 7251da177e4SLinus Torvalds ep = sp->ep; 7261da177e4SLinus Torvalds 727bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", 7280dc47877SHarvey Harrison __func__, sk, addrs, addrcnt); 7291da177e4SLinus Torvalds 7309dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &ep->asocs, asocs) { 7311da177e4SLinus Torvalds 7321da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 7331da177e4SLinus Torvalds continue; 7341da177e4SLinus Torvalds 7351da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_DEL_IP) 7361da177e4SLinus Torvalds continue; 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 7391da177e4SLinus Torvalds continue; 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds /* Check if any address in the packed array of addresses is 7421da177e4SLinus Torvalds * not present in the bind address list of the association. 7431da177e4SLinus Torvalds * If so, do not send the asconf chunk to its peer, but 7441da177e4SLinus Torvalds * continue with other associations. 7451da177e4SLinus Torvalds */ 7461da177e4SLinus Torvalds addr_buf = addrs; 7471da177e4SLinus Torvalds for (i = 0; i < addrcnt; i++) { 748ea110733SJoe Perches laddr = addr_buf; 7491da177e4SLinus Torvalds af = sctp_get_af_specific(laddr->v4.sin_family); 7501da177e4SLinus Torvalds if (!af) { 7511da177e4SLinus Torvalds retval = -EINVAL; 7521da177e4SLinus Torvalds goto out; 7531da177e4SLinus Torvalds } 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds if (!sctp_assoc_lookup_laddr(asoc, laddr)) 7561da177e4SLinus Torvalds break; 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds if (i < addrcnt) 7611da177e4SLinus Torvalds continue; 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds /* Find one address in the association's bind address list 7641da177e4SLinus Torvalds * that is not in the packed array of addresses. This is to 7651da177e4SLinus Torvalds * make sure that we do not delete all the addresses in the 7661da177e4SLinus Torvalds * association. 7671da177e4SLinus Torvalds */ 7681da177e4SLinus Torvalds bp = &asoc->base.bind_addr; 7691da177e4SLinus Torvalds laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, 7701da177e4SLinus Torvalds addrcnt, sp); 7718a07eb0aSMichio Honda if ((laddr == NULL) && (addrcnt == 1)) { 7728a07eb0aSMichio Honda if (asoc->asconf_addr_del_pending) 7731da177e4SLinus Torvalds continue; 7748a07eb0aSMichio Honda asoc->asconf_addr_del_pending = 7758a07eb0aSMichio Honda kzalloc(sizeof(union sctp_addr), GFP_ATOMIC); 7766d65e5eeSMichio Honda if (asoc->asconf_addr_del_pending == NULL) { 7776d65e5eeSMichio Honda retval = -ENOMEM; 7786d65e5eeSMichio Honda goto out; 7796d65e5eeSMichio Honda } 7808a07eb0aSMichio Honda asoc->asconf_addr_del_pending->sa.sa_family = 7818a07eb0aSMichio Honda addrs->sa_family; 7828a07eb0aSMichio Honda asoc->asconf_addr_del_pending->v4.sin_port = 7838a07eb0aSMichio Honda htons(bp->port); 7848a07eb0aSMichio Honda if (addrs->sa_family == AF_INET) { 7858a07eb0aSMichio Honda struct sockaddr_in *sin; 7868a07eb0aSMichio Honda 7878a07eb0aSMichio Honda sin = (struct sockaddr_in *)addrs; 7888a07eb0aSMichio Honda asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr; 7898a07eb0aSMichio Honda } else if (addrs->sa_family == AF_INET6) { 7908a07eb0aSMichio Honda struct sockaddr_in6 *sin6; 7918a07eb0aSMichio Honda 7928a07eb0aSMichio Honda sin6 = (struct sockaddr_in6 *)addrs; 7934e3fd7a0SAlexey Dobriyan asoc->asconf_addr_del_pending->v6.sin6_addr = sin6->sin6_addr; 7948a07eb0aSMichio Honda } 795bb33381dSDaniel Borkmann 796bb33381dSDaniel Borkmann pr_debug("%s: keep the last address asoc:%p %pISc at %p\n", 797bb33381dSDaniel Borkmann __func__, asoc, &asoc->asconf_addr_del_pending->sa, 7988a07eb0aSMichio Honda asoc->asconf_addr_del_pending); 799bb33381dSDaniel Borkmann 8008a07eb0aSMichio Honda asoc->src_out_of_asoc_ok = 1; 8018a07eb0aSMichio Honda stored = 1; 8028a07eb0aSMichio Honda goto skip_mkasconf; 8038a07eb0aSMichio Honda } 8041da177e4SLinus Torvalds 80588362ad8SDaniel Borkmann if (laddr == NULL) 80688362ad8SDaniel Borkmann return -EINVAL; 80788362ad8SDaniel Borkmann 808559cf710SVlad Yasevich /* We do not need RCU protection throughout this loop 809559cf710SVlad Yasevich * because this is done under a socket lock from the 810559cf710SVlad Yasevich * setsockopt call. 811559cf710SVlad Yasevich */ 8121da177e4SLinus Torvalds chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt, 8131da177e4SLinus Torvalds SCTP_PARAM_DEL_IP); 8141da177e4SLinus Torvalds if (!chunk) { 8151da177e4SLinus Torvalds retval = -ENOMEM; 8161da177e4SLinus Torvalds goto out; 8171da177e4SLinus Torvalds } 8181da177e4SLinus Torvalds 8198a07eb0aSMichio Honda skip_mkasconf: 820dc022a98SSridhar Samudrala /* Reset use_as_src flag for the addresses in the bind address 821dc022a98SSridhar Samudrala * list that are to be deleted. 8221da177e4SLinus Torvalds */ 823dc022a98SSridhar Samudrala addr_buf = addrs; 824dc022a98SSridhar Samudrala for (i = 0; i < addrcnt; i++) { 825ea110733SJoe Perches laddr = addr_buf; 826dc022a98SSridhar Samudrala af = sctp_get_af_specific(laddr->v4.sin_family); 827559cf710SVlad Yasevich list_for_each_entry(saddr, &bp->address_list, list) { 8285f242a13SAl Viro if (sctp_cmp_addr_exact(&saddr->a, laddr)) 829f57d96b2SVlad Yasevich saddr->state = SCTP_ADDR_DEL; 830dc022a98SSridhar Samudrala } 831dc022a98SSridhar Samudrala addr_buf += af->sockaddr_len; 832dc022a98SSridhar Samudrala } 833dc022a98SSridhar Samudrala 834dc022a98SSridhar Samudrala /* Update the route and saddr entries for all the transports 835dc022a98SSridhar Samudrala * as some of the addresses in the bind address list are 836dc022a98SSridhar Samudrala * about to be deleted and cannot be used as source addresses. 837dc022a98SSridhar Samudrala */ 8389dbc15f0SRobert P. J. Day list_for_each_entry(transport, &asoc->peer.transport_addr_list, 8399dbc15f0SRobert P. J. Day transports) { 840dc022a98SSridhar Samudrala dst_release(transport->dst); 841dc022a98SSridhar Samudrala sctp_transport_route(transport, NULL, 842dc022a98SSridhar Samudrala sctp_sk(asoc->base.sk)); 843dc022a98SSridhar Samudrala } 844dc022a98SSridhar Samudrala 8458a07eb0aSMichio Honda if (stored) 8468a07eb0aSMichio Honda /* We don't need to transmit ASCONF */ 8478a07eb0aSMichio Honda continue; 848dc022a98SSridhar Samudrala retval = sctp_send_asconf(asoc, chunk); 8491da177e4SLinus Torvalds } 8501da177e4SLinus Torvalds out: 8511da177e4SLinus Torvalds return retval; 8521da177e4SLinus Torvalds } 8531da177e4SLinus Torvalds 8549f7d653bSMichio Honda /* set addr events to assocs in the endpoint. ep and addr_wq must be locked */ 8559f7d653bSMichio Honda int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw) 8569f7d653bSMichio Honda { 8579f7d653bSMichio Honda struct sock *sk = sctp_opt2sk(sp); 8589f7d653bSMichio Honda union sctp_addr *addr; 8599f7d653bSMichio Honda struct sctp_af *af; 8609f7d653bSMichio Honda 8619f7d653bSMichio Honda /* It is safe to write port space in caller. */ 8629f7d653bSMichio Honda addr = &addrw->a; 8639f7d653bSMichio Honda addr->v4.sin_port = htons(sp->ep->base.bind_addr.port); 8649f7d653bSMichio Honda af = sctp_get_af_specific(addr->sa.sa_family); 8659f7d653bSMichio Honda if (!af) 8669f7d653bSMichio Honda return -EINVAL; 8679f7d653bSMichio Honda if (sctp_verify_addr(sk, addr, af->sockaddr_len)) 8689f7d653bSMichio Honda return -EINVAL; 8699f7d653bSMichio Honda 8709f7d653bSMichio Honda if (addrw->state == SCTP_ADDR_NEW) 8719f7d653bSMichio Honda return sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1); 8729f7d653bSMichio Honda else 8739f7d653bSMichio Honda return sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1); 8749f7d653bSMichio Honda } 8759f7d653bSMichio Honda 8761da177e4SLinus Torvalds /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt() 8771da177e4SLinus Torvalds * 8781da177e4SLinus Torvalds * API 8.1 8791da177e4SLinus Torvalds * int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, 8801da177e4SLinus Torvalds * int flags); 8811da177e4SLinus Torvalds * 8821da177e4SLinus Torvalds * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. 8831da177e4SLinus Torvalds * If the sd is an IPv6 socket, the addresses passed can either be IPv4 8841da177e4SLinus Torvalds * or IPv6 addresses. 8851da177e4SLinus Torvalds * 8861da177e4SLinus Torvalds * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see 8871da177e4SLinus Torvalds * Section 3.1.2 for this usage. 8881da177e4SLinus Torvalds * 8891da177e4SLinus Torvalds * addrs is a pointer to an array of one or more socket addresses. Each 8901da177e4SLinus Torvalds * address is contained in its appropriate structure (i.e. struct 8911da177e4SLinus Torvalds * sockaddr_in or struct sockaddr_in6) the family of the address type 89223c435f7SVille Nuorvala * must be used to distinguish the address length (note that this 8931da177e4SLinus Torvalds * representation is termed a "packed array" of addresses). The caller 8941da177e4SLinus Torvalds * specifies the number of addresses in the array with addrcnt. 8951da177e4SLinus Torvalds * 8961da177e4SLinus Torvalds * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns 8971da177e4SLinus Torvalds * -1, and sets errno to the appropriate error code. 8981da177e4SLinus Torvalds * 8991da177e4SLinus Torvalds * For SCTP, the port given in each socket address must be the same, or 9001da177e4SLinus Torvalds * sctp_bindx() will fail, setting errno to EINVAL. 9011da177e4SLinus Torvalds * 9021da177e4SLinus Torvalds * The flags parameter is formed from the bitwise OR of zero or more of 9031da177e4SLinus Torvalds * the following currently defined flags: 9041da177e4SLinus Torvalds * 9051da177e4SLinus Torvalds * SCTP_BINDX_ADD_ADDR 9061da177e4SLinus Torvalds * 9071da177e4SLinus Torvalds * SCTP_BINDX_REM_ADDR 9081da177e4SLinus Torvalds * 9091da177e4SLinus Torvalds * SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the 9101da177e4SLinus Torvalds * association, and SCTP_BINDX_REM_ADDR directs SCTP to remove the given 9111da177e4SLinus Torvalds * addresses from the association. The two flags are mutually exclusive; 9121da177e4SLinus Torvalds * if both are given, sctp_bindx() will fail with EINVAL. A caller may 9131da177e4SLinus Torvalds * not remove all addresses from an association; sctp_bindx() will 9141da177e4SLinus Torvalds * reject such an attempt with EINVAL. 9151da177e4SLinus Torvalds * 9161da177e4SLinus Torvalds * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate 9171da177e4SLinus Torvalds * additional addresses with an endpoint after calling bind(). Or use 9181da177e4SLinus Torvalds * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening 9191da177e4SLinus Torvalds * socket is associated with so that no new association accepted will be 9201da177e4SLinus Torvalds * associated with those addresses. If the endpoint supports dynamic 9211da177e4SLinus Torvalds * address a SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR may cause a 9221da177e4SLinus Torvalds * endpoint to send the appropriate message to the peer to change the 9231da177e4SLinus Torvalds * peers address lists. 9241da177e4SLinus Torvalds * 9251da177e4SLinus Torvalds * Adding and removing addresses from a connected association is 9261da177e4SLinus Torvalds * optional functionality. Implementations that do not support this 9271da177e4SLinus Torvalds * functionality should return EOPNOTSUPP. 9281da177e4SLinus Torvalds * 9291da177e4SLinus Torvalds * Basically do nothing but copying the addresses from user to kernel 9301da177e4SLinus Torvalds * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk. 9313f7a87d2SFrank Filz * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() 9323f7a87d2SFrank Filz * from userspace. 9331da177e4SLinus Torvalds * 9341da177e4SLinus Torvalds * We don't use copy_from_user() for optimization: we first do the 9351da177e4SLinus Torvalds * sanity checks (buffer size -fast- and access check-healthy 9361da177e4SLinus Torvalds * pointer); if all of those succeed, then we can alloc the memory 9371da177e4SLinus Torvalds * (expensive operation) needed to copy the data to kernel. Then we do 9381da177e4SLinus Torvalds * the copying without checking the user space area 9391da177e4SLinus Torvalds * (__copy_from_user()). 9401da177e4SLinus Torvalds * 9411da177e4SLinus Torvalds * On exit there is no need to do sockfd_put(), sys_setsockopt() does 9421da177e4SLinus Torvalds * it. 9431da177e4SLinus Torvalds * 9441da177e4SLinus Torvalds * sk The sk of the socket 9451da177e4SLinus Torvalds * addrs The pointer to the addresses in user land 9461da177e4SLinus Torvalds * addrssize Size of the addrs buffer 9471da177e4SLinus Torvalds * op Operation to perform (add or remove, see the flags of 9481da177e4SLinus Torvalds * sctp_bindx) 9491da177e4SLinus Torvalds * 9501da177e4SLinus Torvalds * Returns 0 if ok, <0 errno code on error. 9511da177e4SLinus Torvalds */ 952dda91928SDaniel Borkmann static int sctp_setsockopt_bindx(struct sock *sk, 9531da177e4SLinus Torvalds struct sockaddr __user *addrs, 9541da177e4SLinus Torvalds int addrs_size, int op) 9551da177e4SLinus Torvalds { 9561da177e4SLinus Torvalds struct sockaddr *kaddrs; 9571da177e4SLinus Torvalds int err; 9581da177e4SLinus Torvalds int addrcnt = 0; 9591da177e4SLinus Torvalds int walk_size = 0; 9601da177e4SLinus Torvalds struct sockaddr *sa_addr; 9611da177e4SLinus Torvalds void *addr_buf; 9621da177e4SLinus Torvalds struct sctp_af *af; 9631da177e4SLinus Torvalds 964bb33381dSDaniel Borkmann pr_debug("%s: sk:%p addrs:%p addrs_size:%d opt:%d\n", 965bb33381dSDaniel Borkmann __func__, sk, addrs, addrs_size, op); 9661da177e4SLinus Torvalds 9671da177e4SLinus Torvalds if (unlikely(addrs_size <= 0)) 9681da177e4SLinus Torvalds return -EINVAL; 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds /* Check the user passed a healthy pointer. */ 9711da177e4SLinus Torvalds if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size))) 9721da177e4SLinus Torvalds return -EFAULT; 9731da177e4SLinus Torvalds 9741da177e4SLinus Torvalds /* Alloc space for the address array in kernel memory. */ 975cacc0621SMarcelo Ricardo Leitner kaddrs = kmalloc(addrs_size, GFP_USER | __GFP_NOWARN); 9761da177e4SLinus Torvalds if (unlikely(!kaddrs)) 9771da177e4SLinus Torvalds return -ENOMEM; 9781da177e4SLinus Torvalds 9791da177e4SLinus Torvalds if (__copy_from_user(kaddrs, addrs, addrs_size)) { 9801da177e4SLinus Torvalds kfree(kaddrs); 9811da177e4SLinus Torvalds return -EFAULT; 9821da177e4SLinus Torvalds } 9831da177e4SLinus Torvalds 9841da177e4SLinus Torvalds /* Walk through the addrs buffer and count the number of addresses. */ 9851da177e4SLinus Torvalds addr_buf = kaddrs; 9861da177e4SLinus Torvalds while (walk_size < addrs_size) { 987d7e0d19aSDan Rosenberg if (walk_size + sizeof(sa_family_t) > addrs_size) { 988d7e0d19aSDan Rosenberg kfree(kaddrs); 989d7e0d19aSDan Rosenberg return -EINVAL; 990d7e0d19aSDan Rosenberg } 991d7e0d19aSDan Rosenberg 992ea110733SJoe Perches sa_addr = addr_buf; 9931da177e4SLinus Torvalds af = sctp_get_af_specific(sa_addr->sa_family); 9941da177e4SLinus Torvalds 9951da177e4SLinus Torvalds /* If the address family is not supported or if this address 9961da177e4SLinus Torvalds * causes the address buffer to overflow return EINVAL. 9971da177e4SLinus Torvalds */ 9981da177e4SLinus Torvalds if (!af || (walk_size + af->sockaddr_len) > addrs_size) { 9991da177e4SLinus Torvalds kfree(kaddrs); 10001da177e4SLinus Torvalds return -EINVAL; 10011da177e4SLinus Torvalds } 10021da177e4SLinus Torvalds addrcnt++; 10031da177e4SLinus Torvalds addr_buf += af->sockaddr_len; 10041da177e4SLinus Torvalds walk_size += af->sockaddr_len; 10051da177e4SLinus Torvalds } 10061da177e4SLinus Torvalds 10071da177e4SLinus Torvalds /* Do the work. */ 10081da177e4SLinus Torvalds switch (op) { 10091da177e4SLinus Torvalds case SCTP_BINDX_ADD_ADDR: 10101da177e4SLinus Torvalds err = sctp_bindx_add(sk, kaddrs, addrcnt); 10111da177e4SLinus Torvalds if (err) 10121da177e4SLinus Torvalds goto out; 10131da177e4SLinus Torvalds err = sctp_send_asconf_add_ip(sk, kaddrs, addrcnt); 10141da177e4SLinus Torvalds break; 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds case SCTP_BINDX_REM_ADDR: 10171da177e4SLinus Torvalds err = sctp_bindx_rem(sk, kaddrs, addrcnt); 10181da177e4SLinus Torvalds if (err) 10191da177e4SLinus Torvalds goto out; 10201da177e4SLinus Torvalds err = sctp_send_asconf_del_ip(sk, kaddrs, addrcnt); 10211da177e4SLinus Torvalds break; 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds default: 10241da177e4SLinus Torvalds err = -EINVAL; 10251da177e4SLinus Torvalds break; 10263ff50b79SStephen Hemminger } 10271da177e4SLinus Torvalds 10281da177e4SLinus Torvalds out: 10291da177e4SLinus Torvalds kfree(kaddrs); 10301da177e4SLinus Torvalds 10311da177e4SLinus Torvalds return err; 10321da177e4SLinus Torvalds } 10331da177e4SLinus Torvalds 10343f7a87d2SFrank Filz /* __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, int addrs_size) 10353f7a87d2SFrank Filz * 10363f7a87d2SFrank Filz * Common routine for handling connect() and sctp_connectx(). 10373f7a87d2SFrank Filz * Connect will come in with just a single address. 10383f7a87d2SFrank Filz */ 10393f7a87d2SFrank Filz static int __sctp_connect(struct sock *sk, 10403f7a87d2SFrank Filz struct sockaddr *kaddrs, 104188a0a948SVlad Yasevich int addrs_size, 104288a0a948SVlad Yasevich sctp_assoc_t *assoc_id) 10433f7a87d2SFrank Filz { 104455e26eb9SEric W. Biederman struct net *net = sock_net(sk); 10453f7a87d2SFrank Filz struct sctp_sock *sp; 10463f7a87d2SFrank Filz struct sctp_endpoint *ep; 10473f7a87d2SFrank Filz struct sctp_association *asoc = NULL; 10483f7a87d2SFrank Filz struct sctp_association *asoc2; 10493f7a87d2SFrank Filz struct sctp_transport *transport; 10503f7a87d2SFrank Filz union sctp_addr to; 10513f7a87d2SFrank Filz sctp_scope_t scope; 10523f7a87d2SFrank Filz long timeo; 10533f7a87d2SFrank Filz int err = 0; 10543f7a87d2SFrank Filz int addrcnt = 0; 10553f7a87d2SFrank Filz int walk_size = 0; 1056e4d1feabSVlad Yasevich union sctp_addr *sa_addr = NULL; 10573f7a87d2SFrank Filz void *addr_buf; 105816d00fb7SVlad Yasevich unsigned short port; 1059f50f95caSVlad Yasevich unsigned int f_flags = 0; 10603f7a87d2SFrank Filz 10613f7a87d2SFrank Filz sp = sctp_sk(sk); 10623f7a87d2SFrank Filz ep = sp->ep; 10633f7a87d2SFrank Filz 10643f7a87d2SFrank Filz /* connect() cannot be done on a socket that is already in ESTABLISHED 10653f7a87d2SFrank Filz * state - UDP-style peeled off socket or a TCP-style socket that 10663f7a87d2SFrank Filz * is already connected. 10673f7a87d2SFrank Filz * It cannot be done even on a TCP-style listening socket. 10683f7a87d2SFrank Filz */ 10693f7a87d2SFrank Filz if (sctp_sstate(sk, ESTABLISHED) || 10703f7a87d2SFrank Filz (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) { 10713f7a87d2SFrank Filz err = -EISCONN; 10723f7a87d2SFrank Filz goto out_free; 10733f7a87d2SFrank Filz } 10743f7a87d2SFrank Filz 10753f7a87d2SFrank Filz /* Walk through the addrs buffer and count the number of addresses. */ 10763f7a87d2SFrank Filz addr_buf = kaddrs; 10773f7a87d2SFrank Filz while (walk_size < addrs_size) { 1078299ee123SJason Gunthorpe struct sctp_af *af; 1079299ee123SJason Gunthorpe 1080d7e0d19aSDan Rosenberg if (walk_size + sizeof(sa_family_t) > addrs_size) { 1081d7e0d19aSDan Rosenberg err = -EINVAL; 1082d7e0d19aSDan Rosenberg goto out_free; 1083d7e0d19aSDan Rosenberg } 1084d7e0d19aSDan Rosenberg 1085ea110733SJoe Perches sa_addr = addr_buf; 10864bdf4b5fSAl Viro af = sctp_get_af_specific(sa_addr->sa.sa_family); 10873f7a87d2SFrank Filz 10883f7a87d2SFrank Filz /* If the address family is not supported or if this address 10893f7a87d2SFrank Filz * causes the address buffer to overflow return EINVAL. 10903f7a87d2SFrank Filz */ 10913f7a87d2SFrank Filz if (!af || (walk_size + af->sockaddr_len) > addrs_size) { 10923f7a87d2SFrank Filz err = -EINVAL; 10933f7a87d2SFrank Filz goto out_free; 10943f7a87d2SFrank Filz } 10953f7a87d2SFrank Filz 1096d7e0d19aSDan Rosenberg port = ntohs(sa_addr->v4.sin_port); 1097d7e0d19aSDan Rosenberg 1098e4d1feabSVlad Yasevich /* Save current address so we can work with it */ 1099e4d1feabSVlad Yasevich memcpy(&to, sa_addr, af->sockaddr_len); 1100e4d1feabSVlad Yasevich 1101e4d1feabSVlad Yasevich err = sctp_verify_addr(sk, &to, af->sockaddr_len); 11023f7a87d2SFrank Filz if (err) 11033f7a87d2SFrank Filz goto out_free; 11043f7a87d2SFrank Filz 110516d00fb7SVlad Yasevich /* Make sure the destination port is correctly set 110616d00fb7SVlad Yasevich * in all addresses. 110716d00fb7SVlad Yasevich */ 1108524fba6cSWei Yongjun if (asoc && asoc->peer.port && asoc->peer.port != port) { 1109524fba6cSWei Yongjun err = -EINVAL; 111016d00fb7SVlad Yasevich goto out_free; 1111524fba6cSWei Yongjun } 11123f7a87d2SFrank Filz 11133f7a87d2SFrank Filz /* Check if there already is a matching association on the 11143f7a87d2SFrank Filz * endpoint (other than the one created here). 11153f7a87d2SFrank Filz */ 1116e4d1feabSVlad Yasevich asoc2 = sctp_endpoint_lookup_assoc(ep, &to, &transport); 11173f7a87d2SFrank Filz if (asoc2 && asoc2 != asoc) { 11183f7a87d2SFrank Filz if (asoc2->state >= SCTP_STATE_ESTABLISHED) 11193f7a87d2SFrank Filz err = -EISCONN; 11203f7a87d2SFrank Filz else 11213f7a87d2SFrank Filz err = -EALREADY; 11223f7a87d2SFrank Filz goto out_free; 11233f7a87d2SFrank Filz } 11243f7a87d2SFrank Filz 11253f7a87d2SFrank Filz /* If we could not find a matching association on the endpoint, 11263f7a87d2SFrank Filz * make sure that there is no peeled-off association matching 11273f7a87d2SFrank Filz * the peer address even on another socket. 11283f7a87d2SFrank Filz */ 1129e4d1feabSVlad Yasevich if (sctp_endpoint_is_peeled_off(ep, &to)) { 11303f7a87d2SFrank Filz err = -EADDRNOTAVAIL; 11313f7a87d2SFrank Filz goto out_free; 11323f7a87d2SFrank Filz } 11333f7a87d2SFrank Filz 11343f7a87d2SFrank Filz if (!asoc) { 11353f7a87d2SFrank Filz /* If a bind() or sctp_bindx() is not called prior to 11363f7a87d2SFrank Filz * an sctp_connectx() call, the system picks an 11373f7a87d2SFrank Filz * ephemeral port and will choose an address set 11383f7a87d2SFrank Filz * equivalent to binding with a wildcard address. 11393f7a87d2SFrank Filz */ 11403f7a87d2SFrank Filz if (!ep->base.bind_addr.port) { 11413f7a87d2SFrank Filz if (sctp_autobind(sk)) { 11423f7a87d2SFrank Filz err = -EAGAIN; 11433f7a87d2SFrank Filz goto out_free; 11443f7a87d2SFrank Filz } 114564a0c1c8SIvan Skytte Jorgensen } else { 114664a0c1c8SIvan Skytte Jorgensen /* 114764a0c1c8SIvan Skytte Jorgensen * If an unprivileged user inherits a 1-many 114864a0c1c8SIvan Skytte Jorgensen * style socket with open associations on a 114964a0c1c8SIvan Skytte Jorgensen * privileged port, it MAY be permitted to 115064a0c1c8SIvan Skytte Jorgensen * accept new associations, but it SHOULD NOT 115164a0c1c8SIvan Skytte Jorgensen * be permitted to open new associations. 115264a0c1c8SIvan Skytte Jorgensen */ 115364a0c1c8SIvan Skytte Jorgensen if (ep->base.bind_addr.port < PROT_SOCK && 11543594698aSEric W. Biederman !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { 115564a0c1c8SIvan Skytte Jorgensen err = -EACCES; 115664a0c1c8SIvan Skytte Jorgensen goto out_free; 115764a0c1c8SIvan Skytte Jorgensen } 11583f7a87d2SFrank Filz } 11593f7a87d2SFrank Filz 1160e4d1feabSVlad Yasevich scope = sctp_scope(&to); 11613f7a87d2SFrank Filz asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); 11623f7a87d2SFrank Filz if (!asoc) { 11633f7a87d2SFrank Filz err = -ENOMEM; 11643f7a87d2SFrank Filz goto out_free; 11653f7a87d2SFrank Filz } 1166409b95afSVlad Yasevich 1167409b95afSVlad Yasevich err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, 1168409b95afSVlad Yasevich GFP_KERNEL); 1169409b95afSVlad Yasevich if (err < 0) { 1170409b95afSVlad Yasevich goto out_free; 1171409b95afSVlad Yasevich } 1172409b95afSVlad Yasevich 11733f7a87d2SFrank Filz } 11743f7a87d2SFrank Filz 11753f7a87d2SFrank Filz /* Prime the peer's transport structures. */ 1176e4d1feabSVlad Yasevich transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, 11773f7a87d2SFrank Filz SCTP_UNKNOWN); 11783f7a87d2SFrank Filz if (!transport) { 11793f7a87d2SFrank Filz err = -ENOMEM; 11803f7a87d2SFrank Filz goto out_free; 11813f7a87d2SFrank Filz } 11823f7a87d2SFrank Filz 11833f7a87d2SFrank Filz addrcnt++; 11843f7a87d2SFrank Filz addr_buf += af->sockaddr_len; 11853f7a87d2SFrank Filz walk_size += af->sockaddr_len; 11863f7a87d2SFrank Filz } 11873f7a87d2SFrank Filz 1188c6ba68a2SVlad Yasevich /* In case the user of sctp_connectx() wants an association 1189c6ba68a2SVlad Yasevich * id back, assign one now. 1190c6ba68a2SVlad Yasevich */ 1191c6ba68a2SVlad Yasevich if (assoc_id) { 1192c6ba68a2SVlad Yasevich err = sctp_assoc_set_id(asoc, GFP_KERNEL); 1193c6ba68a2SVlad Yasevich if (err < 0) 1194c6ba68a2SVlad Yasevich goto out_free; 1195c6ba68a2SVlad Yasevich } 1196c6ba68a2SVlad Yasevich 119755e26eb9SEric W. Biederman err = sctp_primitive_ASSOCIATE(net, asoc, NULL); 11983f7a87d2SFrank Filz if (err < 0) { 11993f7a87d2SFrank Filz goto out_free; 12003f7a87d2SFrank Filz } 12013f7a87d2SFrank Filz 12023f7a87d2SFrank Filz /* Initialize sk's dport and daddr for getpeername() */ 1203c720c7e8SEric Dumazet inet_sk(sk)->inet_dport = htons(asoc->peer.port); 1204299ee123SJason Gunthorpe sp->pf->to_sk_daddr(sa_addr, sk); 12058de8c873SSridhar Samudrala sk->sk_err = 0; 12063f7a87d2SFrank Filz 1207f50f95caSVlad Yasevich /* in-kernel sockets don't generally have a file allocated to them 1208f50f95caSVlad Yasevich * if all they do is call sock_create_kern(). 1209f50f95caSVlad Yasevich */ 1210f50f95caSVlad Yasevich if (sk->sk_socket->file) 1211f50f95caSVlad Yasevich f_flags = sk->sk_socket->file->f_flags; 1212f50f95caSVlad Yasevich 1213f50f95caSVlad Yasevich timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK); 1214f50f95caSVlad Yasevich 12153f7a87d2SFrank Filz err = sctp_wait_for_connect(asoc, &timeo); 1216c6ba68a2SVlad Yasevich if ((err == 0 || err == -EINPROGRESS) && assoc_id) 121788a0a948SVlad Yasevich *assoc_id = asoc->assoc_id; 12183f7a87d2SFrank Filz 12193f7a87d2SFrank Filz /* Don't free association on exit. */ 12203f7a87d2SFrank Filz asoc = NULL; 12213f7a87d2SFrank Filz 12223f7a87d2SFrank Filz out_free: 1223bb33381dSDaniel Borkmann pr_debug("%s: took out_free path with asoc:%p kaddrs:%p err:%d\n", 1224bb33381dSDaniel Borkmann __func__, asoc, kaddrs, err); 12253f7a87d2SFrank Filz 12262eebc1e1SNeil Horman if (asoc) { 12272eebc1e1SNeil Horman /* sctp_primitive_ASSOCIATE may have added this association 12282eebc1e1SNeil Horman * To the hash table, try to unhash it, just in case, its a noop 12292eebc1e1SNeil Horman * if it wasn't hashed so we're safe 12302eebc1e1SNeil Horman */ 12312eebc1e1SNeil Horman sctp_unhash_established(asoc); 12323f7a87d2SFrank Filz sctp_association_free(asoc); 12332eebc1e1SNeil Horman } 12343f7a87d2SFrank Filz return err; 12353f7a87d2SFrank Filz } 12363f7a87d2SFrank Filz 12373f7a87d2SFrank Filz /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt() 12383f7a87d2SFrank Filz * 12393f7a87d2SFrank Filz * API 8.9 124088a0a948SVlad Yasevich * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt, 124188a0a948SVlad Yasevich * sctp_assoc_t *asoc); 12423f7a87d2SFrank Filz * 12433f7a87d2SFrank Filz * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. 12443f7a87d2SFrank Filz * If the sd is an IPv6 socket, the addresses passed can either be IPv4 12453f7a87d2SFrank Filz * or IPv6 addresses. 12463f7a87d2SFrank Filz * 12473f7a87d2SFrank Filz * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see 12483f7a87d2SFrank Filz * Section 3.1.2 for this usage. 12493f7a87d2SFrank Filz * 12503f7a87d2SFrank Filz * addrs is a pointer to an array of one or more socket addresses. Each 12513f7a87d2SFrank Filz * address is contained in its appropriate structure (i.e. struct 12523f7a87d2SFrank Filz * sockaddr_in or struct sockaddr_in6) the family of the address type 12533f7a87d2SFrank Filz * must be used to distengish the address length (note that this 12543f7a87d2SFrank Filz * representation is termed a "packed array" of addresses). The caller 12553f7a87d2SFrank Filz * specifies the number of addresses in the array with addrcnt. 12563f7a87d2SFrank Filz * 125788a0a948SVlad Yasevich * On success, sctp_connectx() returns 0. It also sets the assoc_id to 125888a0a948SVlad Yasevich * the association id of the new association. On failure, sctp_connectx() 125988a0a948SVlad Yasevich * returns -1, and sets errno to the appropriate error code. The assoc_id 126088a0a948SVlad Yasevich * is not touched by the kernel. 12613f7a87d2SFrank Filz * 12623f7a87d2SFrank Filz * For SCTP, the port given in each socket address must be the same, or 12633f7a87d2SFrank Filz * sctp_connectx() will fail, setting errno to EINVAL. 12643f7a87d2SFrank Filz * 12653f7a87d2SFrank Filz * An application can use sctp_connectx to initiate an association with 12663f7a87d2SFrank Filz * an endpoint that is multi-homed. Much like sctp_bindx() this call 12673f7a87d2SFrank Filz * allows a caller to specify multiple addresses at which a peer can be 12683f7a87d2SFrank Filz * reached. The way the SCTP stack uses the list of addresses to set up 126925985edcSLucas De Marchi * the association is implementation dependent. This function only 12703f7a87d2SFrank Filz * specifies that the stack will try to make use of all the addresses in 12713f7a87d2SFrank Filz * the list when needed. 12723f7a87d2SFrank Filz * 12733f7a87d2SFrank Filz * Note that the list of addresses passed in is only used for setting up 12743f7a87d2SFrank Filz * the association. It does not necessarily equal the set of addresses 12753f7a87d2SFrank Filz * the peer uses for the resulting association. If the caller wants to 12763f7a87d2SFrank Filz * find out the set of peer addresses, it must use sctp_getpaddrs() to 12773f7a87d2SFrank Filz * retrieve them after the association has been set up. 12783f7a87d2SFrank Filz * 12793f7a87d2SFrank Filz * Basically do nothing but copying the addresses from user to kernel 12803f7a87d2SFrank Filz * land and invoking either sctp_connectx(). This is used for tunneling 12813f7a87d2SFrank Filz * the sctp_connectx() request through sctp_setsockopt() from userspace. 12823f7a87d2SFrank Filz * 12833f7a87d2SFrank Filz * We don't use copy_from_user() for optimization: we first do the 12843f7a87d2SFrank Filz * sanity checks (buffer size -fast- and access check-healthy 12853f7a87d2SFrank Filz * pointer); if all of those succeed, then we can alloc the memory 12863f7a87d2SFrank Filz * (expensive operation) needed to copy the data to kernel. Then we do 12873f7a87d2SFrank Filz * the copying without checking the user space area 12883f7a87d2SFrank Filz * (__copy_from_user()). 12893f7a87d2SFrank Filz * 12903f7a87d2SFrank Filz * On exit there is no need to do sockfd_put(), sys_setsockopt() does 12913f7a87d2SFrank Filz * it. 12923f7a87d2SFrank Filz * 12933f7a87d2SFrank Filz * sk The sk of the socket 12943f7a87d2SFrank Filz * addrs The pointer to the addresses in user land 12953f7a87d2SFrank Filz * addrssize Size of the addrs buffer 12963f7a87d2SFrank Filz * 129788a0a948SVlad Yasevich * Returns >=0 if ok, <0 errno code on error. 12983f7a87d2SFrank Filz */ 1299dda91928SDaniel Borkmann static int __sctp_setsockopt_connectx(struct sock *sk, 13003f7a87d2SFrank Filz struct sockaddr __user *addrs, 130188a0a948SVlad Yasevich int addrs_size, 130288a0a948SVlad Yasevich sctp_assoc_t *assoc_id) 13033f7a87d2SFrank Filz { 13043f7a87d2SFrank Filz int err = 0; 13053f7a87d2SFrank Filz struct sockaddr *kaddrs; 13063f7a87d2SFrank Filz 1307bb33381dSDaniel Borkmann pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n", 13080dc47877SHarvey Harrison __func__, sk, addrs, addrs_size); 13093f7a87d2SFrank Filz 13103f7a87d2SFrank Filz if (unlikely(addrs_size <= 0)) 13113f7a87d2SFrank Filz return -EINVAL; 13123f7a87d2SFrank Filz 13133f7a87d2SFrank Filz /* Check the user passed a healthy pointer. */ 13143f7a87d2SFrank Filz if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size))) 13153f7a87d2SFrank Filz return -EFAULT; 13163f7a87d2SFrank Filz 13173f7a87d2SFrank Filz /* Alloc space for the address array in kernel memory. */ 13188b3a7005SKris Katterjohn kaddrs = kmalloc(addrs_size, GFP_KERNEL); 13193f7a87d2SFrank Filz if (unlikely(!kaddrs)) 13203f7a87d2SFrank Filz return -ENOMEM; 13213f7a87d2SFrank Filz 13223f7a87d2SFrank Filz if (__copy_from_user(kaddrs, addrs, addrs_size)) { 13233f7a87d2SFrank Filz err = -EFAULT; 13243f7a87d2SFrank Filz } else { 132588a0a948SVlad Yasevich err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id); 13263f7a87d2SFrank Filz } 13273f7a87d2SFrank Filz 13283f7a87d2SFrank Filz kfree(kaddrs); 132988a0a948SVlad Yasevich 13303f7a87d2SFrank Filz return err; 13313f7a87d2SFrank Filz } 13323f7a87d2SFrank Filz 133388a0a948SVlad Yasevich /* 133488a0a948SVlad Yasevich * This is an older interface. It's kept for backward compatibility 133588a0a948SVlad Yasevich * to the option that doesn't provide association id. 133688a0a948SVlad Yasevich */ 1337dda91928SDaniel Borkmann static int sctp_setsockopt_connectx_old(struct sock *sk, 133888a0a948SVlad Yasevich struct sockaddr __user *addrs, 133988a0a948SVlad Yasevich int addrs_size) 134088a0a948SVlad Yasevich { 134188a0a948SVlad Yasevich return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL); 134288a0a948SVlad Yasevich } 134388a0a948SVlad Yasevich 134488a0a948SVlad Yasevich /* 134588a0a948SVlad Yasevich * New interface for the API. The since the API is done with a socket 134688a0a948SVlad Yasevich * option, to make it simple we feed back the association id is as a return 134788a0a948SVlad Yasevich * indication to the call. Error is always negative and association id is 134888a0a948SVlad Yasevich * always positive. 134988a0a948SVlad Yasevich */ 1350dda91928SDaniel Borkmann static int sctp_setsockopt_connectx(struct sock *sk, 135188a0a948SVlad Yasevich struct sockaddr __user *addrs, 135288a0a948SVlad Yasevich int addrs_size) 135388a0a948SVlad Yasevich { 135488a0a948SVlad Yasevich sctp_assoc_t assoc_id = 0; 135588a0a948SVlad Yasevich int err = 0; 135688a0a948SVlad Yasevich 135788a0a948SVlad Yasevich err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id); 135888a0a948SVlad Yasevich 135988a0a948SVlad Yasevich if (err) 136088a0a948SVlad Yasevich return err; 136188a0a948SVlad Yasevich else 136288a0a948SVlad Yasevich return assoc_id; 136388a0a948SVlad Yasevich } 136488a0a948SVlad Yasevich 1365c6ba68a2SVlad Yasevich /* 1366f9c67811SVlad Yasevich * New (hopefully final) interface for the API. 1367f9c67811SVlad Yasevich * We use the sctp_getaddrs_old structure so that use-space library 1368ffd59393SDaniel Borkmann * can avoid any unnecessary allocations. The only different part 1369f9c67811SVlad Yasevich * is that we store the actual length of the address buffer into the 1370f9c67811SVlad Yasevich * addrs_num structure member. That way we can re-use the existing 1371f9c67811SVlad Yasevich * code. 1372c6ba68a2SVlad Yasevich */ 1373ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT 1374ffd59393SDaniel Borkmann struct compat_sctp_getaddrs_old { 1375ffd59393SDaniel Borkmann sctp_assoc_t assoc_id; 1376ffd59393SDaniel Borkmann s32 addr_num; 1377ffd59393SDaniel Borkmann compat_uptr_t addrs; /* struct sockaddr * */ 1378ffd59393SDaniel Borkmann }; 1379ffd59393SDaniel Borkmann #endif 1380ffd59393SDaniel Borkmann 1381dda91928SDaniel Borkmann static int sctp_getsockopt_connectx3(struct sock *sk, int len, 1382c6ba68a2SVlad Yasevich char __user *optval, 1383c6ba68a2SVlad Yasevich int __user *optlen) 1384c6ba68a2SVlad Yasevich { 1385f9c67811SVlad Yasevich struct sctp_getaddrs_old param; 1386c6ba68a2SVlad Yasevich sctp_assoc_t assoc_id = 0; 1387c6ba68a2SVlad Yasevich int err = 0; 1388c6ba68a2SVlad Yasevich 1389ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT 1390ffd59393SDaniel Borkmann if (is_compat_task()) { 1391ffd59393SDaniel Borkmann struct compat_sctp_getaddrs_old param32; 1392c6ba68a2SVlad Yasevich 1393ffd59393SDaniel Borkmann if (len < sizeof(param32)) 1394ffd59393SDaniel Borkmann return -EINVAL; 1395ffd59393SDaniel Borkmann if (copy_from_user(¶m32, optval, sizeof(param32))) 1396f9c67811SVlad Yasevich return -EFAULT; 1397f9c67811SVlad Yasevich 1398ffd59393SDaniel Borkmann param.assoc_id = param32.assoc_id; 1399ffd59393SDaniel Borkmann param.addr_num = param32.addr_num; 1400ffd59393SDaniel Borkmann param.addrs = compat_ptr(param32.addrs); 1401ffd59393SDaniel Borkmann } else 1402ffd59393SDaniel Borkmann #endif 1403ffd59393SDaniel Borkmann { 1404ffd59393SDaniel Borkmann if (len < sizeof(param)) 1405ffd59393SDaniel Borkmann return -EINVAL; 1406ffd59393SDaniel Borkmann if (copy_from_user(¶m, optval, sizeof(param))) 1407ffd59393SDaniel Borkmann return -EFAULT; 1408ffd59393SDaniel Borkmann } 1409c6ba68a2SVlad Yasevich 1410ffd59393SDaniel Borkmann err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *) 1411ffd59393SDaniel Borkmann param.addrs, param.addr_num, 1412ffd59393SDaniel Borkmann &assoc_id); 1413c6ba68a2SVlad Yasevich if (err == 0 || err == -EINPROGRESS) { 1414c6ba68a2SVlad Yasevich if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) 1415c6ba68a2SVlad Yasevich return -EFAULT; 1416c6ba68a2SVlad Yasevich if (put_user(sizeof(assoc_id), optlen)) 1417c6ba68a2SVlad Yasevich return -EFAULT; 1418c6ba68a2SVlad Yasevich } 1419c6ba68a2SVlad Yasevich 1420c6ba68a2SVlad Yasevich return err; 1421c6ba68a2SVlad Yasevich } 1422c6ba68a2SVlad Yasevich 14231da177e4SLinus Torvalds /* API 3.1.4 close() - UDP Style Syntax 14241da177e4SLinus Torvalds * Applications use close() to perform graceful shutdown (as described in 14251da177e4SLinus Torvalds * Section 10.1 of [SCTP]) on ALL the associations currently represented 14261da177e4SLinus Torvalds * by a UDP-style socket. 14271da177e4SLinus Torvalds * 14281da177e4SLinus Torvalds * The syntax is 14291da177e4SLinus Torvalds * 14301da177e4SLinus Torvalds * ret = close(int sd); 14311da177e4SLinus Torvalds * 14321da177e4SLinus Torvalds * sd - the socket descriptor of the associations to be closed. 14331da177e4SLinus Torvalds * 14341da177e4SLinus Torvalds * To gracefully shutdown a specific association represented by the 14351da177e4SLinus Torvalds * UDP-style socket, an application should use the sendmsg() call, 14361da177e4SLinus Torvalds * passing no user data, but including the appropriate flag in the 14371da177e4SLinus Torvalds * ancillary data (see Section xxxx). 14381da177e4SLinus Torvalds * 14391da177e4SLinus Torvalds * If sd in the close() call is a branched-off socket representing only 14401da177e4SLinus Torvalds * one association, the shutdown is performed on that association only. 14411da177e4SLinus Torvalds * 14421da177e4SLinus Torvalds * 4.1.6 close() - TCP Style Syntax 14431da177e4SLinus Torvalds * 14441da177e4SLinus Torvalds * Applications use close() to gracefully close down an association. 14451da177e4SLinus Torvalds * 14461da177e4SLinus Torvalds * The syntax is: 14471da177e4SLinus Torvalds * 14481da177e4SLinus Torvalds * int close(int sd); 14491da177e4SLinus Torvalds * 14501da177e4SLinus Torvalds * sd - the socket descriptor of the association to be closed. 14511da177e4SLinus Torvalds * 14521da177e4SLinus Torvalds * After an application calls close() on a socket descriptor, no further 14531da177e4SLinus Torvalds * socket operations will succeed on that descriptor. 14541da177e4SLinus Torvalds * 14551da177e4SLinus Torvalds * API 7.1.4 SO_LINGER 14561da177e4SLinus Torvalds * 14571da177e4SLinus Torvalds * An application using the TCP-style socket can use this option to 14581da177e4SLinus Torvalds * perform the SCTP ABORT primitive. The linger option structure is: 14591da177e4SLinus Torvalds * 14601da177e4SLinus Torvalds * struct linger { 14611da177e4SLinus Torvalds * int l_onoff; // option on/off 14621da177e4SLinus Torvalds * int l_linger; // linger time 14631da177e4SLinus Torvalds * }; 14641da177e4SLinus Torvalds * 14651da177e4SLinus Torvalds * To enable the option, set l_onoff to 1. If the l_linger value is set 14661da177e4SLinus Torvalds * to 0, calling close() is the same as the ABORT primitive. If the 14671da177e4SLinus Torvalds * value is set to a negative value, the setsockopt() call will return 14681da177e4SLinus Torvalds * an error. If the value is set to a positive value linger_time, the 14691da177e4SLinus Torvalds * close() can be blocked for at most linger_time ms. If the graceful 14701da177e4SLinus Torvalds * shutdown phase does not finish during this period, close() will 14711da177e4SLinus Torvalds * return but the graceful shutdown phase continues in the system. 14721da177e4SLinus Torvalds */ 1473dda91928SDaniel Borkmann static void sctp_close(struct sock *sk, long timeout) 14741da177e4SLinus Torvalds { 147555e26eb9SEric W. Biederman struct net *net = sock_net(sk); 14761da177e4SLinus Torvalds struct sctp_endpoint *ep; 14771da177e4SLinus Torvalds struct sctp_association *asoc; 14781da177e4SLinus Torvalds struct list_head *pos, *temp; 1479cd4fcc70SThomas Graf unsigned int data_was_unread; 14801da177e4SLinus Torvalds 1481bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout); 14821da177e4SLinus Torvalds 1483048ed4b6Swangweidong lock_sock(sk); 14841da177e4SLinus Torvalds sk->sk_shutdown = SHUTDOWN_MASK; 1485bec9640bSVlad Yasevich sk->sk_state = SCTP_SS_CLOSING; 14861da177e4SLinus Torvalds 14871da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 14881da177e4SLinus Torvalds 1489cd4fcc70SThomas Graf /* Clean up any skbs sitting on the receive queue. */ 1490cd4fcc70SThomas Graf data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue); 1491cd4fcc70SThomas Graf data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); 1492cd4fcc70SThomas Graf 149361c9fed4SVladislav Yasevich /* Walk all associations on an endpoint. */ 14941da177e4SLinus Torvalds list_for_each_safe(pos, temp, &ep->asocs) { 14951da177e4SLinus Torvalds asoc = list_entry(pos, struct sctp_association, asocs); 14961da177e4SLinus Torvalds 14971da177e4SLinus Torvalds if (sctp_style(sk, TCP)) { 14981da177e4SLinus Torvalds /* A closed association can still be in the list if 14991da177e4SLinus Torvalds * it belongs to a TCP-style listening socket that is 15001da177e4SLinus Torvalds * not yet accepted. If so, free it. If not, send an 15011da177e4SLinus Torvalds * ABORT or SHUTDOWN based on the linger options. 15021da177e4SLinus Torvalds */ 15031da177e4SLinus Torvalds if (sctp_state(asoc, CLOSED)) { 15041da177e4SLinus Torvalds sctp_unhash_established(asoc); 15051da177e4SLinus Torvalds sctp_association_free(asoc); 1506b89498a1SVladislav Yasevich continue; 1507b89498a1SVladislav Yasevich } 1508b89498a1SVladislav Yasevich } 15091da177e4SLinus Torvalds 1510cd4fcc70SThomas Graf if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) || 1511cd4fcc70SThomas Graf !skb_queue_empty(&asoc->ulpq.reasm) || 1512cd4fcc70SThomas Graf (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { 1513b9ac8672SSridhar Samudrala struct sctp_chunk *chunk; 1514b9ac8672SSridhar Samudrala 1515b9ac8672SSridhar Samudrala chunk = sctp_make_abort_user(asoc, NULL, 0); 1516b9ac8672SSridhar Samudrala if (chunk) 151755e26eb9SEric W. Biederman sctp_primitive_ABORT(net, asoc, chunk); 1518b9ac8672SSridhar Samudrala } else 151955e26eb9SEric W. Biederman sctp_primitive_SHUTDOWN(net, asoc, NULL); 15201da177e4SLinus Torvalds } 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvalds /* On a TCP-style socket, block for at most linger_time if set. */ 15231da177e4SLinus Torvalds if (sctp_style(sk, TCP) && timeout) 15241da177e4SLinus Torvalds sctp_wait_for_close(sk, timeout); 15251da177e4SLinus Torvalds 15261da177e4SLinus Torvalds /* This will run the backlog queue. */ 1527048ed4b6Swangweidong release_sock(sk); 15281da177e4SLinus Torvalds 15291da177e4SLinus Torvalds /* Supposedly, no process has access to the socket, but 15301da177e4SLinus Torvalds * the net layers still may. 15312d45a02dSMarcelo Ricardo Leitner * Also, sctp_destroy_sock() needs to be called with addr_wq_lock 15322d45a02dSMarcelo Ricardo Leitner * held and that should be grabbed before socket lock. 15331da177e4SLinus Torvalds */ 15342d45a02dSMarcelo Ricardo Leitner spin_lock_bh(&net->sctp.addr_wq_lock); 15355bc1d1b4Swangweidong bh_lock_sock(sk); 15361da177e4SLinus Torvalds 15371da177e4SLinus Torvalds /* Hold the sock, since sk_common_release() will put sock_put() 15381da177e4SLinus Torvalds * and we have just a little more cleanup. 15391da177e4SLinus Torvalds */ 15401da177e4SLinus Torvalds sock_hold(sk); 15411da177e4SLinus Torvalds sk_common_release(sk); 15421da177e4SLinus Torvalds 15435bc1d1b4Swangweidong bh_unlock_sock(sk); 15442d45a02dSMarcelo Ricardo Leitner spin_unlock_bh(&net->sctp.addr_wq_lock); 15451da177e4SLinus Torvalds 15461da177e4SLinus Torvalds sock_put(sk); 15471da177e4SLinus Torvalds 15481da177e4SLinus Torvalds SCTP_DBG_OBJCNT_DEC(sock); 15491da177e4SLinus Torvalds } 15501da177e4SLinus Torvalds 15511da177e4SLinus Torvalds /* Handle EPIPE error. */ 15521da177e4SLinus Torvalds static int sctp_error(struct sock *sk, int flags, int err) 15531da177e4SLinus Torvalds { 15541da177e4SLinus Torvalds if (err == -EPIPE) 15551da177e4SLinus Torvalds err = sock_error(sk) ? : -EPIPE; 15561da177e4SLinus Torvalds if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) 15571da177e4SLinus Torvalds send_sig(SIGPIPE, current, 0); 15581da177e4SLinus Torvalds return err; 15591da177e4SLinus Torvalds } 15601da177e4SLinus Torvalds 15611da177e4SLinus Torvalds /* API 3.1.3 sendmsg() - UDP Style Syntax 15621da177e4SLinus Torvalds * 15631da177e4SLinus Torvalds * An application uses sendmsg() and recvmsg() calls to transmit data to 15641da177e4SLinus Torvalds * and receive data from its peer. 15651da177e4SLinus Torvalds * 15661da177e4SLinus Torvalds * ssize_t sendmsg(int socket, const struct msghdr *message, 15671da177e4SLinus Torvalds * int flags); 15681da177e4SLinus Torvalds * 15691da177e4SLinus Torvalds * socket - the socket descriptor of the endpoint. 15701da177e4SLinus Torvalds * message - pointer to the msghdr structure which contains a single 15711da177e4SLinus Torvalds * user message and possibly some ancillary data. 15721da177e4SLinus Torvalds * 15731da177e4SLinus Torvalds * See Section 5 for complete description of the data 15741da177e4SLinus Torvalds * structures. 15751da177e4SLinus Torvalds * 15761da177e4SLinus Torvalds * flags - flags sent or received with the user message, see Section 15771da177e4SLinus Torvalds * 5 for complete description of the flags. 15781da177e4SLinus Torvalds * 15791da177e4SLinus Torvalds * Note: This function could use a rewrite especially when explicit 15801da177e4SLinus Torvalds * connect support comes in. 15811da177e4SLinus Torvalds */ 15821da177e4SLinus Torvalds /* BUG: We do not implement the equivalent of sk_stream_wait_memory(). */ 15831da177e4SLinus Torvalds 1584dda91928SDaniel Borkmann static int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *); 15851da177e4SLinus Torvalds 15861b784140SYing Xue static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) 15871da177e4SLinus Torvalds { 158855e26eb9SEric W. Biederman struct net *net = sock_net(sk); 15891da177e4SLinus Torvalds struct sctp_sock *sp; 15901da177e4SLinus Torvalds struct sctp_endpoint *ep; 15911da177e4SLinus Torvalds struct sctp_association *new_asoc = NULL, *asoc = NULL; 15921da177e4SLinus Torvalds struct sctp_transport *transport, *chunk_tp; 15931da177e4SLinus Torvalds struct sctp_chunk *chunk; 1594dce116aeSAl Viro union sctp_addr to; 15951da177e4SLinus Torvalds struct sockaddr *msg_name = NULL; 1596517aa0bcSJoe Perches struct sctp_sndrcvinfo default_sinfo; 15971da177e4SLinus Torvalds struct sctp_sndrcvinfo *sinfo; 15981da177e4SLinus Torvalds struct sctp_initmsg *sinit; 15991da177e4SLinus Torvalds sctp_assoc_t associd = 0; 16001da177e4SLinus Torvalds sctp_cmsgs_t cmsgs = { NULL }; 16011da177e4SLinus Torvalds sctp_scope_t scope; 16022061dcd6SDaniel Borkmann bool fill_sinfo_ttl = false, wait_connect = false; 16031da177e4SLinus Torvalds struct sctp_datamsg *datamsg; 16041da177e4SLinus Torvalds int msg_flags = msg->msg_flags; 160563b94938SGeir Ola Vaagland __u16 sinfo_flags = 0; 160663b94938SGeir Ola Vaagland long timeo; 160763b94938SGeir Ola Vaagland int err; 16081da177e4SLinus Torvalds 16091da177e4SLinus Torvalds err = 0; 16101da177e4SLinus Torvalds sp = sctp_sk(sk); 16111da177e4SLinus Torvalds ep = sp->ep; 16121da177e4SLinus Torvalds 1613bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, msg:%p, msg_len:%zu ep:%p\n", __func__, sk, 1614bb33381dSDaniel Borkmann msg, msg_len, ep); 16151da177e4SLinus Torvalds 16161da177e4SLinus Torvalds /* We cannot send a message over a TCP-style listening socket. */ 16171da177e4SLinus Torvalds if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) { 16181da177e4SLinus Torvalds err = -EPIPE; 16191da177e4SLinus Torvalds goto out_nounlock; 16201da177e4SLinus Torvalds } 16211da177e4SLinus Torvalds 16221da177e4SLinus Torvalds /* Parse out the SCTP CMSGs. */ 16231da177e4SLinus Torvalds err = sctp_msghdr_parse(msg, &cmsgs); 16241da177e4SLinus Torvalds if (err) { 1625bb33381dSDaniel Borkmann pr_debug("%s: msghdr parse err:%x\n", __func__, err); 16261da177e4SLinus Torvalds goto out_nounlock; 16271da177e4SLinus Torvalds } 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds /* Fetch the destination address for this packet. This 16301da177e4SLinus Torvalds * address only selects the association--it is not necessarily 16311da177e4SLinus Torvalds * the address we will send to. 16321da177e4SLinus Torvalds * For a peeled-off socket, msg_name is ignored. 16331da177e4SLinus Torvalds */ 16341da177e4SLinus Torvalds if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) { 16351da177e4SLinus Torvalds int msg_namelen = msg->msg_namelen; 16361da177e4SLinus Torvalds 16371da177e4SLinus Torvalds err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name, 16381da177e4SLinus Torvalds msg_namelen); 16391da177e4SLinus Torvalds if (err) 16401da177e4SLinus Torvalds return err; 16411da177e4SLinus Torvalds 16421da177e4SLinus Torvalds if (msg_namelen > sizeof(to)) 16431da177e4SLinus Torvalds msg_namelen = sizeof(to); 16441da177e4SLinus Torvalds memcpy(&to, msg->msg_name, msg_namelen); 16451da177e4SLinus Torvalds msg_name = msg->msg_name; 16461da177e4SLinus Torvalds } 16471da177e4SLinus Torvalds 16481da177e4SLinus Torvalds sinit = cmsgs.init; 164963b94938SGeir Ola Vaagland if (cmsgs.sinfo != NULL) { 165063b94938SGeir Ola Vaagland memset(&default_sinfo, 0, sizeof(default_sinfo)); 165163b94938SGeir Ola Vaagland default_sinfo.sinfo_stream = cmsgs.sinfo->snd_sid; 165263b94938SGeir Ola Vaagland default_sinfo.sinfo_flags = cmsgs.sinfo->snd_flags; 165363b94938SGeir Ola Vaagland default_sinfo.sinfo_ppid = cmsgs.sinfo->snd_ppid; 165463b94938SGeir Ola Vaagland default_sinfo.sinfo_context = cmsgs.sinfo->snd_context; 165563b94938SGeir Ola Vaagland default_sinfo.sinfo_assoc_id = cmsgs.sinfo->snd_assoc_id; 16561da177e4SLinus Torvalds 165763b94938SGeir Ola Vaagland sinfo = &default_sinfo; 165863b94938SGeir Ola Vaagland fill_sinfo_ttl = true; 165963b94938SGeir Ola Vaagland } else { 166063b94938SGeir Ola Vaagland sinfo = cmsgs.srinfo; 166163b94938SGeir Ola Vaagland } 166263b94938SGeir Ola Vaagland /* Did the user specify SNDINFO/SNDRCVINFO? */ 16631da177e4SLinus Torvalds if (sinfo) { 16641da177e4SLinus Torvalds sinfo_flags = sinfo->sinfo_flags; 16651da177e4SLinus Torvalds associd = sinfo->sinfo_assoc_id; 16661da177e4SLinus Torvalds } 16671da177e4SLinus Torvalds 1668bb33381dSDaniel Borkmann pr_debug("%s: msg_len:%zu, sinfo_flags:0x%x\n", __func__, 16691da177e4SLinus Torvalds msg_len, sinfo_flags); 16701da177e4SLinus Torvalds 1671eaa5c54dSIvan Skytte Jorgensen /* SCTP_EOF or SCTP_ABORT cannot be set on a TCP-style socket. */ 1672eaa5c54dSIvan Skytte Jorgensen if (sctp_style(sk, TCP) && (sinfo_flags & (SCTP_EOF | SCTP_ABORT))) { 16731da177e4SLinus Torvalds err = -EINVAL; 16741da177e4SLinus Torvalds goto out_nounlock; 16751da177e4SLinus Torvalds } 16761da177e4SLinus Torvalds 1677eaa5c54dSIvan Skytte Jorgensen /* If SCTP_EOF is set, no data can be sent. Disallow sending zero 1678eaa5c54dSIvan Skytte Jorgensen * length messages when SCTP_EOF|SCTP_ABORT is not set. 1679eaa5c54dSIvan Skytte Jorgensen * If SCTP_ABORT is set, the message length could be non zero with 16801da177e4SLinus Torvalds * the msg_iov set to the user abort reason. 16811da177e4SLinus Torvalds */ 1682eaa5c54dSIvan Skytte Jorgensen if (((sinfo_flags & SCTP_EOF) && (msg_len > 0)) || 1683eaa5c54dSIvan Skytte Jorgensen (!(sinfo_flags & (SCTP_EOF|SCTP_ABORT)) && (msg_len == 0))) { 16841da177e4SLinus Torvalds err = -EINVAL; 16851da177e4SLinus Torvalds goto out_nounlock; 16861da177e4SLinus Torvalds } 16871da177e4SLinus Torvalds 1688eaa5c54dSIvan Skytte Jorgensen /* If SCTP_ADDR_OVER is set, there must be an address 16891da177e4SLinus Torvalds * specified in msg_name. 16901da177e4SLinus Torvalds */ 1691eaa5c54dSIvan Skytte Jorgensen if ((sinfo_flags & SCTP_ADDR_OVER) && (!msg->msg_name)) { 16921da177e4SLinus Torvalds err = -EINVAL; 16931da177e4SLinus Torvalds goto out_nounlock; 16941da177e4SLinus Torvalds } 16951da177e4SLinus Torvalds 16961da177e4SLinus Torvalds transport = NULL; 16971da177e4SLinus Torvalds 1698bb33381dSDaniel Borkmann pr_debug("%s: about to look up association\n", __func__); 16991da177e4SLinus Torvalds 1700048ed4b6Swangweidong lock_sock(sk); 17011da177e4SLinus Torvalds 17021da177e4SLinus Torvalds /* If a msg_name has been specified, assume this is to be used. */ 17031da177e4SLinus Torvalds if (msg_name) { 17041da177e4SLinus Torvalds /* Look for a matching association on the endpoint. */ 1705dce116aeSAl Viro asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); 17061da177e4SLinus Torvalds if (!asoc) { 17071da177e4SLinus Torvalds /* If we could not find a matching association on the 17081da177e4SLinus Torvalds * endpoint, make sure that it is not a TCP-style 17091da177e4SLinus Torvalds * socket that already has an association or there is 17101da177e4SLinus Torvalds * no peeled-off association on another socket. 17111da177e4SLinus Torvalds */ 17121da177e4SLinus Torvalds if ((sctp_style(sk, TCP) && 17131da177e4SLinus Torvalds sctp_sstate(sk, ESTABLISHED)) || 1714dce116aeSAl Viro sctp_endpoint_is_peeled_off(ep, &to)) { 17151da177e4SLinus Torvalds err = -EADDRNOTAVAIL; 17161da177e4SLinus Torvalds goto out_unlock; 17171da177e4SLinus Torvalds } 17181da177e4SLinus Torvalds } 17191da177e4SLinus Torvalds } else { 17201da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, associd); 17211da177e4SLinus Torvalds if (!asoc) { 17221da177e4SLinus Torvalds err = -EPIPE; 17231da177e4SLinus Torvalds goto out_unlock; 17241da177e4SLinus Torvalds } 17251da177e4SLinus Torvalds } 17261da177e4SLinus Torvalds 17271da177e4SLinus Torvalds if (asoc) { 1728bb33381dSDaniel Borkmann pr_debug("%s: just looked up association:%p\n", __func__, asoc); 17291da177e4SLinus Torvalds 17301da177e4SLinus Torvalds /* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED 17311da177e4SLinus Torvalds * socket that has an association in CLOSED state. This can 17321da177e4SLinus Torvalds * happen when an accepted socket has an association that is 17331da177e4SLinus Torvalds * already CLOSED. 17341da177e4SLinus Torvalds */ 17351da177e4SLinus Torvalds if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) { 17361da177e4SLinus Torvalds err = -EPIPE; 17371da177e4SLinus Torvalds goto out_unlock; 17381da177e4SLinus Torvalds } 17391da177e4SLinus Torvalds 1740eaa5c54dSIvan Skytte Jorgensen if (sinfo_flags & SCTP_EOF) { 1741bb33381dSDaniel Borkmann pr_debug("%s: shutting down association:%p\n", 1742bb33381dSDaniel Borkmann __func__, asoc); 1743bb33381dSDaniel Borkmann 174455e26eb9SEric W. Biederman sctp_primitive_SHUTDOWN(net, asoc, NULL); 17451da177e4SLinus Torvalds err = 0; 17461da177e4SLinus Torvalds goto out_unlock; 17471da177e4SLinus Torvalds } 1748eaa5c54dSIvan Skytte Jorgensen if (sinfo_flags & SCTP_ABORT) { 1749c164a9baSSridhar Samudrala 1750c164a9baSSridhar Samudrala chunk = sctp_make_abort_user(asoc, msg, msg_len); 1751c164a9baSSridhar Samudrala if (!chunk) { 1752c164a9baSSridhar Samudrala err = -ENOMEM; 1753c164a9baSSridhar Samudrala goto out_unlock; 1754c164a9baSSridhar Samudrala } 1755c164a9baSSridhar Samudrala 1756bb33381dSDaniel Borkmann pr_debug("%s: aborting association:%p\n", 1757bb33381dSDaniel Borkmann __func__, asoc); 1758bb33381dSDaniel Borkmann 175955e26eb9SEric W. Biederman sctp_primitive_ABORT(net, asoc, chunk); 17601da177e4SLinus Torvalds err = 0; 17611da177e4SLinus Torvalds goto out_unlock; 17621da177e4SLinus Torvalds } 17631da177e4SLinus Torvalds } 17641da177e4SLinus Torvalds 17651da177e4SLinus Torvalds /* Do we need to create the association? */ 17661da177e4SLinus Torvalds if (!asoc) { 1767bb33381dSDaniel Borkmann pr_debug("%s: there is no association yet\n", __func__); 17681da177e4SLinus Torvalds 1769eaa5c54dSIvan Skytte Jorgensen if (sinfo_flags & (SCTP_EOF | SCTP_ABORT)) { 17701da177e4SLinus Torvalds err = -EINVAL; 17711da177e4SLinus Torvalds goto out_unlock; 17721da177e4SLinus Torvalds } 17731da177e4SLinus Torvalds 17741da177e4SLinus Torvalds /* Check for invalid stream against the stream counts, 17751da177e4SLinus Torvalds * either the default or the user specified stream counts. 17761da177e4SLinus Torvalds */ 17771da177e4SLinus Torvalds if (sinfo) { 17780e864b21SDan Carpenter if (!sinit || !sinit->sinit_num_ostreams) { 17791da177e4SLinus Torvalds /* Check against the defaults. */ 17801da177e4SLinus Torvalds if (sinfo->sinfo_stream >= 17811da177e4SLinus Torvalds sp->initmsg.sinit_num_ostreams) { 17821da177e4SLinus Torvalds err = -EINVAL; 17831da177e4SLinus Torvalds goto out_unlock; 17841da177e4SLinus Torvalds } 17851da177e4SLinus Torvalds } else { 17861da177e4SLinus Torvalds /* Check against the requested. */ 17871da177e4SLinus Torvalds if (sinfo->sinfo_stream >= 17881da177e4SLinus Torvalds sinit->sinit_num_ostreams) { 17891da177e4SLinus Torvalds err = -EINVAL; 17901da177e4SLinus Torvalds goto out_unlock; 17911da177e4SLinus Torvalds } 17921da177e4SLinus Torvalds } 17931da177e4SLinus Torvalds } 17941da177e4SLinus Torvalds 17951da177e4SLinus Torvalds /* 17961da177e4SLinus Torvalds * API 3.1.2 bind() - UDP Style Syntax 17971da177e4SLinus Torvalds * If a bind() or sctp_bindx() is not called prior to a 17981da177e4SLinus Torvalds * sendmsg() call that initiates a new association, the 17991da177e4SLinus Torvalds * system picks an ephemeral port and will choose an address 18001da177e4SLinus Torvalds * set equivalent to binding with a wildcard address. 18011da177e4SLinus Torvalds */ 18021da177e4SLinus Torvalds if (!ep->base.bind_addr.port) { 18031da177e4SLinus Torvalds if (sctp_autobind(sk)) { 18041da177e4SLinus Torvalds err = -EAGAIN; 18051da177e4SLinus Torvalds goto out_unlock; 18061da177e4SLinus Torvalds } 180764a0c1c8SIvan Skytte Jorgensen } else { 180864a0c1c8SIvan Skytte Jorgensen /* 180964a0c1c8SIvan Skytte Jorgensen * If an unprivileged user inherits a one-to-many 181064a0c1c8SIvan Skytte Jorgensen * style socket with open associations on a privileged 181164a0c1c8SIvan Skytte Jorgensen * port, it MAY be permitted to accept new associations, 181264a0c1c8SIvan Skytte Jorgensen * but it SHOULD NOT be permitted to open new 181364a0c1c8SIvan Skytte Jorgensen * associations. 181464a0c1c8SIvan Skytte Jorgensen */ 181564a0c1c8SIvan Skytte Jorgensen if (ep->base.bind_addr.port < PROT_SOCK && 18163594698aSEric W. Biederman !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { 181764a0c1c8SIvan Skytte Jorgensen err = -EACCES; 181864a0c1c8SIvan Skytte Jorgensen goto out_unlock; 181964a0c1c8SIvan Skytte Jorgensen } 18201da177e4SLinus Torvalds } 18211da177e4SLinus Torvalds 18221da177e4SLinus Torvalds scope = sctp_scope(&to); 18231da177e4SLinus Torvalds new_asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); 18241da177e4SLinus Torvalds if (!new_asoc) { 18251da177e4SLinus Torvalds err = -ENOMEM; 18261da177e4SLinus Torvalds goto out_unlock; 18271da177e4SLinus Torvalds } 18281da177e4SLinus Torvalds asoc = new_asoc; 1829409b95afSVlad Yasevich err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL); 1830409b95afSVlad Yasevich if (err < 0) { 1831409b95afSVlad Yasevich err = -ENOMEM; 1832409b95afSVlad Yasevich goto out_free; 1833409b95afSVlad Yasevich } 18341da177e4SLinus Torvalds 18351da177e4SLinus Torvalds /* If the SCTP_INIT ancillary data is specified, set all 18361da177e4SLinus Torvalds * the association init values accordingly. 18371da177e4SLinus Torvalds */ 18381da177e4SLinus Torvalds if (sinit) { 18391da177e4SLinus Torvalds if (sinit->sinit_num_ostreams) { 18401da177e4SLinus Torvalds asoc->c.sinit_num_ostreams = 18411da177e4SLinus Torvalds sinit->sinit_num_ostreams; 18421da177e4SLinus Torvalds } 18431da177e4SLinus Torvalds if (sinit->sinit_max_instreams) { 18441da177e4SLinus Torvalds asoc->c.sinit_max_instreams = 18451da177e4SLinus Torvalds sinit->sinit_max_instreams; 18461da177e4SLinus Torvalds } 18471da177e4SLinus Torvalds if (sinit->sinit_max_attempts) { 18481da177e4SLinus Torvalds asoc->max_init_attempts 18491da177e4SLinus Torvalds = sinit->sinit_max_attempts; 18501da177e4SLinus Torvalds } 18511da177e4SLinus Torvalds if (sinit->sinit_max_init_timeo) { 18521da177e4SLinus Torvalds asoc->max_init_timeo = 18531da177e4SLinus Torvalds msecs_to_jiffies(sinit->sinit_max_init_timeo); 18541da177e4SLinus Torvalds } 18551da177e4SLinus Torvalds } 18561da177e4SLinus Torvalds 18571da177e4SLinus Torvalds /* Prime the peer's transport structures. */ 1858dce116aeSAl Viro transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, SCTP_UNKNOWN); 18591da177e4SLinus Torvalds if (!transport) { 18601da177e4SLinus Torvalds err = -ENOMEM; 18611da177e4SLinus Torvalds goto out_free; 18621da177e4SLinus Torvalds } 18631da177e4SLinus Torvalds } 18641da177e4SLinus Torvalds 18651da177e4SLinus Torvalds /* ASSERT: we have a valid association at this point. */ 1866bb33381dSDaniel Borkmann pr_debug("%s: we have a valid association\n", __func__); 18671da177e4SLinus Torvalds 18681da177e4SLinus Torvalds if (!sinfo) { 186963b94938SGeir Ola Vaagland /* If the user didn't specify SNDINFO/SNDRCVINFO, make up 187063b94938SGeir Ola Vaagland * one with some defaults. 18711da177e4SLinus Torvalds */ 1872517aa0bcSJoe Perches memset(&default_sinfo, 0, sizeof(default_sinfo)); 18731da177e4SLinus Torvalds default_sinfo.sinfo_stream = asoc->default_stream; 18741da177e4SLinus Torvalds default_sinfo.sinfo_flags = asoc->default_flags; 18751da177e4SLinus Torvalds default_sinfo.sinfo_ppid = asoc->default_ppid; 18761da177e4SLinus Torvalds default_sinfo.sinfo_context = asoc->default_context; 18771da177e4SLinus Torvalds default_sinfo.sinfo_timetolive = asoc->default_timetolive; 18781da177e4SLinus Torvalds default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); 187963b94938SGeir Ola Vaagland 18801da177e4SLinus Torvalds sinfo = &default_sinfo; 188163b94938SGeir Ola Vaagland } else if (fill_sinfo_ttl) { 188263b94938SGeir Ola Vaagland /* In case SNDINFO was specified, we still need to fill 188363b94938SGeir Ola Vaagland * it with a default ttl from the assoc here. 188463b94938SGeir Ola Vaagland */ 188563b94938SGeir Ola Vaagland sinfo->sinfo_timetolive = asoc->default_timetolive; 18861da177e4SLinus Torvalds } 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds /* API 7.1.7, the sndbuf size per association bounds the 18891da177e4SLinus Torvalds * maximum size of data that can be sent in a single send call. 18901da177e4SLinus Torvalds */ 18911da177e4SLinus Torvalds if (msg_len > sk->sk_sndbuf) { 18921da177e4SLinus Torvalds err = -EMSGSIZE; 18931da177e4SLinus Torvalds goto out_free; 18941da177e4SLinus Torvalds } 18951da177e4SLinus Torvalds 18968a479491SVlad Yasevich if (asoc->pmtu_pending) 189702f3d4ceSDavid S. Miller sctp_assoc_pending_pmtu(sk, asoc); 18988a479491SVlad Yasevich 18991da177e4SLinus Torvalds /* If fragmentation is disabled and the message length exceeds the 19001da177e4SLinus Torvalds * association fragmentation point, return EMSGSIZE. The I-D 19011da177e4SLinus Torvalds * does not specify what this error is, but this looks like 19021da177e4SLinus Torvalds * a great fit. 19031da177e4SLinus Torvalds */ 19041da177e4SLinus Torvalds if (sctp_sk(sk)->disable_fragments && (msg_len > asoc->frag_point)) { 19051da177e4SLinus Torvalds err = -EMSGSIZE; 19061da177e4SLinus Torvalds goto out_free; 19071da177e4SLinus Torvalds } 19081da177e4SLinus Torvalds 19091da177e4SLinus Torvalds /* Check for invalid stream. */ 19101da177e4SLinus Torvalds if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { 19111da177e4SLinus Torvalds err = -EINVAL; 19121da177e4SLinus Torvalds goto out_free; 19131da177e4SLinus Torvalds } 19141da177e4SLinus Torvalds 19151da177e4SLinus Torvalds timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 19161da177e4SLinus Torvalds if (!sctp_wspace(asoc)) { 19171da177e4SLinus Torvalds err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); 19181da177e4SLinus Torvalds if (err) 19191da177e4SLinus Torvalds goto out_free; 19201da177e4SLinus Torvalds } 19211da177e4SLinus Torvalds 19221da177e4SLinus Torvalds /* If an address is passed with the sendto/sendmsg call, it is used 19231da177e4SLinus Torvalds * to override the primary destination address in the TCP model, or 1924eaa5c54dSIvan Skytte Jorgensen * when SCTP_ADDR_OVER flag is set in the UDP model. 19251da177e4SLinus Torvalds */ 19261da177e4SLinus Torvalds if ((sctp_style(sk, TCP) && msg_name) || 1927eaa5c54dSIvan Skytte Jorgensen (sinfo_flags & SCTP_ADDR_OVER)) { 1928dce116aeSAl Viro chunk_tp = sctp_assoc_lookup_paddr(asoc, &to); 19291da177e4SLinus Torvalds if (!chunk_tp) { 19301da177e4SLinus Torvalds err = -EINVAL; 19311da177e4SLinus Torvalds goto out_free; 19321da177e4SLinus Torvalds } 19331da177e4SLinus Torvalds } else 19341da177e4SLinus Torvalds chunk_tp = NULL; 19351da177e4SLinus Torvalds 19361da177e4SLinus Torvalds /* Auto-connect, if we aren't connected already. */ 19371da177e4SLinus Torvalds if (sctp_state(asoc, CLOSED)) { 193855e26eb9SEric W. Biederman err = sctp_primitive_ASSOCIATE(net, asoc, NULL); 19391da177e4SLinus Torvalds if (err < 0) 19401da177e4SLinus Torvalds goto out_free; 1941bb33381dSDaniel Borkmann 19422061dcd6SDaniel Borkmann wait_connect = true; 1943bb33381dSDaniel Borkmann pr_debug("%s: we associated primitively\n", __func__); 19441da177e4SLinus Torvalds } 19451da177e4SLinus Torvalds 19461da177e4SLinus Torvalds /* Break the message into multiple chunks of maximum size. */ 1947c0371da6SAl Viro datamsg = sctp_datamsg_from_user(asoc, sinfo, &msg->msg_iter); 19486e51fe75STommi Rantala if (IS_ERR(datamsg)) { 19496e51fe75STommi Rantala err = PTR_ERR(datamsg); 19501da177e4SLinus Torvalds goto out_free; 19511da177e4SLinus Torvalds } 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvalds /* Now send the (possibly) fragmented message. */ 19549dbc15f0SRobert P. J. Day list_for_each_entry(chunk, &datamsg->chunks, frag_list) { 195580445cfbSFlorian Westphal sctp_chunk_hold(chunk); 19561da177e4SLinus Torvalds 19571da177e4SLinus Torvalds /* Do accounting for the write space. */ 19581da177e4SLinus Torvalds sctp_set_owner_w(chunk); 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds chunk->transport = chunk_tp; 19619c5c62beSVlad Yasevich } 19621da177e4SLinus Torvalds 19631da177e4SLinus Torvalds /* Send it to the lower layers. Note: all chunks 19641da177e4SLinus Torvalds * must either fail or succeed. The lower layer 19651da177e4SLinus Torvalds * works that way today. Keep it that way or this 19661da177e4SLinus Torvalds * breaks. 19671da177e4SLinus Torvalds */ 196855e26eb9SEric W. Biederman err = sctp_primitive_SEND(net, asoc, datamsg); 19691da177e4SLinus Torvalds /* Did the lower layer accept the chunk? */ 1970bb33381dSDaniel Borkmann if (err) { 19719c5c62beSVlad Yasevich sctp_datamsg_free(datamsg); 19721da177e4SLinus Torvalds goto out_free; 1973bb33381dSDaniel Borkmann } 1974bb33381dSDaniel Borkmann 1975bb33381dSDaniel Borkmann pr_debug("%s: we sent primitively\n", __func__); 1976bb33381dSDaniel Borkmann 1977bb33381dSDaniel Borkmann sctp_datamsg_put(datamsg); 19781da177e4SLinus Torvalds err = msg_len; 19791da177e4SLinus Torvalds 19802061dcd6SDaniel Borkmann if (unlikely(wait_connect)) { 19812061dcd6SDaniel Borkmann timeo = sock_sndtimeo(sk, msg_flags & MSG_DONTWAIT); 19822061dcd6SDaniel Borkmann sctp_wait_for_connect(asoc, &timeo); 19832061dcd6SDaniel Borkmann } 19842061dcd6SDaniel Borkmann 19851da177e4SLinus Torvalds /* If we are already past ASSOCIATE, the lower 19861da177e4SLinus Torvalds * layers are responsible for association cleanup. 19871da177e4SLinus Torvalds */ 19881da177e4SLinus Torvalds goto out_unlock; 19891da177e4SLinus Torvalds 19901da177e4SLinus Torvalds out_free: 19912eebc1e1SNeil Horman if (new_asoc) { 19922eebc1e1SNeil Horman sctp_unhash_established(asoc); 19931da177e4SLinus Torvalds sctp_association_free(asoc); 19942eebc1e1SNeil Horman } 19951da177e4SLinus Torvalds out_unlock: 1996048ed4b6Swangweidong release_sock(sk); 19971da177e4SLinus Torvalds 19981da177e4SLinus Torvalds out_nounlock: 19991da177e4SLinus Torvalds return sctp_error(sk, msg_flags, err); 20001da177e4SLinus Torvalds 20011da177e4SLinus Torvalds #if 0 20021da177e4SLinus Torvalds do_sock_err: 20031da177e4SLinus Torvalds if (msg_len) 20041da177e4SLinus Torvalds err = msg_len; 20051da177e4SLinus Torvalds else 20061da177e4SLinus Torvalds err = sock_error(sk); 20071da177e4SLinus Torvalds goto out; 20081da177e4SLinus Torvalds 20091da177e4SLinus Torvalds do_interrupted: 20101da177e4SLinus Torvalds if (msg_len) 20111da177e4SLinus Torvalds err = msg_len; 20121da177e4SLinus Torvalds goto out; 20131da177e4SLinus Torvalds #endif /* 0 */ 20141da177e4SLinus Torvalds } 20151da177e4SLinus Torvalds 20161da177e4SLinus Torvalds /* This is an extended version of skb_pull() that removes the data from the 20171da177e4SLinus Torvalds * start of a skb even when data is spread across the list of skb's in the 20181da177e4SLinus Torvalds * frag_list. len specifies the total amount of data that needs to be removed. 20191da177e4SLinus Torvalds * when 'len' bytes could be removed from the skb, it returns 0. 20201da177e4SLinus Torvalds * If 'len' exceeds the total skb length, it returns the no. of bytes that 20211da177e4SLinus Torvalds * could not be removed. 20221da177e4SLinus Torvalds */ 20231da177e4SLinus Torvalds static int sctp_skb_pull(struct sk_buff *skb, int len) 20241da177e4SLinus Torvalds { 20251da177e4SLinus Torvalds struct sk_buff *list; 20261da177e4SLinus Torvalds int skb_len = skb_headlen(skb); 20271da177e4SLinus Torvalds int rlen; 20281da177e4SLinus Torvalds 20291da177e4SLinus Torvalds if (len <= skb_len) { 20301da177e4SLinus Torvalds __skb_pull(skb, len); 20311da177e4SLinus Torvalds return 0; 20321da177e4SLinus Torvalds } 20331da177e4SLinus Torvalds len -= skb_len; 20341da177e4SLinus Torvalds __skb_pull(skb, skb_len); 20351da177e4SLinus Torvalds 20361b003be3SDavid S. Miller skb_walk_frags(skb, list) { 20371da177e4SLinus Torvalds rlen = sctp_skb_pull(list, len); 20381da177e4SLinus Torvalds skb->len -= (len-rlen); 20391da177e4SLinus Torvalds skb->data_len -= (len-rlen); 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds if (!rlen) 20421da177e4SLinus Torvalds return 0; 20431da177e4SLinus Torvalds 20441da177e4SLinus Torvalds len = rlen; 20451da177e4SLinus Torvalds } 20461da177e4SLinus Torvalds 20471da177e4SLinus Torvalds return len; 20481da177e4SLinus Torvalds } 20491da177e4SLinus Torvalds 20501da177e4SLinus Torvalds /* API 3.1.3 recvmsg() - UDP Style Syntax 20511da177e4SLinus Torvalds * 20521da177e4SLinus Torvalds * ssize_t recvmsg(int socket, struct msghdr *message, 20531da177e4SLinus Torvalds * int flags); 20541da177e4SLinus Torvalds * 20551da177e4SLinus Torvalds * socket - the socket descriptor of the endpoint. 20561da177e4SLinus Torvalds * message - pointer to the msghdr structure which contains a single 20571da177e4SLinus Torvalds * user message and possibly some ancillary data. 20581da177e4SLinus Torvalds * 20591da177e4SLinus Torvalds * See Section 5 for complete description of the data 20601da177e4SLinus Torvalds * structures. 20611da177e4SLinus Torvalds * 20621da177e4SLinus Torvalds * flags - flags sent or received with the user message, see Section 20631da177e4SLinus Torvalds * 5 for complete description of the flags. 20641da177e4SLinus Torvalds */ 20651b784140SYing Xue static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 20661b784140SYing Xue int noblock, int flags, int *addr_len) 20671da177e4SLinus Torvalds { 20681da177e4SLinus Torvalds struct sctp_ulpevent *event = NULL; 20691da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 20701da177e4SLinus Torvalds struct sk_buff *skb; 20711da177e4SLinus Torvalds int copied; 20721da177e4SLinus Torvalds int err = 0; 20731da177e4SLinus Torvalds int skb_len; 20741da177e4SLinus Torvalds 2075bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, msghdr:%p, len:%zd, noblock:%d, flags:0x%x, " 2076bb33381dSDaniel Borkmann "addr_len:%p)\n", __func__, sk, msg, len, noblock, flags, 2077bb33381dSDaniel Borkmann addr_len); 20781da177e4SLinus Torvalds 2079048ed4b6Swangweidong lock_sock(sk); 20801da177e4SLinus Torvalds 20811da177e4SLinus Torvalds if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) { 20821da177e4SLinus Torvalds err = -ENOTCONN; 20831da177e4SLinus Torvalds goto out; 20841da177e4SLinus Torvalds } 20851da177e4SLinus Torvalds 20861da177e4SLinus Torvalds skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); 20871da177e4SLinus Torvalds if (!skb) 20881da177e4SLinus Torvalds goto out; 20891da177e4SLinus Torvalds 20901da177e4SLinus Torvalds /* Get the total length of the skb including any skb's in the 20911da177e4SLinus Torvalds * frag_list. 20921da177e4SLinus Torvalds */ 20931da177e4SLinus Torvalds skb_len = skb->len; 20941da177e4SLinus Torvalds 20951da177e4SLinus Torvalds copied = skb_len; 20961da177e4SLinus Torvalds if (copied > len) 20971da177e4SLinus Torvalds copied = len; 20981da177e4SLinus Torvalds 209951f3d02bSDavid S. Miller err = skb_copy_datagram_msg(skb, 0, msg, copied); 21001da177e4SLinus Torvalds 21011da177e4SLinus Torvalds event = sctp_skb2event(skb); 21021da177e4SLinus Torvalds 21031da177e4SLinus Torvalds if (err) 21041da177e4SLinus Torvalds goto out_free; 21051da177e4SLinus Torvalds 21063b885787SNeil Horman sock_recv_ts_and_drops(msg, sk, skb); 21071da177e4SLinus Torvalds if (sctp_ulpevent_is_notification(event)) { 21081da177e4SLinus Torvalds msg->msg_flags |= MSG_NOTIFICATION; 21091da177e4SLinus Torvalds sp->pf->event_msgname(event, msg->msg_name, addr_len); 21101da177e4SLinus Torvalds } else { 21111da177e4SLinus Torvalds sp->pf->skb_msgname(skb, msg->msg_name, addr_len); 21121da177e4SLinus Torvalds } 21131da177e4SLinus Torvalds 21142347c80fSGeir Ola Vaagland /* Check if we allow SCTP_NXTINFO. */ 21152347c80fSGeir Ola Vaagland if (sp->recvnxtinfo) 21162347c80fSGeir Ola Vaagland sctp_ulpevent_read_nxtinfo(event, msg, sk); 21170d3a421dSGeir Ola Vaagland /* Check if we allow SCTP_RCVINFO. */ 21180d3a421dSGeir Ola Vaagland if (sp->recvrcvinfo) 21190d3a421dSGeir Ola Vaagland sctp_ulpevent_read_rcvinfo(event, msg); 21201da177e4SLinus Torvalds /* Check if we allow SCTP_SNDRCVINFO. */ 21211da177e4SLinus Torvalds if (sp->subscribe.sctp_data_io_event) 21221da177e4SLinus Torvalds sctp_ulpevent_read_sndrcvinfo(event, msg); 21230d3a421dSGeir Ola Vaagland 21241da177e4SLinus Torvalds err = copied; 21251da177e4SLinus Torvalds 21261da177e4SLinus Torvalds /* If skb's length exceeds the user's buffer, update the skb and 21271da177e4SLinus Torvalds * push it back to the receive_queue so that the next call to 21281da177e4SLinus Torvalds * recvmsg() will return the remaining data. Don't set MSG_EOR. 21291da177e4SLinus Torvalds */ 21301da177e4SLinus Torvalds if (skb_len > copied) { 21311da177e4SLinus Torvalds msg->msg_flags &= ~MSG_EOR; 21321da177e4SLinus Torvalds if (flags & MSG_PEEK) 21331da177e4SLinus Torvalds goto out_free; 21341da177e4SLinus Torvalds sctp_skb_pull(skb, copied); 21351da177e4SLinus Torvalds skb_queue_head(&sk->sk_receive_queue, skb); 21361da177e4SLinus Torvalds 2137362d5204SDaniel Borkmann /* When only partial message is copied to the user, increase 2138362d5204SDaniel Borkmann * rwnd by that amount. If all the data in the skb is read, 2139362d5204SDaniel Borkmann * rwnd is updated when the event is freed. 2140362d5204SDaniel Borkmann */ 2141362d5204SDaniel Borkmann if (!sctp_ulpevent_is_notification(event)) 2142362d5204SDaniel Borkmann sctp_assoc_rwnd_increase(event->asoc, copied); 21431da177e4SLinus Torvalds goto out; 21441da177e4SLinus Torvalds } else if ((event->msg_flags & MSG_NOTIFICATION) || 21451da177e4SLinus Torvalds (event->msg_flags & MSG_EOR)) 21461da177e4SLinus Torvalds msg->msg_flags |= MSG_EOR; 21471da177e4SLinus Torvalds else 21481da177e4SLinus Torvalds msg->msg_flags &= ~MSG_EOR; 21491da177e4SLinus Torvalds 21501da177e4SLinus Torvalds out_free: 21511da177e4SLinus Torvalds if (flags & MSG_PEEK) { 21521da177e4SLinus Torvalds /* Release the skb reference acquired after peeking the skb in 21531da177e4SLinus Torvalds * sctp_skb_recv_datagram(). 21541da177e4SLinus Torvalds */ 21551da177e4SLinus Torvalds kfree_skb(skb); 21561da177e4SLinus Torvalds } else { 21571da177e4SLinus Torvalds /* Free the event which includes releasing the reference to 21581da177e4SLinus Torvalds * the owner of the skb, freeing the skb and updating the 21591da177e4SLinus Torvalds * rwnd. 21601da177e4SLinus Torvalds */ 21611da177e4SLinus Torvalds sctp_ulpevent_free(event); 21621da177e4SLinus Torvalds } 21631da177e4SLinus Torvalds out: 2164048ed4b6Swangweidong release_sock(sk); 21651da177e4SLinus Torvalds return err; 21661da177e4SLinus Torvalds } 21671da177e4SLinus Torvalds 21681da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) 21691da177e4SLinus Torvalds * 21701da177e4SLinus Torvalds * This option is a on/off flag. If enabled no SCTP message 21711da177e4SLinus Torvalds * fragmentation will be performed. Instead if a message being sent 21721da177e4SLinus Torvalds * exceeds the current PMTU size, the message will NOT be sent and 21731da177e4SLinus Torvalds * instead a error will be indicated to the user. 21741da177e4SLinus Torvalds */ 21751da177e4SLinus Torvalds static int sctp_setsockopt_disable_fragments(struct sock *sk, 2176b7058842SDavid S. Miller char __user *optval, 2177b7058842SDavid S. Miller unsigned int optlen) 21781da177e4SLinus Torvalds { 21791da177e4SLinus Torvalds int val; 21801da177e4SLinus Torvalds 21811da177e4SLinus Torvalds if (optlen < sizeof(int)) 21821da177e4SLinus Torvalds return -EINVAL; 21831da177e4SLinus Torvalds 21841da177e4SLinus Torvalds if (get_user(val, (int __user *)optval)) 21851da177e4SLinus Torvalds return -EFAULT; 21861da177e4SLinus Torvalds 21871da177e4SLinus Torvalds sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1; 21881da177e4SLinus Torvalds 21891da177e4SLinus Torvalds return 0; 21901da177e4SLinus Torvalds } 21911da177e4SLinus Torvalds 21921da177e4SLinus Torvalds static int sctp_setsockopt_events(struct sock *sk, char __user *optval, 2193b7058842SDavid S. Miller unsigned int optlen) 21941da177e4SLinus Torvalds { 219594912301SWei Yongjun struct sctp_association *asoc; 219694912301SWei Yongjun struct sctp_ulpevent *event; 219794912301SWei Yongjun 21987e8616d8SVlad Yasevich if (optlen > sizeof(struct sctp_event_subscribe)) 21991da177e4SLinus Torvalds return -EINVAL; 22001da177e4SLinus Torvalds if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) 22011da177e4SLinus Torvalds return -EFAULT; 220294912301SWei Yongjun 2203bbbea41dSDaniel Borkmann /* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, 220494912301SWei Yongjun * if there is no data to be sent or retransmit, the stack will 220594912301SWei Yongjun * immediately send up this notification. 220694912301SWei Yongjun */ 220794912301SWei Yongjun if (sctp_ulpevent_type_enabled(SCTP_SENDER_DRY_EVENT, 220894912301SWei Yongjun &sctp_sk(sk)->subscribe)) { 220994912301SWei Yongjun asoc = sctp_id2assoc(sk, 0); 221094912301SWei Yongjun 221194912301SWei Yongjun if (asoc && sctp_outq_is_empty(&asoc->outqueue)) { 221294912301SWei Yongjun event = sctp_ulpevent_make_sender_dry_event(asoc, 221394912301SWei Yongjun GFP_ATOMIC); 221494912301SWei Yongjun if (!event) 221594912301SWei Yongjun return -ENOMEM; 221694912301SWei Yongjun 221794912301SWei Yongjun sctp_ulpq_tail_event(&asoc->ulpq, event); 221894912301SWei Yongjun } 221994912301SWei Yongjun } 222094912301SWei Yongjun 22211da177e4SLinus Torvalds return 0; 22221da177e4SLinus Torvalds } 22231da177e4SLinus Torvalds 22241da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) 22251da177e4SLinus Torvalds * 22261da177e4SLinus Torvalds * This socket option is applicable to the UDP-style socket only. When 22271da177e4SLinus Torvalds * set it will cause associations that are idle for more than the 22281da177e4SLinus Torvalds * specified number of seconds to automatically close. An association 22291da177e4SLinus Torvalds * being idle is defined an association that has NOT sent or received 22301da177e4SLinus Torvalds * user data. The special value of '0' indicates that no automatic 22311da177e4SLinus Torvalds * close of any associations should be performed. The option expects an 22321da177e4SLinus Torvalds * integer defining the number of seconds of idle time before an 22331da177e4SLinus Torvalds * association is closed. 22341da177e4SLinus Torvalds */ 22351da177e4SLinus Torvalds static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, 2236b7058842SDavid S. Miller unsigned int optlen) 22371da177e4SLinus Torvalds { 22381da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 22399f70f46bSNeil Horman struct net *net = sock_net(sk); 22401da177e4SLinus Torvalds 22411da177e4SLinus Torvalds /* Applicable to UDP-style socket only */ 22421da177e4SLinus Torvalds if (sctp_style(sk, TCP)) 22431da177e4SLinus Torvalds return -EOPNOTSUPP; 22441da177e4SLinus Torvalds if (optlen != sizeof(int)) 22451da177e4SLinus Torvalds return -EINVAL; 22461da177e4SLinus Torvalds if (copy_from_user(&sp->autoclose, optval, optlen)) 22471da177e4SLinus Torvalds return -EFAULT; 22481da177e4SLinus Torvalds 22499f70f46bSNeil Horman if (sp->autoclose > net->sctp.max_autoclose) 22509f70f46bSNeil Horman sp->autoclose = net->sctp.max_autoclose; 22519f70f46bSNeil Horman 22521da177e4SLinus Torvalds return 0; 22531da177e4SLinus Torvalds } 22541da177e4SLinus Torvalds 22551da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) 22561da177e4SLinus Torvalds * 22571da177e4SLinus Torvalds * Applications can enable or disable heartbeats for any peer address of 22581da177e4SLinus Torvalds * an association, modify an address's heartbeat interval, force a 22591da177e4SLinus Torvalds * heartbeat to be sent immediately, and adjust the address's maximum 22601da177e4SLinus Torvalds * number of retransmissions sent before an address is considered 22611da177e4SLinus Torvalds * unreachable. The following structure is used to access and modify an 22621da177e4SLinus Torvalds * address's parameters: 22631da177e4SLinus Torvalds * 22641da177e4SLinus Torvalds * struct sctp_paddrparams { 22651da177e4SLinus Torvalds * sctp_assoc_t spp_assoc_id; 22661da177e4SLinus Torvalds * struct sockaddr_storage spp_address; 22671da177e4SLinus Torvalds * uint32_t spp_hbinterval; 22681da177e4SLinus Torvalds * uint16_t spp_pathmaxrxt; 226952ccb8e9SFrank Filz * uint32_t spp_pathmtu; 227052ccb8e9SFrank Filz * uint32_t spp_sackdelay; 227152ccb8e9SFrank Filz * uint32_t spp_flags; 22721da177e4SLinus Torvalds * }; 22731da177e4SLinus Torvalds * 227452ccb8e9SFrank Filz * spp_assoc_id - (one-to-many style socket) This is filled in the 227552ccb8e9SFrank Filz * application, and identifies the association for 227652ccb8e9SFrank Filz * this query. 22771da177e4SLinus Torvalds * spp_address - This specifies which address is of interest. 22781da177e4SLinus Torvalds * spp_hbinterval - This contains the value of the heartbeat interval, 227952ccb8e9SFrank Filz * in milliseconds. If a value of zero 228052ccb8e9SFrank Filz * is present in this field then no changes are to 228152ccb8e9SFrank Filz * be made to this parameter. 22821da177e4SLinus Torvalds * spp_pathmaxrxt - This contains the maximum number of 22831da177e4SLinus Torvalds * retransmissions before this address shall be 228452ccb8e9SFrank Filz * considered unreachable. If a value of zero 228552ccb8e9SFrank Filz * is present in this field then no changes are to 228652ccb8e9SFrank Filz * be made to this parameter. 228752ccb8e9SFrank Filz * spp_pathmtu - When Path MTU discovery is disabled the value 228852ccb8e9SFrank Filz * specified here will be the "fixed" path mtu. 228952ccb8e9SFrank Filz * Note that if the spp_address field is empty 229052ccb8e9SFrank Filz * then all associations on this address will 229152ccb8e9SFrank Filz * have this fixed path mtu set upon them. 229252ccb8e9SFrank Filz * 229352ccb8e9SFrank Filz * spp_sackdelay - When delayed sack is enabled, this value specifies 229452ccb8e9SFrank Filz * the number of milliseconds that sacks will be delayed 229552ccb8e9SFrank Filz * for. This value will apply to all addresses of an 229652ccb8e9SFrank Filz * association if the spp_address field is empty. Note 229752ccb8e9SFrank Filz * also, that if delayed sack is enabled and this 229852ccb8e9SFrank Filz * value is set to 0, no change is made to the last 229952ccb8e9SFrank Filz * recorded delayed sack timer value. 230052ccb8e9SFrank Filz * 230152ccb8e9SFrank Filz * spp_flags - These flags are used to control various features 230252ccb8e9SFrank Filz * on an association. The flag field may contain 230352ccb8e9SFrank Filz * zero or more of the following options. 230452ccb8e9SFrank Filz * 230552ccb8e9SFrank Filz * SPP_HB_ENABLE - Enable heartbeats on the 230652ccb8e9SFrank Filz * specified address. Note that if the address 230752ccb8e9SFrank Filz * field is empty all addresses for the association 230852ccb8e9SFrank Filz * have heartbeats enabled upon them. 230952ccb8e9SFrank Filz * 231052ccb8e9SFrank Filz * SPP_HB_DISABLE - Disable heartbeats on the 231152ccb8e9SFrank Filz * speicifed address. Note that if the address 231252ccb8e9SFrank Filz * field is empty all addresses for the association 231352ccb8e9SFrank Filz * will have their heartbeats disabled. Note also 231452ccb8e9SFrank Filz * that SPP_HB_ENABLE and SPP_HB_DISABLE are 231552ccb8e9SFrank Filz * mutually exclusive, only one of these two should 231652ccb8e9SFrank Filz * be specified. Enabling both fields will have 231752ccb8e9SFrank Filz * undetermined results. 231852ccb8e9SFrank Filz * 231952ccb8e9SFrank Filz * SPP_HB_DEMAND - Request a user initiated heartbeat 232052ccb8e9SFrank Filz * to be made immediately. 232152ccb8e9SFrank Filz * 2322bdf3092aSVlad Yasevich * SPP_HB_TIME_IS_ZERO - Specify's that the time for 2323bdf3092aSVlad Yasevich * heartbeat delayis to be set to the value of 0 2324bdf3092aSVlad Yasevich * milliseconds. 2325bdf3092aSVlad Yasevich * 232652ccb8e9SFrank Filz * SPP_PMTUD_ENABLE - This field will enable PMTU 232752ccb8e9SFrank Filz * discovery upon the specified address. Note that 232852ccb8e9SFrank Filz * if the address feild is empty then all addresses 232952ccb8e9SFrank Filz * on the association are effected. 233052ccb8e9SFrank Filz * 233152ccb8e9SFrank Filz * SPP_PMTUD_DISABLE - This field will disable PMTU 233252ccb8e9SFrank Filz * discovery upon the specified address. Note that 233352ccb8e9SFrank Filz * if the address feild is empty then all addresses 233452ccb8e9SFrank Filz * on the association are effected. Not also that 233552ccb8e9SFrank Filz * SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually 233652ccb8e9SFrank Filz * exclusive. Enabling both will have undetermined 233752ccb8e9SFrank Filz * results. 233852ccb8e9SFrank Filz * 233952ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE - Setting this flag turns 234052ccb8e9SFrank Filz * on delayed sack. The time specified in spp_sackdelay 234152ccb8e9SFrank Filz * is used to specify the sack delay for this address. Note 234252ccb8e9SFrank Filz * that if spp_address is empty then all addresses will 234352ccb8e9SFrank Filz * enable delayed sack and take on the sack delay 234452ccb8e9SFrank Filz * value specified in spp_sackdelay. 234552ccb8e9SFrank Filz * SPP_SACKDELAY_DISABLE - Setting this flag turns 234652ccb8e9SFrank Filz * off delayed sack. If the spp_address field is blank then 234752ccb8e9SFrank Filz * delayed sack is disabled for the entire association. Note 234852ccb8e9SFrank Filz * also that this field is mutually exclusive to 234952ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE, setting both will have undefined 235052ccb8e9SFrank Filz * results. 23511da177e4SLinus Torvalds */ 235216164366SAdrian Bunk static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, 235352ccb8e9SFrank Filz struct sctp_transport *trans, 235452ccb8e9SFrank Filz struct sctp_association *asoc, 235552ccb8e9SFrank Filz struct sctp_sock *sp, 235652ccb8e9SFrank Filz int hb_change, 235752ccb8e9SFrank Filz int pmtud_change, 235852ccb8e9SFrank Filz int sackdelay_change) 235952ccb8e9SFrank Filz { 236052ccb8e9SFrank Filz int error; 236152ccb8e9SFrank Filz 236252ccb8e9SFrank Filz if (params->spp_flags & SPP_HB_DEMAND && trans) { 236355e26eb9SEric W. Biederman struct net *net = sock_net(trans->asoc->base.sk); 236455e26eb9SEric W. Biederman 236555e26eb9SEric W. Biederman error = sctp_primitive_REQUESTHEARTBEAT(net, trans->asoc, trans); 236652ccb8e9SFrank Filz if (error) 236752ccb8e9SFrank Filz return error; 236852ccb8e9SFrank Filz } 236952ccb8e9SFrank Filz 2370bdf3092aSVlad Yasevich /* Note that unless the spp_flag is set to SPP_HB_ENABLE the value of 2371bdf3092aSVlad Yasevich * this field is ignored. Note also that a value of zero indicates 2372bdf3092aSVlad Yasevich * the current setting should be left unchanged. 2373bdf3092aSVlad Yasevich */ 2374bdf3092aSVlad Yasevich if (params->spp_flags & SPP_HB_ENABLE) { 2375bdf3092aSVlad Yasevich 2376bdf3092aSVlad Yasevich /* Re-zero the interval if the SPP_HB_TIME_IS_ZERO is 2377bdf3092aSVlad Yasevich * set. This lets us use 0 value when this flag 2378bdf3092aSVlad Yasevich * is set. 2379bdf3092aSVlad Yasevich */ 2380bdf3092aSVlad Yasevich if (params->spp_flags & SPP_HB_TIME_IS_ZERO) 2381bdf3092aSVlad Yasevich params->spp_hbinterval = 0; 2382bdf3092aSVlad Yasevich 2383bdf3092aSVlad Yasevich if (params->spp_hbinterval || 2384bdf3092aSVlad Yasevich (params->spp_flags & SPP_HB_TIME_IS_ZERO)) { 238552ccb8e9SFrank Filz if (trans) { 2386bdf3092aSVlad Yasevich trans->hbinterval = 2387bdf3092aSVlad Yasevich msecs_to_jiffies(params->spp_hbinterval); 238852ccb8e9SFrank Filz } else if (asoc) { 2389bdf3092aSVlad Yasevich asoc->hbinterval = 2390bdf3092aSVlad Yasevich msecs_to_jiffies(params->spp_hbinterval); 239152ccb8e9SFrank Filz } else { 239252ccb8e9SFrank Filz sp->hbinterval = params->spp_hbinterval; 239352ccb8e9SFrank Filz } 239452ccb8e9SFrank Filz } 2395bdf3092aSVlad Yasevich } 239652ccb8e9SFrank Filz 239752ccb8e9SFrank Filz if (hb_change) { 239852ccb8e9SFrank Filz if (trans) { 239952ccb8e9SFrank Filz trans->param_flags = 240052ccb8e9SFrank Filz (trans->param_flags & ~SPP_HB) | hb_change; 240152ccb8e9SFrank Filz } else if (asoc) { 240252ccb8e9SFrank Filz asoc->param_flags = 240352ccb8e9SFrank Filz (asoc->param_flags & ~SPP_HB) | hb_change; 240452ccb8e9SFrank Filz } else { 240552ccb8e9SFrank Filz sp->param_flags = 240652ccb8e9SFrank Filz (sp->param_flags & ~SPP_HB) | hb_change; 240752ccb8e9SFrank Filz } 240852ccb8e9SFrank Filz } 240952ccb8e9SFrank Filz 2410bdf3092aSVlad Yasevich /* When Path MTU discovery is disabled the value specified here will 2411bdf3092aSVlad Yasevich * be the "fixed" path mtu (i.e. the value of the spp_flags field must 2412bdf3092aSVlad Yasevich * include the flag SPP_PMTUD_DISABLE for this field to have any 2413bdf3092aSVlad Yasevich * effect). 2414bdf3092aSVlad Yasevich */ 2415bdf3092aSVlad Yasevich if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { 241652ccb8e9SFrank Filz if (trans) { 241752ccb8e9SFrank Filz trans->pathmtu = params->spp_pathmtu; 241802f3d4ceSDavid S. Miller sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); 241952ccb8e9SFrank Filz } else if (asoc) { 242052ccb8e9SFrank Filz asoc->pathmtu = params->spp_pathmtu; 2421f68b2e05SVlad Yasevich sctp_frag_point(asoc, params->spp_pathmtu); 242252ccb8e9SFrank Filz } else { 242352ccb8e9SFrank Filz sp->pathmtu = params->spp_pathmtu; 242452ccb8e9SFrank Filz } 242552ccb8e9SFrank Filz } 242652ccb8e9SFrank Filz 242752ccb8e9SFrank Filz if (pmtud_change) { 242852ccb8e9SFrank Filz if (trans) { 242952ccb8e9SFrank Filz int update = (trans->param_flags & SPP_PMTUD_DISABLE) && 243052ccb8e9SFrank Filz (params->spp_flags & SPP_PMTUD_ENABLE); 243152ccb8e9SFrank Filz trans->param_flags = 243252ccb8e9SFrank Filz (trans->param_flags & ~SPP_PMTUD) | pmtud_change; 243352ccb8e9SFrank Filz if (update) { 24349914ae3cSVlad Yasevich sctp_transport_pmtu(trans, sctp_opt2sk(sp)); 243502f3d4ceSDavid S. Miller sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); 243652ccb8e9SFrank Filz } 243752ccb8e9SFrank Filz } else if (asoc) { 243852ccb8e9SFrank Filz asoc->param_flags = 243952ccb8e9SFrank Filz (asoc->param_flags & ~SPP_PMTUD) | pmtud_change; 244052ccb8e9SFrank Filz } else { 244152ccb8e9SFrank Filz sp->param_flags = 244252ccb8e9SFrank Filz (sp->param_flags & ~SPP_PMTUD) | pmtud_change; 244352ccb8e9SFrank Filz } 244452ccb8e9SFrank Filz } 244552ccb8e9SFrank Filz 2446bdf3092aSVlad Yasevich /* Note that unless the spp_flag is set to SPP_SACKDELAY_ENABLE the 2447bdf3092aSVlad Yasevich * value of this field is ignored. Note also that a value of zero 2448bdf3092aSVlad Yasevich * indicates the current setting should be left unchanged. 2449bdf3092aSVlad Yasevich */ 2450bdf3092aSVlad Yasevich if ((params->spp_flags & SPP_SACKDELAY_ENABLE) && params->spp_sackdelay) { 245152ccb8e9SFrank Filz if (trans) { 245252ccb8e9SFrank Filz trans->sackdelay = 245352ccb8e9SFrank Filz msecs_to_jiffies(params->spp_sackdelay); 245452ccb8e9SFrank Filz } else if (asoc) { 245552ccb8e9SFrank Filz asoc->sackdelay = 245652ccb8e9SFrank Filz msecs_to_jiffies(params->spp_sackdelay); 245752ccb8e9SFrank Filz } else { 245852ccb8e9SFrank Filz sp->sackdelay = params->spp_sackdelay; 245952ccb8e9SFrank Filz } 246052ccb8e9SFrank Filz } 246152ccb8e9SFrank Filz 246252ccb8e9SFrank Filz if (sackdelay_change) { 246352ccb8e9SFrank Filz if (trans) { 246452ccb8e9SFrank Filz trans->param_flags = 246552ccb8e9SFrank Filz (trans->param_flags & ~SPP_SACKDELAY) | 246652ccb8e9SFrank Filz sackdelay_change; 246752ccb8e9SFrank Filz } else if (asoc) { 246852ccb8e9SFrank Filz asoc->param_flags = 246952ccb8e9SFrank Filz (asoc->param_flags & ~SPP_SACKDELAY) | 247052ccb8e9SFrank Filz sackdelay_change; 247152ccb8e9SFrank Filz } else { 247252ccb8e9SFrank Filz sp->param_flags = 247352ccb8e9SFrank Filz (sp->param_flags & ~SPP_SACKDELAY) | 247452ccb8e9SFrank Filz sackdelay_change; 247552ccb8e9SFrank Filz } 247652ccb8e9SFrank Filz } 247752ccb8e9SFrank Filz 247837051f73SAndrei Pelinescu-Onciul /* Note that a value of zero indicates the current setting should be 247937051f73SAndrei Pelinescu-Onciul left unchanged. 2480bdf3092aSVlad Yasevich */ 248137051f73SAndrei Pelinescu-Onciul if (params->spp_pathmaxrxt) { 248252ccb8e9SFrank Filz if (trans) { 248352ccb8e9SFrank Filz trans->pathmaxrxt = params->spp_pathmaxrxt; 248452ccb8e9SFrank Filz } else if (asoc) { 248552ccb8e9SFrank Filz asoc->pathmaxrxt = params->spp_pathmaxrxt; 248652ccb8e9SFrank Filz } else { 248752ccb8e9SFrank Filz sp->pathmaxrxt = params->spp_pathmaxrxt; 248852ccb8e9SFrank Filz } 248952ccb8e9SFrank Filz } 249052ccb8e9SFrank Filz 249152ccb8e9SFrank Filz return 0; 249252ccb8e9SFrank Filz } 249352ccb8e9SFrank Filz 24941da177e4SLinus Torvalds static int sctp_setsockopt_peer_addr_params(struct sock *sk, 2495b7058842SDavid S. Miller char __user *optval, 2496b7058842SDavid S. Miller unsigned int optlen) 24971da177e4SLinus Torvalds { 24981da177e4SLinus Torvalds struct sctp_paddrparams params; 249952ccb8e9SFrank Filz struct sctp_transport *trans = NULL; 250052ccb8e9SFrank Filz struct sctp_association *asoc = NULL; 250152ccb8e9SFrank Filz struct sctp_sock *sp = sctp_sk(sk); 25021da177e4SLinus Torvalds int error; 250352ccb8e9SFrank Filz int hb_change, pmtud_change, sackdelay_change; 25041da177e4SLinus Torvalds 25051da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_paddrparams)) 25061da177e4SLinus Torvalds return -EINVAL; 250752ccb8e9SFrank Filz 25081da177e4SLinus Torvalds if (copy_from_user(¶ms, optval, optlen)) 25091da177e4SLinus Torvalds return -EFAULT; 25101da177e4SLinus Torvalds 251152ccb8e9SFrank Filz /* Validate flags and value parameters. */ 251252ccb8e9SFrank Filz hb_change = params.spp_flags & SPP_HB; 251352ccb8e9SFrank Filz pmtud_change = params.spp_flags & SPP_PMTUD; 251452ccb8e9SFrank Filz sackdelay_change = params.spp_flags & SPP_SACKDELAY; 25151da177e4SLinus Torvalds 251652ccb8e9SFrank Filz if (hb_change == SPP_HB || 251752ccb8e9SFrank Filz pmtud_change == SPP_PMTUD || 251852ccb8e9SFrank Filz sackdelay_change == SPP_SACKDELAY || 251952ccb8e9SFrank Filz params.spp_sackdelay > 500 || 2520f64f9e71SJoe Perches (params.spp_pathmtu && 2521f64f9e71SJoe Perches params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT)) 25221da177e4SLinus Torvalds return -EINVAL; 25231da177e4SLinus Torvalds 252452ccb8e9SFrank Filz /* If an address other than INADDR_ANY is specified, and 252552ccb8e9SFrank Filz * no transport is found, then the request is invalid. 252652ccb8e9SFrank Filz */ 252752cae8f0SVlad Yasevich if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { 25281da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, ¶ms.spp_address, 25291da177e4SLinus Torvalds params.spp_assoc_id); 25301da177e4SLinus Torvalds if (!trans) 25311da177e4SLinus Torvalds return -EINVAL; 25321da177e4SLinus Torvalds } 25331da177e4SLinus Torvalds 253452ccb8e9SFrank Filz /* Get association, if assoc_id != 0 and the socket is a one 253552ccb8e9SFrank Filz * to many style socket, and an association was not found, then 253652ccb8e9SFrank Filz * the id was invalid. 25371da177e4SLinus Torvalds */ 253852ccb8e9SFrank Filz asoc = sctp_id2assoc(sk, params.spp_assoc_id); 253952ccb8e9SFrank Filz if (!asoc && params.spp_assoc_id && sctp_style(sk, UDP)) 254052ccb8e9SFrank Filz return -EINVAL; 254152ccb8e9SFrank Filz 254252ccb8e9SFrank Filz /* Heartbeat demand can only be sent on a transport or 254352ccb8e9SFrank Filz * association, but not a socket. 254452ccb8e9SFrank Filz */ 254552ccb8e9SFrank Filz if (params.spp_flags & SPP_HB_DEMAND && !trans && !asoc) 254652ccb8e9SFrank Filz return -EINVAL; 254752ccb8e9SFrank Filz 254852ccb8e9SFrank Filz /* Process parameters. */ 254952ccb8e9SFrank Filz error = sctp_apply_peer_addr_params(¶ms, trans, asoc, sp, 255052ccb8e9SFrank Filz hb_change, pmtud_change, 255152ccb8e9SFrank Filz sackdelay_change); 255252ccb8e9SFrank Filz 255352ccb8e9SFrank Filz if (error) 255452ccb8e9SFrank Filz return error; 255552ccb8e9SFrank Filz 255652ccb8e9SFrank Filz /* If changes are for association, also apply parameters to each 255752ccb8e9SFrank Filz * transport. 255852ccb8e9SFrank Filz */ 255952ccb8e9SFrank Filz if (!trans && asoc) { 25609dbc15f0SRobert P. J. Day list_for_each_entry(trans, &asoc->peer.transport_addr_list, 25619dbc15f0SRobert P. J. Day transports) { 256252ccb8e9SFrank Filz sctp_apply_peer_addr_params(¶ms, trans, asoc, sp, 256352ccb8e9SFrank Filz hb_change, pmtud_change, 256452ccb8e9SFrank Filz sackdelay_change); 256552ccb8e9SFrank Filz } 256652ccb8e9SFrank Filz } 25671da177e4SLinus Torvalds 25681da177e4SLinus Torvalds return 0; 25691da177e4SLinus Torvalds } 25701da177e4SLinus Torvalds 25710ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags) 25720ea5e4dfSwangweidong { 25730ea5e4dfSwangweidong return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; 25740ea5e4dfSwangweidong } 25750ea5e4dfSwangweidong 25760ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags) 25770ea5e4dfSwangweidong { 25780ea5e4dfSwangweidong return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; 25790ea5e4dfSwangweidong } 25800ea5e4dfSwangweidong 2581d364d927SWei Yongjun /* 2582d364d927SWei Yongjun * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 25837708610bSFrank Filz * 2584d364d927SWei Yongjun * This option will effect the way delayed acks are performed. This 2585d364d927SWei Yongjun * option allows you to get or set the delayed ack time, in 2586d364d927SWei Yongjun * milliseconds. It also allows changing the delayed ack frequency. 2587d364d927SWei Yongjun * Changing the frequency to 1 disables the delayed sack algorithm. If 2588d364d927SWei Yongjun * the assoc_id is 0, then this sets or gets the endpoints default 2589d364d927SWei Yongjun * values. If the assoc_id field is non-zero, then the set or get 2590d364d927SWei Yongjun * effects the specified association for the one to many model (the 2591d364d927SWei Yongjun * assoc_id field is ignored by the one to one model). Note that if 2592d364d927SWei Yongjun * sack_delay or sack_freq are 0 when setting this option, then the 2593d364d927SWei Yongjun * current values will remain unchanged. 25947708610bSFrank Filz * 2595d364d927SWei Yongjun * struct sctp_sack_info { 2596d364d927SWei Yongjun * sctp_assoc_t sack_assoc_id; 2597d364d927SWei Yongjun * uint32_t sack_delay; 2598d364d927SWei Yongjun * uint32_t sack_freq; 25997708610bSFrank Filz * }; 26007708610bSFrank Filz * 2601d364d927SWei Yongjun * sack_assoc_id - This parameter, indicates which association the user 2602d364d927SWei Yongjun * is performing an action upon. Note that if this field's value is 2603d364d927SWei Yongjun * zero then the endpoints default value is changed (effecting future 26047708610bSFrank Filz * associations only). 26057708610bSFrank Filz * 2606d364d927SWei Yongjun * sack_delay - This parameter contains the number of milliseconds that 2607d364d927SWei Yongjun * the user is requesting the delayed ACK timer be set to. Note that 2608d364d927SWei Yongjun * this value is defined in the standard to be between 200 and 500 2609d364d927SWei Yongjun * milliseconds. 26107708610bSFrank Filz * 2611d364d927SWei Yongjun * sack_freq - This parameter contains the number of packets that must 2612d364d927SWei Yongjun * be received before a sack is sent without waiting for the delay 2613d364d927SWei Yongjun * timer to expire. The default value for this is 2, setting this 2614d364d927SWei Yongjun * value to 1 will disable the delayed sack algorithm. 26157708610bSFrank Filz */ 26167708610bSFrank Filz 2617d364d927SWei Yongjun static int sctp_setsockopt_delayed_ack(struct sock *sk, 2618b7058842SDavid S. Miller char __user *optval, unsigned int optlen) 26197708610bSFrank Filz { 2620d364d927SWei Yongjun struct sctp_sack_info params; 26217708610bSFrank Filz struct sctp_transport *trans = NULL; 26227708610bSFrank Filz struct sctp_association *asoc = NULL; 26237708610bSFrank Filz struct sctp_sock *sp = sctp_sk(sk); 26247708610bSFrank Filz 2625d364d927SWei Yongjun if (optlen == sizeof(struct sctp_sack_info)) { 26267708610bSFrank Filz if (copy_from_user(¶ms, optval, optlen)) 26277708610bSFrank Filz return -EFAULT; 26287708610bSFrank Filz 2629d364d927SWei Yongjun if (params.sack_delay == 0 && params.sack_freq == 0) 2630d364d927SWei Yongjun return 0; 2631d364d927SWei Yongjun } else if (optlen == sizeof(struct sctp_assoc_value)) { 263294f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 2633f916ec96SNeil Horman "%s (pid %d) " 263494f65193SNeil Horman "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 2635f916ec96SNeil Horman "Use struct sctp_sack_info instead\n", 2636f916ec96SNeil Horman current->comm, task_pid_nr(current)); 2637d364d927SWei Yongjun if (copy_from_user(¶ms, optval, optlen)) 2638d364d927SWei Yongjun return -EFAULT; 2639d364d927SWei Yongjun 2640d364d927SWei Yongjun if (params.sack_delay == 0) 2641d364d927SWei Yongjun params.sack_freq = 1; 2642d364d927SWei Yongjun else 2643d364d927SWei Yongjun params.sack_freq = 0; 2644d364d927SWei Yongjun } else 26457708610bSFrank Filz return -EINVAL; 26467708610bSFrank Filz 2647d364d927SWei Yongjun /* Validate value parameter. */ 2648d364d927SWei Yongjun if (params.sack_delay > 500) 2649d364d927SWei Yongjun return -EINVAL; 2650d364d927SWei Yongjun 2651d364d927SWei Yongjun /* Get association, if sack_assoc_id != 0 and the socket is a one 26527708610bSFrank Filz * to many style socket, and an association was not found, then 26537708610bSFrank Filz * the id was invalid. 26547708610bSFrank Filz */ 2655d364d927SWei Yongjun asoc = sctp_id2assoc(sk, params.sack_assoc_id); 2656d364d927SWei Yongjun if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP)) 26577708610bSFrank Filz return -EINVAL; 26587708610bSFrank Filz 2659d364d927SWei Yongjun if (params.sack_delay) { 26607708610bSFrank Filz if (asoc) { 26617708610bSFrank Filz asoc->sackdelay = 2662d364d927SWei Yongjun msecs_to_jiffies(params.sack_delay); 26637708610bSFrank Filz asoc->param_flags = 26640ea5e4dfSwangweidong sctp_spp_sackdelay_enable(asoc->param_flags); 26657708610bSFrank Filz } else { 2666d364d927SWei Yongjun sp->sackdelay = params.sack_delay; 26677708610bSFrank Filz sp->param_flags = 26680ea5e4dfSwangweidong sctp_spp_sackdelay_enable(sp->param_flags); 26697708610bSFrank Filz } 2670d364d927SWei Yongjun } 2671d364d927SWei Yongjun 2672d364d927SWei Yongjun if (params.sack_freq == 1) { 26737708610bSFrank Filz if (asoc) { 26747708610bSFrank Filz asoc->param_flags = 26750ea5e4dfSwangweidong sctp_spp_sackdelay_disable(asoc->param_flags); 26767708610bSFrank Filz } else { 26777708610bSFrank Filz sp->param_flags = 26780ea5e4dfSwangweidong sctp_spp_sackdelay_disable(sp->param_flags); 26797708610bSFrank Filz } 2680d364d927SWei Yongjun } else if (params.sack_freq > 1) { 2681d364d927SWei Yongjun if (asoc) { 2682d364d927SWei Yongjun asoc->sackfreq = params.sack_freq; 2683d364d927SWei Yongjun asoc->param_flags = 26840ea5e4dfSwangweidong sctp_spp_sackdelay_enable(asoc->param_flags); 2685d364d927SWei Yongjun } else { 2686d364d927SWei Yongjun sp->sackfreq = params.sack_freq; 2687d364d927SWei Yongjun sp->param_flags = 26880ea5e4dfSwangweidong sctp_spp_sackdelay_enable(sp->param_flags); 2689d364d927SWei Yongjun } 26907708610bSFrank Filz } 26917708610bSFrank Filz 26927708610bSFrank Filz /* If change is for association, also apply to each transport. */ 26937708610bSFrank Filz if (asoc) { 26949dbc15f0SRobert P. J. Day list_for_each_entry(trans, &asoc->peer.transport_addr_list, 26959dbc15f0SRobert P. J. Day transports) { 2696d364d927SWei Yongjun if (params.sack_delay) { 26977708610bSFrank Filz trans->sackdelay = 2698d364d927SWei Yongjun msecs_to_jiffies(params.sack_delay); 26997708610bSFrank Filz trans->param_flags = 27000ea5e4dfSwangweidong sctp_spp_sackdelay_enable(trans->param_flags); 2701d364d927SWei Yongjun } 27027bfe8bdbSVlad Yasevich if (params.sack_freq == 1) { 27037708610bSFrank Filz trans->param_flags = 27040ea5e4dfSwangweidong sctp_spp_sackdelay_disable(trans->param_flags); 2705d364d927SWei Yongjun } else if (params.sack_freq > 1) { 2706d364d927SWei Yongjun trans->sackfreq = params.sack_freq; 2707d364d927SWei Yongjun trans->param_flags = 27080ea5e4dfSwangweidong sctp_spp_sackdelay_enable(trans->param_flags); 27097708610bSFrank Filz } 27107708610bSFrank Filz } 27117708610bSFrank Filz } 27127708610bSFrank Filz 27137708610bSFrank Filz return 0; 27147708610bSFrank Filz } 27157708610bSFrank Filz 27161da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG) 27171da177e4SLinus Torvalds * 27181da177e4SLinus Torvalds * Applications can specify protocol parameters for the default association 27191da177e4SLinus Torvalds * initialization. The option name argument to setsockopt() and getsockopt() 27201da177e4SLinus Torvalds * is SCTP_INITMSG. 27211da177e4SLinus Torvalds * 27221da177e4SLinus Torvalds * Setting initialization parameters is effective only on an unconnected 27231da177e4SLinus Torvalds * socket (for UDP-style sockets only future associations are effected 27241da177e4SLinus Torvalds * by the change). With TCP-style sockets, this option is inherited by 27251da177e4SLinus Torvalds * sockets derived from a listener socket. 27261da177e4SLinus Torvalds */ 2727b7058842SDavid S. Miller static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen) 27281da177e4SLinus Torvalds { 27291da177e4SLinus Torvalds struct sctp_initmsg sinit; 27301da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 27311da177e4SLinus Torvalds 27321da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_initmsg)) 27331da177e4SLinus Torvalds return -EINVAL; 27341da177e4SLinus Torvalds if (copy_from_user(&sinit, optval, optlen)) 27351da177e4SLinus Torvalds return -EFAULT; 27361da177e4SLinus Torvalds 27371da177e4SLinus Torvalds if (sinit.sinit_num_ostreams) 27381da177e4SLinus Torvalds sp->initmsg.sinit_num_ostreams = sinit.sinit_num_ostreams; 27391da177e4SLinus Torvalds if (sinit.sinit_max_instreams) 27401da177e4SLinus Torvalds sp->initmsg.sinit_max_instreams = sinit.sinit_max_instreams; 27411da177e4SLinus Torvalds if (sinit.sinit_max_attempts) 27421da177e4SLinus Torvalds sp->initmsg.sinit_max_attempts = sinit.sinit_max_attempts; 27431da177e4SLinus Torvalds if (sinit.sinit_max_init_timeo) 27441da177e4SLinus Torvalds sp->initmsg.sinit_max_init_timeo = sinit.sinit_max_init_timeo; 27451da177e4SLinus Torvalds 27461da177e4SLinus Torvalds return 0; 27471da177e4SLinus Torvalds } 27481da177e4SLinus Torvalds 27491da177e4SLinus Torvalds /* 27501da177e4SLinus Torvalds * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 27511da177e4SLinus Torvalds * 27521da177e4SLinus Torvalds * Applications that wish to use the sendto() system call may wish to 27531da177e4SLinus Torvalds * specify a default set of parameters that would normally be supplied 27541da177e4SLinus Torvalds * through the inclusion of ancillary data. This socket option allows 27551da177e4SLinus Torvalds * such an application to set the default sctp_sndrcvinfo structure. 27561da177e4SLinus Torvalds * The application that wishes to use this socket option simply passes 27571da177e4SLinus Torvalds * in to this call the sctp_sndrcvinfo structure defined in Section 27581da177e4SLinus Torvalds * 5.2.2) The input parameters accepted by this call include 27591da177e4SLinus Torvalds * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 27601da177e4SLinus Torvalds * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 27611da177e4SLinus Torvalds * to this call if the caller is using the UDP model. 27621da177e4SLinus Torvalds */ 27631da177e4SLinus Torvalds static int sctp_setsockopt_default_send_param(struct sock *sk, 2764b7058842SDavid S. Miller char __user *optval, 2765b7058842SDavid S. Miller unsigned int optlen) 27661da177e4SLinus Torvalds { 27671da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 27686b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 27696b3fd5f3SGeir Ola Vaagland struct sctp_sndrcvinfo info; 27701da177e4SLinus Torvalds 27716b3fd5f3SGeir Ola Vaagland if (optlen != sizeof(info)) 27721da177e4SLinus Torvalds return -EINVAL; 27731da177e4SLinus Torvalds if (copy_from_user(&info, optval, optlen)) 27741da177e4SLinus Torvalds return -EFAULT; 27756b3fd5f3SGeir Ola Vaagland if (info.sinfo_flags & 27766b3fd5f3SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 27776b3fd5f3SGeir Ola Vaagland SCTP_ABORT | SCTP_EOF)) 27786b3fd5f3SGeir Ola Vaagland return -EINVAL; 27791da177e4SLinus Torvalds 27801da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); 27811da177e4SLinus Torvalds if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) 27821da177e4SLinus Torvalds return -EINVAL; 27831da177e4SLinus Torvalds if (asoc) { 27841da177e4SLinus Torvalds asoc->default_stream = info.sinfo_stream; 27851da177e4SLinus Torvalds asoc->default_flags = info.sinfo_flags; 27861da177e4SLinus Torvalds asoc->default_ppid = info.sinfo_ppid; 27871da177e4SLinus Torvalds asoc->default_context = info.sinfo_context; 27881da177e4SLinus Torvalds asoc->default_timetolive = info.sinfo_timetolive; 27891da177e4SLinus Torvalds } else { 27901da177e4SLinus Torvalds sp->default_stream = info.sinfo_stream; 27911da177e4SLinus Torvalds sp->default_flags = info.sinfo_flags; 27921da177e4SLinus Torvalds sp->default_ppid = info.sinfo_ppid; 27931da177e4SLinus Torvalds sp->default_context = info.sinfo_context; 27941da177e4SLinus Torvalds sp->default_timetolive = info.sinfo_timetolive; 27951da177e4SLinus Torvalds } 27961da177e4SLinus Torvalds 27971da177e4SLinus Torvalds return 0; 27981da177e4SLinus Torvalds } 27991da177e4SLinus Torvalds 28006b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters 28016b3fd5f3SGeir Ola Vaagland * (SCTP_DEFAULT_SNDINFO) 28026b3fd5f3SGeir Ola Vaagland */ 28036b3fd5f3SGeir Ola Vaagland static int sctp_setsockopt_default_sndinfo(struct sock *sk, 28046b3fd5f3SGeir Ola Vaagland char __user *optval, 28056b3fd5f3SGeir Ola Vaagland unsigned int optlen) 28066b3fd5f3SGeir Ola Vaagland { 28076b3fd5f3SGeir Ola Vaagland struct sctp_sock *sp = sctp_sk(sk); 28086b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 28096b3fd5f3SGeir Ola Vaagland struct sctp_sndinfo info; 28106b3fd5f3SGeir Ola Vaagland 28116b3fd5f3SGeir Ola Vaagland if (optlen != sizeof(info)) 28126b3fd5f3SGeir Ola Vaagland return -EINVAL; 28136b3fd5f3SGeir Ola Vaagland if (copy_from_user(&info, optval, optlen)) 28146b3fd5f3SGeir Ola Vaagland return -EFAULT; 28156b3fd5f3SGeir Ola Vaagland if (info.snd_flags & 28166b3fd5f3SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 28176b3fd5f3SGeir Ola Vaagland SCTP_ABORT | SCTP_EOF)) 28186b3fd5f3SGeir Ola Vaagland return -EINVAL; 28196b3fd5f3SGeir Ola Vaagland 28206b3fd5f3SGeir Ola Vaagland asoc = sctp_id2assoc(sk, info.snd_assoc_id); 28216b3fd5f3SGeir Ola Vaagland if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) 28226b3fd5f3SGeir Ola Vaagland return -EINVAL; 28236b3fd5f3SGeir Ola Vaagland if (asoc) { 28246b3fd5f3SGeir Ola Vaagland asoc->default_stream = info.snd_sid; 28256b3fd5f3SGeir Ola Vaagland asoc->default_flags = info.snd_flags; 28266b3fd5f3SGeir Ola Vaagland asoc->default_ppid = info.snd_ppid; 28276b3fd5f3SGeir Ola Vaagland asoc->default_context = info.snd_context; 28286b3fd5f3SGeir Ola Vaagland } else { 28296b3fd5f3SGeir Ola Vaagland sp->default_stream = info.snd_sid; 28306b3fd5f3SGeir Ola Vaagland sp->default_flags = info.snd_flags; 28316b3fd5f3SGeir Ola Vaagland sp->default_ppid = info.snd_ppid; 28326b3fd5f3SGeir Ola Vaagland sp->default_context = info.snd_context; 28336b3fd5f3SGeir Ola Vaagland } 28346b3fd5f3SGeir Ola Vaagland 28356b3fd5f3SGeir Ola Vaagland return 0; 28366b3fd5f3SGeir Ola Vaagland } 28376b3fd5f3SGeir Ola Vaagland 28381da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 28391da177e4SLinus Torvalds * 28401da177e4SLinus Torvalds * Requests that the local SCTP stack use the enclosed peer address as 28411da177e4SLinus Torvalds * the association primary. The enclosed address must be one of the 28421da177e4SLinus Torvalds * association peer's addresses. 28431da177e4SLinus Torvalds */ 28441da177e4SLinus Torvalds static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, 2845b7058842SDavid S. Miller unsigned int optlen) 28461da177e4SLinus Torvalds { 28471da177e4SLinus Torvalds struct sctp_prim prim; 28481da177e4SLinus Torvalds struct sctp_transport *trans; 28491da177e4SLinus Torvalds 28501da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_prim)) 28511da177e4SLinus Torvalds return -EINVAL; 28521da177e4SLinus Torvalds 28531da177e4SLinus Torvalds if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) 28541da177e4SLinus Torvalds return -EFAULT; 28551da177e4SLinus Torvalds 28561da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id); 28571da177e4SLinus Torvalds if (!trans) 28581da177e4SLinus Torvalds return -EINVAL; 28591da177e4SLinus Torvalds 28601da177e4SLinus Torvalds sctp_assoc_set_primary(trans->asoc, trans); 28611da177e4SLinus Torvalds 28621da177e4SLinus Torvalds return 0; 28631da177e4SLinus Torvalds } 28641da177e4SLinus Torvalds 28651da177e4SLinus Torvalds /* 28661da177e4SLinus Torvalds * 7.1.5 SCTP_NODELAY 28671da177e4SLinus Torvalds * 28681da177e4SLinus Torvalds * Turn on/off any Nagle-like algorithm. This means that packets are 28691da177e4SLinus Torvalds * generally sent as soon as possible and no unnecessary delays are 28701da177e4SLinus Torvalds * introduced, at the cost of more packets in the network. Expects an 28711da177e4SLinus Torvalds * integer boolean flag. 28721da177e4SLinus Torvalds */ 28731da177e4SLinus Torvalds static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval, 2874b7058842SDavid S. Miller unsigned int optlen) 28751da177e4SLinus Torvalds { 28761da177e4SLinus Torvalds int val; 28771da177e4SLinus Torvalds 28781da177e4SLinus Torvalds if (optlen < sizeof(int)) 28791da177e4SLinus Torvalds return -EINVAL; 28801da177e4SLinus Torvalds if (get_user(val, (int __user *)optval)) 28811da177e4SLinus Torvalds return -EFAULT; 28821da177e4SLinus Torvalds 28831da177e4SLinus Torvalds sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; 28841da177e4SLinus Torvalds return 0; 28851da177e4SLinus Torvalds } 28861da177e4SLinus Torvalds 28871da177e4SLinus Torvalds /* 28881da177e4SLinus Torvalds * 28891da177e4SLinus Torvalds * 7.1.1 SCTP_RTOINFO 28901da177e4SLinus Torvalds * 28911da177e4SLinus Torvalds * The protocol parameters used to initialize and bound retransmission 28921da177e4SLinus Torvalds * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 28931da177e4SLinus Torvalds * and modify these parameters. 28941da177e4SLinus Torvalds * All parameters are time values, in milliseconds. A value of 0, when 28951da177e4SLinus Torvalds * modifying the parameters, indicates that the current value should not 28961da177e4SLinus Torvalds * be changed. 28971da177e4SLinus Torvalds * 28981da177e4SLinus Torvalds */ 2899b7058842SDavid S. Miller static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen) 2900b7058842SDavid S. Miller { 29011da177e4SLinus Torvalds struct sctp_rtoinfo rtoinfo; 29021da177e4SLinus Torvalds struct sctp_association *asoc; 290385f935d4Swangweidong unsigned long rto_min, rto_max; 290485f935d4Swangweidong struct sctp_sock *sp = sctp_sk(sk); 29051da177e4SLinus Torvalds 29061da177e4SLinus Torvalds if (optlen != sizeof (struct sctp_rtoinfo)) 29071da177e4SLinus Torvalds return -EINVAL; 29081da177e4SLinus Torvalds 29091da177e4SLinus Torvalds if (copy_from_user(&rtoinfo, optval, optlen)) 29101da177e4SLinus Torvalds return -EFAULT; 29111da177e4SLinus Torvalds 29121da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); 29131da177e4SLinus Torvalds 29141da177e4SLinus Torvalds /* Set the values to the specific association */ 29151da177e4SLinus Torvalds if (!asoc && rtoinfo.srto_assoc_id && sctp_style(sk, UDP)) 29161da177e4SLinus Torvalds return -EINVAL; 29171da177e4SLinus Torvalds 291885f935d4Swangweidong rto_max = rtoinfo.srto_max; 291985f935d4Swangweidong rto_min = rtoinfo.srto_min; 292085f935d4Swangweidong 292185f935d4Swangweidong if (rto_max) 292285f935d4Swangweidong rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max; 292385f935d4Swangweidong else 292485f935d4Swangweidong rto_max = asoc ? asoc->rto_max : sp->rtoinfo.srto_max; 292585f935d4Swangweidong 292685f935d4Swangweidong if (rto_min) 292785f935d4Swangweidong rto_min = asoc ? msecs_to_jiffies(rto_min) : rto_min; 292885f935d4Swangweidong else 292985f935d4Swangweidong rto_min = asoc ? asoc->rto_min : sp->rtoinfo.srto_min; 293085f935d4Swangweidong 293185f935d4Swangweidong if (rto_min > rto_max) 293285f935d4Swangweidong return -EINVAL; 293385f935d4Swangweidong 29341da177e4SLinus Torvalds if (asoc) { 29351da177e4SLinus Torvalds if (rtoinfo.srto_initial != 0) 29361da177e4SLinus Torvalds asoc->rto_initial = 29371da177e4SLinus Torvalds msecs_to_jiffies(rtoinfo.srto_initial); 293885f935d4Swangweidong asoc->rto_max = rto_max; 293985f935d4Swangweidong asoc->rto_min = rto_min; 29401da177e4SLinus Torvalds } else { 29411da177e4SLinus Torvalds /* If there is no association or the association-id = 0 29421da177e4SLinus Torvalds * set the values to the endpoint. 29431da177e4SLinus Torvalds */ 29441da177e4SLinus Torvalds if (rtoinfo.srto_initial != 0) 29451da177e4SLinus Torvalds sp->rtoinfo.srto_initial = rtoinfo.srto_initial; 294685f935d4Swangweidong sp->rtoinfo.srto_max = rto_max; 294785f935d4Swangweidong sp->rtoinfo.srto_min = rto_min; 29481da177e4SLinus Torvalds } 29491da177e4SLinus Torvalds 29501da177e4SLinus Torvalds return 0; 29511da177e4SLinus Torvalds } 29521da177e4SLinus Torvalds 29531da177e4SLinus Torvalds /* 29541da177e4SLinus Torvalds * 29551da177e4SLinus Torvalds * 7.1.2 SCTP_ASSOCINFO 29561da177e4SLinus Torvalds * 295759c51591SMichael Opdenacker * This option is used to tune the maximum retransmission attempts 29581da177e4SLinus Torvalds * of the association. 29591da177e4SLinus Torvalds * Returns an error if the new association retransmission value is 29601da177e4SLinus Torvalds * greater than the sum of the retransmission value of the peer. 29611da177e4SLinus Torvalds * See [SCTP] for more information. 29621da177e4SLinus Torvalds * 29631da177e4SLinus Torvalds */ 2964b7058842SDavid S. Miller static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen) 29651da177e4SLinus Torvalds { 29661da177e4SLinus Torvalds 29671da177e4SLinus Torvalds struct sctp_assocparams assocparams; 29681da177e4SLinus Torvalds struct sctp_association *asoc; 29691da177e4SLinus Torvalds 29701da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_assocparams)) 29711da177e4SLinus Torvalds return -EINVAL; 29721da177e4SLinus Torvalds if (copy_from_user(&assocparams, optval, optlen)) 29731da177e4SLinus Torvalds return -EFAULT; 29741da177e4SLinus Torvalds 29751da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); 29761da177e4SLinus Torvalds 29771da177e4SLinus Torvalds if (!asoc && assocparams.sasoc_assoc_id && sctp_style(sk, UDP)) 29781da177e4SLinus Torvalds return -EINVAL; 29791da177e4SLinus Torvalds 29801da177e4SLinus Torvalds /* Set the values to the specific association */ 29811da177e4SLinus Torvalds if (asoc) { 2982402d68c4SVlad Yasevich if (assocparams.sasoc_asocmaxrxt != 0) { 2983402d68c4SVlad Yasevich __u32 path_sum = 0; 2984402d68c4SVlad Yasevich int paths = 0; 2985402d68c4SVlad Yasevich struct sctp_transport *peer_addr; 2986402d68c4SVlad Yasevich 29879dbc15f0SRobert P. J. Day list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list, 29889dbc15f0SRobert P. J. Day transports) { 2989402d68c4SVlad Yasevich path_sum += peer_addr->pathmaxrxt; 2990402d68c4SVlad Yasevich paths++; 2991402d68c4SVlad Yasevich } 2992402d68c4SVlad Yasevich 2993025dfdafSFrederik Schwarzer /* Only validate asocmaxrxt if we have more than 2994402d68c4SVlad Yasevich * one path/transport. We do this because path 2995402d68c4SVlad Yasevich * retransmissions are only counted when we have more 2996402d68c4SVlad Yasevich * then one path. 2997402d68c4SVlad Yasevich */ 2998402d68c4SVlad Yasevich if (paths > 1 && 2999402d68c4SVlad Yasevich assocparams.sasoc_asocmaxrxt > path_sum) 3000402d68c4SVlad Yasevich return -EINVAL; 3001402d68c4SVlad Yasevich 30021da177e4SLinus Torvalds asoc->max_retrans = assocparams.sasoc_asocmaxrxt; 3003402d68c4SVlad Yasevich } 3004402d68c4SVlad Yasevich 300552db882fSDaniel Borkmann if (assocparams.sasoc_cookie_life != 0) 300652db882fSDaniel Borkmann asoc->cookie_life = ms_to_ktime(assocparams.sasoc_cookie_life); 30071da177e4SLinus Torvalds } else { 30081da177e4SLinus Torvalds /* Set the values to the endpoint */ 30091da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 30101da177e4SLinus Torvalds 30111da177e4SLinus Torvalds if (assocparams.sasoc_asocmaxrxt != 0) 30121da177e4SLinus Torvalds sp->assocparams.sasoc_asocmaxrxt = 30131da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt; 30141da177e4SLinus Torvalds if (assocparams.sasoc_cookie_life != 0) 30151da177e4SLinus Torvalds sp->assocparams.sasoc_cookie_life = 30161da177e4SLinus Torvalds assocparams.sasoc_cookie_life; 30171da177e4SLinus Torvalds } 30181da177e4SLinus Torvalds return 0; 30191da177e4SLinus Torvalds } 30201da177e4SLinus Torvalds 30211da177e4SLinus Torvalds /* 30221da177e4SLinus Torvalds * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 30231da177e4SLinus Torvalds * 30241da177e4SLinus Torvalds * This socket option is a boolean flag which turns on or off mapped V4 30251da177e4SLinus Torvalds * addresses. If this option is turned on and the socket is type 30261da177e4SLinus Torvalds * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 30271da177e4SLinus Torvalds * If this option is turned off, then no mapping will be done of V4 30281da177e4SLinus Torvalds * addresses and a user will receive both PF_INET6 and PF_INET type 30291da177e4SLinus Torvalds * addresses on the socket. 30301da177e4SLinus Torvalds */ 3031b7058842SDavid S. Miller static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen) 30321da177e4SLinus Torvalds { 30331da177e4SLinus Torvalds int val; 30341da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 30351da177e4SLinus Torvalds 30361da177e4SLinus Torvalds if (optlen < sizeof(int)) 30371da177e4SLinus Torvalds return -EINVAL; 30381da177e4SLinus Torvalds if (get_user(val, (int __user *)optval)) 30391da177e4SLinus Torvalds return -EFAULT; 30401da177e4SLinus Torvalds if (val) 30411da177e4SLinus Torvalds sp->v4mapped = 1; 30421da177e4SLinus Torvalds else 30431da177e4SLinus Torvalds sp->v4mapped = 0; 30441da177e4SLinus Torvalds 30451da177e4SLinus Torvalds return 0; 30461da177e4SLinus Torvalds } 30471da177e4SLinus Torvalds 30481da177e4SLinus Torvalds /* 3049e89c2095SWei Yongjun * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 3050e89c2095SWei Yongjun * This option will get or set the maximum size to put in any outgoing 3051e89c2095SWei Yongjun * SCTP DATA chunk. If a message is larger than this size it will be 30521da177e4SLinus Torvalds * fragmented by SCTP into the specified size. Note that the underlying 30531da177e4SLinus Torvalds * SCTP implementation may fragment into smaller sized chunks when the 30541da177e4SLinus Torvalds * PMTU of the underlying association is smaller than the value set by 3055e89c2095SWei Yongjun * the user. The default value for this option is '0' which indicates 3056e89c2095SWei Yongjun * the user is NOT limiting fragmentation and only the PMTU will effect 3057e89c2095SWei Yongjun * SCTP's choice of DATA chunk size. Note also that values set larger 3058e89c2095SWei Yongjun * than the maximum size of an IP datagram will effectively let SCTP 3059e89c2095SWei Yongjun * control fragmentation (i.e. the same as setting this option to 0). 3060e89c2095SWei Yongjun * 3061e89c2095SWei Yongjun * The following structure is used to access and modify this parameter: 3062e89c2095SWei Yongjun * 3063e89c2095SWei Yongjun * struct sctp_assoc_value { 3064e89c2095SWei Yongjun * sctp_assoc_t assoc_id; 3065e89c2095SWei Yongjun * uint32_t assoc_value; 3066e89c2095SWei Yongjun * }; 3067e89c2095SWei Yongjun * 3068e89c2095SWei Yongjun * assoc_id: This parameter is ignored for one-to-one style sockets. 3069e89c2095SWei Yongjun * For one-to-many style sockets this parameter indicates which 3070e89c2095SWei Yongjun * association the user is performing an action upon. Note that if 3071e89c2095SWei Yongjun * this field's value is zero then the endpoints default value is 3072e89c2095SWei Yongjun * changed (effecting future associations only). 3073e89c2095SWei Yongjun * assoc_value: This parameter specifies the maximum size in bytes. 30741da177e4SLinus Torvalds */ 3075b7058842SDavid S. Miller static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen) 30761da177e4SLinus Torvalds { 3077e89c2095SWei Yongjun struct sctp_assoc_value params; 30781da177e4SLinus Torvalds struct sctp_association *asoc; 30791da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 30801da177e4SLinus Torvalds int val; 30811da177e4SLinus Torvalds 3082e89c2095SWei Yongjun if (optlen == sizeof(int)) { 308394f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 3084f916ec96SNeil Horman "%s (pid %d) " 308594f65193SNeil Horman "Use of int in maxseg socket option.\n" 3086f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 3087f916ec96SNeil Horman current->comm, task_pid_nr(current)); 3088e89c2095SWei Yongjun if (copy_from_user(&val, optval, optlen)) 30891da177e4SLinus Torvalds return -EFAULT; 3090e89c2095SWei Yongjun params.assoc_id = 0; 3091e89c2095SWei Yongjun } else if (optlen == sizeof(struct sctp_assoc_value)) { 3092e89c2095SWei Yongjun if (copy_from_user(¶ms, optval, optlen)) 3093e89c2095SWei Yongjun return -EFAULT; 3094e89c2095SWei Yongjun val = params.assoc_value; 3095e89c2095SWei Yongjun } else 3096e89c2095SWei Yongjun return -EINVAL; 3097e89c2095SWei Yongjun 309896a33998SIvan Skytte Jorgensen if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))) 30991da177e4SLinus Torvalds return -EINVAL; 3100e89c2095SWei Yongjun 3101e89c2095SWei Yongjun asoc = sctp_id2assoc(sk, params.assoc_id); 3102e89c2095SWei Yongjun if (!asoc && params.assoc_id && sctp_style(sk, UDP)) 3103e89c2095SWei Yongjun return -EINVAL; 3104e89c2095SWei Yongjun 3105e89c2095SWei Yongjun if (asoc) { 3106e89c2095SWei Yongjun if (val == 0) { 3107e89c2095SWei Yongjun val = asoc->pathmtu; 3108e89c2095SWei Yongjun val -= sp->pf->af->net_header_len; 3109e89c2095SWei Yongjun val -= sizeof(struct sctphdr) + 3110e89c2095SWei Yongjun sizeof(struct sctp_data_chunk); 3111e89c2095SWei Yongjun } 3112f68b2e05SVlad Yasevich asoc->user_frag = val; 3113f68b2e05SVlad Yasevich asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu); 3114e89c2095SWei Yongjun } else { 31151da177e4SLinus Torvalds sp->user_frag = val; 3116e89c2095SWei Yongjun } 31171da177e4SLinus Torvalds 31181da177e4SLinus Torvalds return 0; 31191da177e4SLinus Torvalds } 31201da177e4SLinus Torvalds 31211da177e4SLinus Torvalds 31221da177e4SLinus Torvalds /* 31231da177e4SLinus Torvalds * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) 31241da177e4SLinus Torvalds * 31251da177e4SLinus Torvalds * Requests that the peer mark the enclosed address as the association 31261da177e4SLinus Torvalds * primary. The enclosed address must be one of the association's 31271da177e4SLinus Torvalds * locally bound addresses. The following structure is used to make a 31281da177e4SLinus Torvalds * set primary request: 31291da177e4SLinus Torvalds */ 31301da177e4SLinus Torvalds static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval, 3131b7058842SDavid S. Miller unsigned int optlen) 31321da177e4SLinus Torvalds { 3133e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 31341da177e4SLinus Torvalds struct sctp_sock *sp; 31351da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 31361da177e4SLinus Torvalds struct sctp_setpeerprim prim; 31371da177e4SLinus Torvalds struct sctp_chunk *chunk; 313840a01039SWei Yongjun struct sctp_af *af; 31391da177e4SLinus Torvalds int err; 31401da177e4SLinus Torvalds 31411da177e4SLinus Torvalds sp = sctp_sk(sk); 31421da177e4SLinus Torvalds 3143e1fc3b14SEric W. Biederman if (!net->sctp.addip_enable) 31441da177e4SLinus Torvalds return -EPERM; 31451da177e4SLinus Torvalds 31461da177e4SLinus Torvalds if (optlen != sizeof(struct sctp_setpeerprim)) 31471da177e4SLinus Torvalds return -EINVAL; 31481da177e4SLinus Torvalds 31491da177e4SLinus Torvalds if (copy_from_user(&prim, optval, optlen)) 31501da177e4SLinus Torvalds return -EFAULT; 31511da177e4SLinus Torvalds 31521da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, prim.sspp_assoc_id); 31531da177e4SLinus Torvalds if (!asoc) 31541da177e4SLinus Torvalds return -EINVAL; 31551da177e4SLinus Torvalds 31561da177e4SLinus Torvalds if (!asoc->peer.asconf_capable) 31571da177e4SLinus Torvalds return -EPERM; 31581da177e4SLinus Torvalds 31591da177e4SLinus Torvalds if (asoc->peer.addip_disabled_mask & SCTP_PARAM_SET_PRIMARY) 31601da177e4SLinus Torvalds return -EPERM; 31611da177e4SLinus Torvalds 31621da177e4SLinus Torvalds if (!sctp_state(asoc, ESTABLISHED)) 31631da177e4SLinus Torvalds return -ENOTCONN; 31641da177e4SLinus Torvalds 316540a01039SWei Yongjun af = sctp_get_af_specific(prim.sspp_addr.ss_family); 316640a01039SWei Yongjun if (!af) 316740a01039SWei Yongjun return -EINVAL; 316840a01039SWei Yongjun 316940a01039SWei Yongjun if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL)) 317040a01039SWei Yongjun return -EADDRNOTAVAIL; 317140a01039SWei Yongjun 31721da177e4SLinus Torvalds if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr)) 31731da177e4SLinus Torvalds return -EADDRNOTAVAIL; 31741da177e4SLinus Torvalds 31751da177e4SLinus Torvalds /* Create an ASCONF chunk with SET_PRIMARY parameter */ 31761da177e4SLinus Torvalds chunk = sctp_make_asconf_set_prim(asoc, 31771da177e4SLinus Torvalds (union sctp_addr *)&prim.sspp_addr); 31781da177e4SLinus Torvalds if (!chunk) 31791da177e4SLinus Torvalds return -ENOMEM; 31801da177e4SLinus Torvalds 31811da177e4SLinus Torvalds err = sctp_send_asconf(asoc, chunk); 31821da177e4SLinus Torvalds 3183bb33381dSDaniel Borkmann pr_debug("%s: we set peer primary addr primitively\n", __func__); 31841da177e4SLinus Torvalds 31851da177e4SLinus Torvalds return err; 31861da177e4SLinus Torvalds } 31871da177e4SLinus Torvalds 31880f3fffd8SIvan Skytte Jorgensen static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval, 3189b7058842SDavid S. Miller unsigned int optlen) 31901da177e4SLinus Torvalds { 31910f3fffd8SIvan Skytte Jorgensen struct sctp_setadaptation adaptation; 31921da177e4SLinus Torvalds 31930f3fffd8SIvan Skytte Jorgensen if (optlen != sizeof(struct sctp_setadaptation)) 31941da177e4SLinus Torvalds return -EINVAL; 31950f3fffd8SIvan Skytte Jorgensen if (copy_from_user(&adaptation, optval, optlen)) 31961da177e4SLinus Torvalds return -EFAULT; 31971da177e4SLinus Torvalds 31980f3fffd8SIvan Skytte Jorgensen sctp_sk(sk)->adaptation_ind = adaptation.ssb_adaptation_ind; 31991da177e4SLinus Torvalds 32001da177e4SLinus Torvalds return 0; 32011da177e4SLinus Torvalds } 32021da177e4SLinus Torvalds 32036ab792f5SIvan Skytte Jorgensen /* 32046ab792f5SIvan Skytte Jorgensen * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 32056ab792f5SIvan Skytte Jorgensen * 32066ab792f5SIvan Skytte Jorgensen * The context field in the sctp_sndrcvinfo structure is normally only 32076ab792f5SIvan Skytte Jorgensen * used when a failed message is retrieved holding the value that was 32086ab792f5SIvan Skytte Jorgensen * sent down on the actual send call. This option allows the setting of 32096ab792f5SIvan Skytte Jorgensen * a default context on an association basis that will be received on 32106ab792f5SIvan Skytte Jorgensen * reading messages from the peer. This is especially helpful in the 32116ab792f5SIvan Skytte Jorgensen * one-2-many model for an application to keep some reference to an 32126ab792f5SIvan Skytte Jorgensen * internal state machine that is processing messages on the 32136ab792f5SIvan Skytte Jorgensen * association. Note that the setting of this value only effects 32146ab792f5SIvan Skytte Jorgensen * received messages from the peer and does not effect the value that is 32156ab792f5SIvan Skytte Jorgensen * saved with outbound messages. 32166ab792f5SIvan Skytte Jorgensen */ 32176ab792f5SIvan Skytte Jorgensen static int sctp_setsockopt_context(struct sock *sk, char __user *optval, 3218b7058842SDavid S. Miller unsigned int optlen) 32196ab792f5SIvan Skytte Jorgensen { 32206ab792f5SIvan Skytte Jorgensen struct sctp_assoc_value params; 32216ab792f5SIvan Skytte Jorgensen struct sctp_sock *sp; 32226ab792f5SIvan Skytte Jorgensen struct sctp_association *asoc; 32236ab792f5SIvan Skytte Jorgensen 32246ab792f5SIvan Skytte Jorgensen if (optlen != sizeof(struct sctp_assoc_value)) 32256ab792f5SIvan Skytte Jorgensen return -EINVAL; 32266ab792f5SIvan Skytte Jorgensen if (copy_from_user(¶ms, optval, optlen)) 32276ab792f5SIvan Skytte Jorgensen return -EFAULT; 32286ab792f5SIvan Skytte Jorgensen 32296ab792f5SIvan Skytte Jorgensen sp = sctp_sk(sk); 32306ab792f5SIvan Skytte Jorgensen 32316ab792f5SIvan Skytte Jorgensen if (params.assoc_id != 0) { 32326ab792f5SIvan Skytte Jorgensen asoc = sctp_id2assoc(sk, params.assoc_id); 32336ab792f5SIvan Skytte Jorgensen if (!asoc) 32346ab792f5SIvan Skytte Jorgensen return -EINVAL; 32356ab792f5SIvan Skytte Jorgensen asoc->default_rcv_context = params.assoc_value; 32366ab792f5SIvan Skytte Jorgensen } else { 32376ab792f5SIvan Skytte Jorgensen sp->default_rcv_context = params.assoc_value; 32386ab792f5SIvan Skytte Jorgensen } 32396ab792f5SIvan Skytte Jorgensen 32406ab792f5SIvan Skytte Jorgensen return 0; 32416ab792f5SIvan Skytte Jorgensen } 32426ab792f5SIvan Skytte Jorgensen 3243b6e1331fSVlad Yasevich /* 3244b6e1331fSVlad Yasevich * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 3245b6e1331fSVlad Yasevich * 3246b6e1331fSVlad Yasevich * This options will at a minimum specify if the implementation is doing 3247b6e1331fSVlad Yasevich * fragmented interleave. Fragmented interleave, for a one to many 3248b6e1331fSVlad Yasevich * socket, is when subsequent calls to receive a message may return 3249b6e1331fSVlad Yasevich * parts of messages from different associations. Some implementations 3250b6e1331fSVlad Yasevich * may allow you to turn this value on or off. If so, when turned off, 3251b6e1331fSVlad Yasevich * no fragment interleave will occur (which will cause a head of line 3252b6e1331fSVlad Yasevich * blocking amongst multiple associations sharing the same one to many 3253b6e1331fSVlad Yasevich * socket). When this option is turned on, then each receive call may 3254b6e1331fSVlad Yasevich * come from a different association (thus the user must receive data 3255b6e1331fSVlad Yasevich * with the extended calls (e.g. sctp_recvmsg) to keep track of which 3256b6e1331fSVlad Yasevich * association each receive belongs to. 3257b6e1331fSVlad Yasevich * 3258b6e1331fSVlad Yasevich * This option takes a boolean value. A non-zero value indicates that 3259b6e1331fSVlad Yasevich * fragmented interleave is on. A value of zero indicates that 3260b6e1331fSVlad Yasevich * fragmented interleave is off. 3261b6e1331fSVlad Yasevich * 3262b6e1331fSVlad Yasevich * Note that it is important that an implementation that allows this 3263b6e1331fSVlad Yasevich * option to be turned on, have it off by default. Otherwise an unaware 3264b6e1331fSVlad Yasevich * application using the one to many model may become confused and act 3265b6e1331fSVlad Yasevich * incorrectly. 3266b6e1331fSVlad Yasevich */ 3267b6e1331fSVlad Yasevich static int sctp_setsockopt_fragment_interleave(struct sock *sk, 3268b6e1331fSVlad Yasevich char __user *optval, 3269b7058842SDavid S. Miller unsigned int optlen) 3270b6e1331fSVlad Yasevich { 3271b6e1331fSVlad Yasevich int val; 3272b6e1331fSVlad Yasevich 3273b6e1331fSVlad Yasevich if (optlen != sizeof(int)) 3274b6e1331fSVlad Yasevich return -EINVAL; 3275b6e1331fSVlad Yasevich if (get_user(val, (int __user *)optval)) 3276b6e1331fSVlad Yasevich return -EFAULT; 3277b6e1331fSVlad Yasevich 3278b6e1331fSVlad Yasevich sctp_sk(sk)->frag_interleave = (val == 0) ? 0 : 1; 3279b6e1331fSVlad Yasevich 3280b6e1331fSVlad Yasevich return 0; 3281b6e1331fSVlad Yasevich } 3282b6e1331fSVlad Yasevich 3283d49d91d7SVlad Yasevich /* 32848510b937SWei Yongjun * 8.1.21. Set or Get the SCTP Partial Delivery Point 3285d49d91d7SVlad Yasevich * (SCTP_PARTIAL_DELIVERY_POINT) 32868510b937SWei Yongjun * 3287d49d91d7SVlad Yasevich * This option will set or get the SCTP partial delivery point. This 3288d49d91d7SVlad Yasevich * point is the size of a message where the partial delivery API will be 3289d49d91d7SVlad Yasevich * invoked to help free up rwnd space for the peer. Setting this to a 32908510b937SWei Yongjun * lower value will cause partial deliveries to happen more often. The 3291d49d91d7SVlad Yasevich * calls argument is an integer that sets or gets the partial delivery 32928510b937SWei Yongjun * point. Note also that the call will fail if the user attempts to set 32938510b937SWei Yongjun * this value larger than the socket receive buffer size. 32948510b937SWei Yongjun * 32958510b937SWei Yongjun * Note that any single message having a length smaller than or equal to 32968510b937SWei Yongjun * the SCTP partial delivery point will be delivered in one single read 32978510b937SWei Yongjun * call as long as the user provided buffer is large enough to hold the 32988510b937SWei Yongjun * message. 3299d49d91d7SVlad Yasevich */ 3300d49d91d7SVlad Yasevich static int sctp_setsockopt_partial_delivery_point(struct sock *sk, 3301d49d91d7SVlad Yasevich char __user *optval, 3302b7058842SDavid S. Miller unsigned int optlen) 3303d49d91d7SVlad Yasevich { 3304d49d91d7SVlad Yasevich u32 val; 3305d49d91d7SVlad Yasevich 3306d49d91d7SVlad Yasevich if (optlen != sizeof(u32)) 3307d49d91d7SVlad Yasevich return -EINVAL; 3308d49d91d7SVlad Yasevich if (get_user(val, (int __user *)optval)) 3309d49d91d7SVlad Yasevich return -EFAULT; 3310d49d91d7SVlad Yasevich 33118510b937SWei Yongjun /* Note: We double the receive buffer from what the user sets 33128510b937SWei Yongjun * it to be, also initial rwnd is based on rcvbuf/2. 33138510b937SWei Yongjun */ 33148510b937SWei Yongjun if (val > (sk->sk_rcvbuf >> 1)) 33158510b937SWei Yongjun return -EINVAL; 33168510b937SWei Yongjun 3317d49d91d7SVlad Yasevich sctp_sk(sk)->pd_point = val; 3318d49d91d7SVlad Yasevich 3319d49d91d7SVlad Yasevich return 0; /* is this the right error code? */ 3320d49d91d7SVlad Yasevich } 3321d49d91d7SVlad Yasevich 332270331571SVlad Yasevich /* 332370331571SVlad Yasevich * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 332470331571SVlad Yasevich * 332570331571SVlad Yasevich * This option will allow a user to change the maximum burst of packets 332670331571SVlad Yasevich * that can be emitted by this association. Note that the default value 332770331571SVlad Yasevich * is 4, and some implementations may restrict this setting so that it 332870331571SVlad Yasevich * can only be lowered. 332970331571SVlad Yasevich * 333070331571SVlad Yasevich * NOTE: This text doesn't seem right. Do this on a socket basis with 333170331571SVlad Yasevich * future associations inheriting the socket value. 333270331571SVlad Yasevich */ 333370331571SVlad Yasevich static int sctp_setsockopt_maxburst(struct sock *sk, 333470331571SVlad Yasevich char __user *optval, 3335b7058842SDavid S. Miller unsigned int optlen) 333670331571SVlad Yasevich { 3337219b99a9SNeil Horman struct sctp_assoc_value params; 3338219b99a9SNeil Horman struct sctp_sock *sp; 3339219b99a9SNeil Horman struct sctp_association *asoc; 334070331571SVlad Yasevich int val; 3341219b99a9SNeil Horman int assoc_id = 0; 334270331571SVlad Yasevich 3343219b99a9SNeil Horman if (optlen == sizeof(int)) { 334494f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 3345f916ec96SNeil Horman "%s (pid %d) " 334694f65193SNeil Horman "Use of int in max_burst socket option deprecated.\n" 3347f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 3348f916ec96SNeil Horman current->comm, task_pid_nr(current)); 3349219b99a9SNeil Horman if (copy_from_user(&val, optval, optlen)) 335070331571SVlad Yasevich return -EFAULT; 3351219b99a9SNeil Horman } else if (optlen == sizeof(struct sctp_assoc_value)) { 3352219b99a9SNeil Horman if (copy_from_user(¶ms, optval, optlen)) 3353219b99a9SNeil Horman return -EFAULT; 3354219b99a9SNeil Horman val = params.assoc_value; 3355219b99a9SNeil Horman assoc_id = params.assoc_id; 3356219b99a9SNeil Horman } else 335770331571SVlad Yasevich return -EINVAL; 335870331571SVlad Yasevich 3359219b99a9SNeil Horman sp = sctp_sk(sk); 3360219b99a9SNeil Horman 3361219b99a9SNeil Horman if (assoc_id != 0) { 3362219b99a9SNeil Horman asoc = sctp_id2assoc(sk, assoc_id); 3363219b99a9SNeil Horman if (!asoc) 3364219b99a9SNeil Horman return -EINVAL; 3365219b99a9SNeil Horman asoc->max_burst = val; 3366219b99a9SNeil Horman } else 3367219b99a9SNeil Horman sp->max_burst = val; 336870331571SVlad Yasevich 336970331571SVlad Yasevich return 0; 337070331571SVlad Yasevich } 337170331571SVlad Yasevich 337265b07e5dSVlad Yasevich /* 337365b07e5dSVlad Yasevich * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) 337465b07e5dSVlad Yasevich * 337565b07e5dSVlad Yasevich * This set option adds a chunk type that the user is requesting to be 337665b07e5dSVlad Yasevich * received only in an authenticated way. Changes to the list of chunks 337765b07e5dSVlad Yasevich * will only effect future associations on the socket. 337865b07e5dSVlad Yasevich */ 337965b07e5dSVlad Yasevich static int sctp_setsockopt_auth_chunk(struct sock *sk, 338065b07e5dSVlad Yasevich char __user *optval, 3381b7058842SDavid S. Miller unsigned int optlen) 338265b07e5dSVlad Yasevich { 3383b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 338465b07e5dSVlad Yasevich struct sctp_authchunk val; 338565b07e5dSVlad Yasevich 3386b14878ccSVlad Yasevich if (!ep->auth_enable) 33875e739d17SVlad Yasevich return -EACCES; 33885e739d17SVlad Yasevich 338965b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authchunk)) 339065b07e5dSVlad Yasevich return -EINVAL; 339165b07e5dSVlad Yasevich if (copy_from_user(&val, optval, optlen)) 339265b07e5dSVlad Yasevich return -EFAULT; 339365b07e5dSVlad Yasevich 339465b07e5dSVlad Yasevich switch (val.sauth_chunk) { 339565b07e5dSVlad Yasevich case SCTP_CID_INIT: 339665b07e5dSVlad Yasevich case SCTP_CID_INIT_ACK: 339765b07e5dSVlad Yasevich case SCTP_CID_SHUTDOWN_COMPLETE: 339865b07e5dSVlad Yasevich case SCTP_CID_AUTH: 339965b07e5dSVlad Yasevich return -EINVAL; 340065b07e5dSVlad Yasevich } 340165b07e5dSVlad Yasevich 340265b07e5dSVlad Yasevich /* add this chunk id to the endpoint */ 3403b14878ccSVlad Yasevich return sctp_auth_ep_add_chunkid(ep, val.sauth_chunk); 340465b07e5dSVlad Yasevich } 340565b07e5dSVlad Yasevich 340665b07e5dSVlad Yasevich /* 340765b07e5dSVlad Yasevich * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) 340865b07e5dSVlad Yasevich * 340965b07e5dSVlad Yasevich * This option gets or sets the list of HMAC algorithms that the local 341065b07e5dSVlad Yasevich * endpoint requires the peer to use. 341165b07e5dSVlad Yasevich */ 341265b07e5dSVlad Yasevich static int sctp_setsockopt_hmac_ident(struct sock *sk, 341365b07e5dSVlad Yasevich char __user *optval, 3414b7058842SDavid S. Miller unsigned int optlen) 341565b07e5dSVlad Yasevich { 3416b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 341765b07e5dSVlad Yasevich struct sctp_hmacalgo *hmacs; 3418d9724055SVlad Yasevich u32 idents; 341965b07e5dSVlad Yasevich int err; 342065b07e5dSVlad Yasevich 3421b14878ccSVlad Yasevich if (!ep->auth_enable) 34225e739d17SVlad Yasevich return -EACCES; 34235e739d17SVlad Yasevich 342465b07e5dSVlad Yasevich if (optlen < sizeof(struct sctp_hmacalgo)) 342565b07e5dSVlad Yasevich return -EINVAL; 342665b07e5dSVlad Yasevich 3427934253a7SShan Wei hmacs = memdup_user(optval, optlen); 3428934253a7SShan Wei if (IS_ERR(hmacs)) 3429934253a7SShan Wei return PTR_ERR(hmacs); 343065b07e5dSVlad Yasevich 3431d9724055SVlad Yasevich idents = hmacs->shmac_num_idents; 3432d9724055SVlad Yasevich if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || 3433d9724055SVlad Yasevich (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) { 343465b07e5dSVlad Yasevich err = -EINVAL; 343565b07e5dSVlad Yasevich goto out; 343665b07e5dSVlad Yasevich } 343765b07e5dSVlad Yasevich 3438b14878ccSVlad Yasevich err = sctp_auth_ep_set_hmacs(ep, hmacs); 343965b07e5dSVlad Yasevich out: 344065b07e5dSVlad Yasevich kfree(hmacs); 344165b07e5dSVlad Yasevich return err; 344265b07e5dSVlad Yasevich } 344365b07e5dSVlad Yasevich 344465b07e5dSVlad Yasevich /* 344565b07e5dSVlad Yasevich * 7.1.20. Set a shared key (SCTP_AUTH_KEY) 344665b07e5dSVlad Yasevich * 344765b07e5dSVlad Yasevich * This option will set a shared secret key which is used to build an 344865b07e5dSVlad Yasevich * association shared key. 344965b07e5dSVlad Yasevich */ 345065b07e5dSVlad Yasevich static int sctp_setsockopt_auth_key(struct sock *sk, 345165b07e5dSVlad Yasevich char __user *optval, 3452b7058842SDavid S. Miller unsigned int optlen) 345365b07e5dSVlad Yasevich { 3454b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 345565b07e5dSVlad Yasevich struct sctp_authkey *authkey; 345665b07e5dSVlad Yasevich struct sctp_association *asoc; 345765b07e5dSVlad Yasevich int ret; 345865b07e5dSVlad Yasevich 3459b14878ccSVlad Yasevich if (!ep->auth_enable) 34605e739d17SVlad Yasevich return -EACCES; 34615e739d17SVlad Yasevich 346265b07e5dSVlad Yasevich if (optlen <= sizeof(struct sctp_authkey)) 346365b07e5dSVlad Yasevich return -EINVAL; 346465b07e5dSVlad Yasevich 3465934253a7SShan Wei authkey = memdup_user(optval, optlen); 3466934253a7SShan Wei if (IS_ERR(authkey)) 3467934253a7SShan Wei return PTR_ERR(authkey); 346865b07e5dSVlad Yasevich 3469328fc47eSVlad Yasevich if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { 347030c2235cSVlad Yasevich ret = -EINVAL; 347130c2235cSVlad Yasevich goto out; 347230c2235cSVlad Yasevich } 347330c2235cSVlad Yasevich 347465b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); 347565b07e5dSVlad Yasevich if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) { 347665b07e5dSVlad Yasevich ret = -EINVAL; 347765b07e5dSVlad Yasevich goto out; 347865b07e5dSVlad Yasevich } 347965b07e5dSVlad Yasevich 3480b14878ccSVlad Yasevich ret = sctp_auth_set_key(ep, asoc, authkey); 348165b07e5dSVlad Yasevich out: 34826ba542a2SDaniel Borkmann kzfree(authkey); 348365b07e5dSVlad Yasevich return ret; 348465b07e5dSVlad Yasevich } 348565b07e5dSVlad Yasevich 348665b07e5dSVlad Yasevich /* 348765b07e5dSVlad Yasevich * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) 348865b07e5dSVlad Yasevich * 348965b07e5dSVlad Yasevich * This option will get or set the active shared key to be used to build 349065b07e5dSVlad Yasevich * the association shared key. 349165b07e5dSVlad Yasevich */ 349265b07e5dSVlad Yasevich static int sctp_setsockopt_active_key(struct sock *sk, 349365b07e5dSVlad Yasevich char __user *optval, 3494b7058842SDavid S. Miller unsigned int optlen) 349565b07e5dSVlad Yasevich { 3496b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 349765b07e5dSVlad Yasevich struct sctp_authkeyid val; 349865b07e5dSVlad Yasevich struct sctp_association *asoc; 349965b07e5dSVlad Yasevich 3500b14878ccSVlad Yasevich if (!ep->auth_enable) 35015e739d17SVlad Yasevich return -EACCES; 35025e739d17SVlad Yasevich 350365b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authkeyid)) 350465b07e5dSVlad Yasevich return -EINVAL; 350565b07e5dSVlad Yasevich if (copy_from_user(&val, optval, optlen)) 350665b07e5dSVlad Yasevich return -EFAULT; 350765b07e5dSVlad Yasevich 350865b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 350965b07e5dSVlad Yasevich if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 351065b07e5dSVlad Yasevich return -EINVAL; 351165b07e5dSVlad Yasevich 3512b14878ccSVlad Yasevich return sctp_auth_set_active_key(ep, asoc, val.scact_keynumber); 351365b07e5dSVlad Yasevich } 351465b07e5dSVlad Yasevich 351565b07e5dSVlad Yasevich /* 351665b07e5dSVlad Yasevich * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY) 351765b07e5dSVlad Yasevich * 351865b07e5dSVlad Yasevich * This set option will delete a shared secret key from use. 351965b07e5dSVlad Yasevich */ 352065b07e5dSVlad Yasevich static int sctp_setsockopt_del_key(struct sock *sk, 352165b07e5dSVlad Yasevich char __user *optval, 3522b7058842SDavid S. Miller unsigned int optlen) 352365b07e5dSVlad Yasevich { 3524b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 352565b07e5dSVlad Yasevich struct sctp_authkeyid val; 352665b07e5dSVlad Yasevich struct sctp_association *asoc; 352765b07e5dSVlad Yasevich 3528b14878ccSVlad Yasevich if (!ep->auth_enable) 35295e739d17SVlad Yasevich return -EACCES; 35305e739d17SVlad Yasevich 353165b07e5dSVlad Yasevich if (optlen != sizeof(struct sctp_authkeyid)) 353265b07e5dSVlad Yasevich return -EINVAL; 353365b07e5dSVlad Yasevich if (copy_from_user(&val, optval, optlen)) 353465b07e5dSVlad Yasevich return -EFAULT; 353565b07e5dSVlad Yasevich 353665b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 353765b07e5dSVlad Yasevich if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 353865b07e5dSVlad Yasevich return -EINVAL; 353965b07e5dSVlad Yasevich 3540b14878ccSVlad Yasevich return sctp_auth_del_key_id(ep, asoc, val.scact_keynumber); 354165b07e5dSVlad Yasevich 354265b07e5dSVlad Yasevich } 354365b07e5dSVlad Yasevich 35447dc04d71SMichio Honda /* 35457dc04d71SMichio Honda * 8.1.23 SCTP_AUTO_ASCONF 35467dc04d71SMichio Honda * 35477dc04d71SMichio Honda * This option will enable or disable the use of the automatic generation of 35487dc04d71SMichio Honda * ASCONF chunks to add and delete addresses to an existing association. Note 35497dc04d71SMichio Honda * that this option has two caveats namely: a) it only affects sockets that 35507dc04d71SMichio Honda * are bound to all addresses available to the SCTP stack, and b) the system 35517dc04d71SMichio Honda * administrator may have an overriding control that turns the ASCONF feature 35527dc04d71SMichio Honda * off no matter what setting the socket option may have. 35537dc04d71SMichio Honda * This option expects an integer boolean flag, where a non-zero value turns on 35547dc04d71SMichio Honda * the option, and a zero value turns off the option. 35557dc04d71SMichio Honda * Note. In this implementation, socket operation overrides default parameter 35567dc04d71SMichio Honda * being set by sysctl as well as FreeBSD implementation 35577dc04d71SMichio Honda */ 35587dc04d71SMichio Honda static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, 35597dc04d71SMichio Honda unsigned int optlen) 35607dc04d71SMichio Honda { 35617dc04d71SMichio Honda int val; 35627dc04d71SMichio Honda struct sctp_sock *sp = sctp_sk(sk); 35637dc04d71SMichio Honda 35647dc04d71SMichio Honda if (optlen < sizeof(int)) 35657dc04d71SMichio Honda return -EINVAL; 35667dc04d71SMichio Honda if (get_user(val, (int __user *)optval)) 35677dc04d71SMichio Honda return -EFAULT; 35687dc04d71SMichio Honda if (!sctp_is_ep_boundall(sk) && val) 35697dc04d71SMichio Honda return -EINVAL; 35707dc04d71SMichio Honda if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf)) 35717dc04d71SMichio Honda return 0; 35727dc04d71SMichio Honda 35732d45a02dSMarcelo Ricardo Leitner spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock); 35747dc04d71SMichio Honda if (val == 0 && sp->do_auto_asconf) { 35757dc04d71SMichio Honda list_del(&sp->auto_asconf_list); 35767dc04d71SMichio Honda sp->do_auto_asconf = 0; 35777dc04d71SMichio Honda } else if (val && !sp->do_auto_asconf) { 35787dc04d71SMichio Honda list_add_tail(&sp->auto_asconf_list, 35794db67e80SEric W. Biederman &sock_net(sk)->sctp.auto_asconf_splist); 35807dc04d71SMichio Honda sp->do_auto_asconf = 1; 35817dc04d71SMichio Honda } 35822d45a02dSMarcelo Ricardo Leitner spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock); 35837dc04d71SMichio Honda return 0; 35847dc04d71SMichio Honda } 35857dc04d71SMichio Honda 35865aa93bcfSNeil Horman /* 35875aa93bcfSNeil Horman * SCTP_PEER_ADDR_THLDS 35885aa93bcfSNeil Horman * 35895aa93bcfSNeil Horman * This option allows us to alter the partially failed threshold for one or all 35905aa93bcfSNeil Horman * transports in an association. See Section 6.1 of: 35915aa93bcfSNeil Horman * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 35925aa93bcfSNeil Horman */ 35935aa93bcfSNeil Horman static int sctp_setsockopt_paddr_thresholds(struct sock *sk, 35945aa93bcfSNeil Horman char __user *optval, 35955aa93bcfSNeil Horman unsigned int optlen) 35965aa93bcfSNeil Horman { 35975aa93bcfSNeil Horman struct sctp_paddrthlds val; 35985aa93bcfSNeil Horman struct sctp_transport *trans; 35995aa93bcfSNeil Horman struct sctp_association *asoc; 36005aa93bcfSNeil Horman 36015aa93bcfSNeil Horman if (optlen < sizeof(struct sctp_paddrthlds)) 36025aa93bcfSNeil Horman return -EINVAL; 36035aa93bcfSNeil Horman if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, 36045aa93bcfSNeil Horman sizeof(struct sctp_paddrthlds))) 36055aa93bcfSNeil Horman return -EFAULT; 36065aa93bcfSNeil Horman 36075aa93bcfSNeil Horman 36085aa93bcfSNeil Horman if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { 36095aa93bcfSNeil Horman asoc = sctp_id2assoc(sk, val.spt_assoc_id); 36105aa93bcfSNeil Horman if (!asoc) 36115aa93bcfSNeil Horman return -ENOENT; 36125aa93bcfSNeil Horman list_for_each_entry(trans, &asoc->peer.transport_addr_list, 36135aa93bcfSNeil Horman transports) { 36145aa93bcfSNeil Horman if (val.spt_pathmaxrxt) 36155aa93bcfSNeil Horman trans->pathmaxrxt = val.spt_pathmaxrxt; 36165aa93bcfSNeil Horman trans->pf_retrans = val.spt_pathpfthld; 36175aa93bcfSNeil Horman } 36185aa93bcfSNeil Horman 36195aa93bcfSNeil Horman if (val.spt_pathmaxrxt) 36205aa93bcfSNeil Horman asoc->pathmaxrxt = val.spt_pathmaxrxt; 36215aa93bcfSNeil Horman asoc->pf_retrans = val.spt_pathpfthld; 36225aa93bcfSNeil Horman } else { 36235aa93bcfSNeil Horman trans = sctp_addr_id2transport(sk, &val.spt_address, 36245aa93bcfSNeil Horman val.spt_assoc_id); 36255aa93bcfSNeil Horman if (!trans) 36265aa93bcfSNeil Horman return -ENOENT; 36275aa93bcfSNeil Horman 36285aa93bcfSNeil Horman if (val.spt_pathmaxrxt) 36295aa93bcfSNeil Horman trans->pathmaxrxt = val.spt_pathmaxrxt; 36305aa93bcfSNeil Horman trans->pf_retrans = val.spt_pathpfthld; 36315aa93bcfSNeil Horman } 36325aa93bcfSNeil Horman 36335aa93bcfSNeil Horman return 0; 36345aa93bcfSNeil Horman } 36355aa93bcfSNeil Horman 36360d3a421dSGeir Ola Vaagland static int sctp_setsockopt_recvrcvinfo(struct sock *sk, 36370d3a421dSGeir Ola Vaagland char __user *optval, 36380d3a421dSGeir Ola Vaagland unsigned int optlen) 36390d3a421dSGeir Ola Vaagland { 36400d3a421dSGeir Ola Vaagland int val; 36410d3a421dSGeir Ola Vaagland 36420d3a421dSGeir Ola Vaagland if (optlen < sizeof(int)) 36430d3a421dSGeir Ola Vaagland return -EINVAL; 36440d3a421dSGeir Ola Vaagland if (get_user(val, (int __user *) optval)) 36450d3a421dSGeir Ola Vaagland return -EFAULT; 36460d3a421dSGeir Ola Vaagland 36470d3a421dSGeir Ola Vaagland sctp_sk(sk)->recvrcvinfo = (val == 0) ? 0 : 1; 36480d3a421dSGeir Ola Vaagland 36490d3a421dSGeir Ola Vaagland return 0; 36500d3a421dSGeir Ola Vaagland } 36510d3a421dSGeir Ola Vaagland 36522347c80fSGeir Ola Vaagland static int sctp_setsockopt_recvnxtinfo(struct sock *sk, 36532347c80fSGeir Ola Vaagland char __user *optval, 36542347c80fSGeir Ola Vaagland unsigned int optlen) 36552347c80fSGeir Ola Vaagland { 36562347c80fSGeir Ola Vaagland int val; 36572347c80fSGeir Ola Vaagland 36582347c80fSGeir Ola Vaagland if (optlen < sizeof(int)) 36592347c80fSGeir Ola Vaagland return -EINVAL; 36602347c80fSGeir Ola Vaagland if (get_user(val, (int __user *) optval)) 36612347c80fSGeir Ola Vaagland return -EFAULT; 36622347c80fSGeir Ola Vaagland 36632347c80fSGeir Ola Vaagland sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1; 36642347c80fSGeir Ola Vaagland 36652347c80fSGeir Ola Vaagland return 0; 36662347c80fSGeir Ola Vaagland } 36672347c80fSGeir Ola Vaagland 36681da177e4SLinus Torvalds /* API 6.2 setsockopt(), getsockopt() 36691da177e4SLinus Torvalds * 36701da177e4SLinus Torvalds * Applications use setsockopt() and getsockopt() to set or retrieve 36711da177e4SLinus Torvalds * socket options. Socket options are used to change the default 36721da177e4SLinus Torvalds * behavior of sockets calls. They are described in Section 7. 36731da177e4SLinus Torvalds * 36741da177e4SLinus Torvalds * The syntax is: 36751da177e4SLinus Torvalds * 36761da177e4SLinus Torvalds * ret = getsockopt(int sd, int level, int optname, void __user *optval, 36771da177e4SLinus Torvalds * int __user *optlen); 36781da177e4SLinus Torvalds * ret = setsockopt(int sd, int level, int optname, const void __user *optval, 36791da177e4SLinus Torvalds * int optlen); 36801da177e4SLinus Torvalds * 36811da177e4SLinus Torvalds * sd - the socket descript. 36821da177e4SLinus Torvalds * level - set to IPPROTO_SCTP for all SCTP options. 36831da177e4SLinus Torvalds * optname - the option name. 36841da177e4SLinus Torvalds * optval - the buffer to store the value of the option. 36851da177e4SLinus Torvalds * optlen - the size of the buffer. 36861da177e4SLinus Torvalds */ 3687dda91928SDaniel Borkmann static int sctp_setsockopt(struct sock *sk, int level, int optname, 3688b7058842SDavid S. Miller char __user *optval, unsigned int optlen) 36891da177e4SLinus Torvalds { 36901da177e4SLinus Torvalds int retval = 0; 36911da177e4SLinus Torvalds 3692bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 36931da177e4SLinus Torvalds 36941da177e4SLinus Torvalds /* I can hardly begin to describe how wrong this is. This is 36951da177e4SLinus Torvalds * so broken as to be worse than useless. The API draft 36961da177e4SLinus Torvalds * REALLY is NOT helpful here... I am not convinced that the 36971da177e4SLinus Torvalds * semantics of setsockopt() with a level OTHER THAN SOL_SCTP 36981da177e4SLinus Torvalds * are at all well-founded. 36991da177e4SLinus Torvalds */ 37001da177e4SLinus Torvalds if (level != SOL_SCTP) { 37011da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 37021da177e4SLinus Torvalds retval = af->setsockopt(sk, level, optname, optval, optlen); 37031da177e4SLinus Torvalds goto out_nounlock; 37041da177e4SLinus Torvalds } 37051da177e4SLinus Torvalds 3706048ed4b6Swangweidong lock_sock(sk); 37071da177e4SLinus Torvalds 37081da177e4SLinus Torvalds switch (optname) { 37091da177e4SLinus Torvalds case SCTP_SOCKOPT_BINDX_ADD: 37101da177e4SLinus Torvalds /* 'optlen' is the size of the addresses buffer. */ 37111da177e4SLinus Torvalds retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval, 37121da177e4SLinus Torvalds optlen, SCTP_BINDX_ADD_ADDR); 37131da177e4SLinus Torvalds break; 37141da177e4SLinus Torvalds 37151da177e4SLinus Torvalds case SCTP_SOCKOPT_BINDX_REM: 37161da177e4SLinus Torvalds /* 'optlen' is the size of the addresses buffer. */ 37171da177e4SLinus Torvalds retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval, 37181da177e4SLinus Torvalds optlen, SCTP_BINDX_REM_ADDR); 37191da177e4SLinus Torvalds break; 37201da177e4SLinus Torvalds 372188a0a948SVlad Yasevich case SCTP_SOCKOPT_CONNECTX_OLD: 372288a0a948SVlad Yasevich /* 'optlen' is the size of the addresses buffer. */ 372388a0a948SVlad Yasevich retval = sctp_setsockopt_connectx_old(sk, 372488a0a948SVlad Yasevich (struct sockaddr __user *)optval, 372588a0a948SVlad Yasevich optlen); 372688a0a948SVlad Yasevich break; 372788a0a948SVlad Yasevich 37283f7a87d2SFrank Filz case SCTP_SOCKOPT_CONNECTX: 37293f7a87d2SFrank Filz /* 'optlen' is the size of the addresses buffer. */ 373088a0a948SVlad Yasevich retval = sctp_setsockopt_connectx(sk, 373188a0a948SVlad Yasevich (struct sockaddr __user *)optval, 37323f7a87d2SFrank Filz optlen); 37333f7a87d2SFrank Filz break; 37343f7a87d2SFrank Filz 37351da177e4SLinus Torvalds case SCTP_DISABLE_FRAGMENTS: 37361da177e4SLinus Torvalds retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); 37371da177e4SLinus Torvalds break; 37381da177e4SLinus Torvalds 37391da177e4SLinus Torvalds case SCTP_EVENTS: 37401da177e4SLinus Torvalds retval = sctp_setsockopt_events(sk, optval, optlen); 37411da177e4SLinus Torvalds break; 37421da177e4SLinus Torvalds 37431da177e4SLinus Torvalds case SCTP_AUTOCLOSE: 37441da177e4SLinus Torvalds retval = sctp_setsockopt_autoclose(sk, optval, optlen); 37451da177e4SLinus Torvalds break; 37461da177e4SLinus Torvalds 37471da177e4SLinus Torvalds case SCTP_PEER_ADDR_PARAMS: 37481da177e4SLinus Torvalds retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen); 37491da177e4SLinus Torvalds break; 37501da177e4SLinus Torvalds 37514580ccc0SShan Wei case SCTP_DELAYED_SACK: 3752d364d927SWei Yongjun retval = sctp_setsockopt_delayed_ack(sk, optval, optlen); 37537708610bSFrank Filz break; 3754d49d91d7SVlad Yasevich case SCTP_PARTIAL_DELIVERY_POINT: 3755d49d91d7SVlad Yasevich retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen); 3756d49d91d7SVlad Yasevich break; 37577708610bSFrank Filz 37581da177e4SLinus Torvalds case SCTP_INITMSG: 37591da177e4SLinus Torvalds retval = sctp_setsockopt_initmsg(sk, optval, optlen); 37601da177e4SLinus Torvalds break; 37611da177e4SLinus Torvalds case SCTP_DEFAULT_SEND_PARAM: 37621da177e4SLinus Torvalds retval = sctp_setsockopt_default_send_param(sk, optval, 37631da177e4SLinus Torvalds optlen); 37641da177e4SLinus Torvalds break; 37656b3fd5f3SGeir Ola Vaagland case SCTP_DEFAULT_SNDINFO: 37666b3fd5f3SGeir Ola Vaagland retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen); 37676b3fd5f3SGeir Ola Vaagland break; 37681da177e4SLinus Torvalds case SCTP_PRIMARY_ADDR: 37691da177e4SLinus Torvalds retval = sctp_setsockopt_primary_addr(sk, optval, optlen); 37701da177e4SLinus Torvalds break; 37711da177e4SLinus Torvalds case SCTP_SET_PEER_PRIMARY_ADDR: 37721da177e4SLinus Torvalds retval = sctp_setsockopt_peer_primary_addr(sk, optval, optlen); 37731da177e4SLinus Torvalds break; 37741da177e4SLinus Torvalds case SCTP_NODELAY: 37751da177e4SLinus Torvalds retval = sctp_setsockopt_nodelay(sk, optval, optlen); 37761da177e4SLinus Torvalds break; 37771da177e4SLinus Torvalds case SCTP_RTOINFO: 37781da177e4SLinus Torvalds retval = sctp_setsockopt_rtoinfo(sk, optval, optlen); 37791da177e4SLinus Torvalds break; 37801da177e4SLinus Torvalds case SCTP_ASSOCINFO: 37811da177e4SLinus Torvalds retval = sctp_setsockopt_associnfo(sk, optval, optlen); 37821da177e4SLinus Torvalds break; 37831da177e4SLinus Torvalds case SCTP_I_WANT_MAPPED_V4_ADDR: 37841da177e4SLinus Torvalds retval = sctp_setsockopt_mappedv4(sk, optval, optlen); 37851da177e4SLinus Torvalds break; 37861da177e4SLinus Torvalds case SCTP_MAXSEG: 37871da177e4SLinus Torvalds retval = sctp_setsockopt_maxseg(sk, optval, optlen); 37881da177e4SLinus Torvalds break; 37890f3fffd8SIvan Skytte Jorgensen case SCTP_ADAPTATION_LAYER: 37900f3fffd8SIvan Skytte Jorgensen retval = sctp_setsockopt_adaptation_layer(sk, optval, optlen); 37911da177e4SLinus Torvalds break; 37926ab792f5SIvan Skytte Jorgensen case SCTP_CONTEXT: 37936ab792f5SIvan Skytte Jorgensen retval = sctp_setsockopt_context(sk, optval, optlen); 37946ab792f5SIvan Skytte Jorgensen break; 3795b6e1331fSVlad Yasevich case SCTP_FRAGMENT_INTERLEAVE: 3796b6e1331fSVlad Yasevich retval = sctp_setsockopt_fragment_interleave(sk, optval, optlen); 3797b6e1331fSVlad Yasevich break; 379870331571SVlad Yasevich case SCTP_MAX_BURST: 379970331571SVlad Yasevich retval = sctp_setsockopt_maxburst(sk, optval, optlen); 380070331571SVlad Yasevich break; 380165b07e5dSVlad Yasevich case SCTP_AUTH_CHUNK: 380265b07e5dSVlad Yasevich retval = sctp_setsockopt_auth_chunk(sk, optval, optlen); 380365b07e5dSVlad Yasevich break; 380465b07e5dSVlad Yasevich case SCTP_HMAC_IDENT: 380565b07e5dSVlad Yasevich retval = sctp_setsockopt_hmac_ident(sk, optval, optlen); 380665b07e5dSVlad Yasevich break; 380765b07e5dSVlad Yasevich case SCTP_AUTH_KEY: 380865b07e5dSVlad Yasevich retval = sctp_setsockopt_auth_key(sk, optval, optlen); 380965b07e5dSVlad Yasevich break; 381065b07e5dSVlad Yasevich case SCTP_AUTH_ACTIVE_KEY: 381165b07e5dSVlad Yasevich retval = sctp_setsockopt_active_key(sk, optval, optlen); 381265b07e5dSVlad Yasevich break; 381365b07e5dSVlad Yasevich case SCTP_AUTH_DELETE_KEY: 381465b07e5dSVlad Yasevich retval = sctp_setsockopt_del_key(sk, optval, optlen); 381565b07e5dSVlad Yasevich break; 38167dc04d71SMichio Honda case SCTP_AUTO_ASCONF: 38177dc04d71SMichio Honda retval = sctp_setsockopt_auto_asconf(sk, optval, optlen); 38187dc04d71SMichio Honda break; 38195aa93bcfSNeil Horman case SCTP_PEER_ADDR_THLDS: 38205aa93bcfSNeil Horman retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); 38215aa93bcfSNeil Horman break; 38220d3a421dSGeir Ola Vaagland case SCTP_RECVRCVINFO: 38230d3a421dSGeir Ola Vaagland retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); 38240d3a421dSGeir Ola Vaagland break; 38252347c80fSGeir Ola Vaagland case SCTP_RECVNXTINFO: 38262347c80fSGeir Ola Vaagland retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen); 38272347c80fSGeir Ola Vaagland break; 38281da177e4SLinus Torvalds default: 38291da177e4SLinus Torvalds retval = -ENOPROTOOPT; 38301da177e4SLinus Torvalds break; 38313ff50b79SStephen Hemminger } 38321da177e4SLinus Torvalds 3833048ed4b6Swangweidong release_sock(sk); 38341da177e4SLinus Torvalds 38351da177e4SLinus Torvalds out_nounlock: 38361da177e4SLinus Torvalds return retval; 38371da177e4SLinus Torvalds } 38381da177e4SLinus Torvalds 38391da177e4SLinus Torvalds /* API 3.1.6 connect() - UDP Style Syntax 38401da177e4SLinus Torvalds * 38411da177e4SLinus Torvalds * An application may use the connect() call in the UDP model to initiate an 38421da177e4SLinus Torvalds * association without sending data. 38431da177e4SLinus Torvalds * 38441da177e4SLinus Torvalds * The syntax is: 38451da177e4SLinus Torvalds * 38461da177e4SLinus Torvalds * ret = connect(int sd, const struct sockaddr *nam, socklen_t len); 38471da177e4SLinus Torvalds * 38481da177e4SLinus Torvalds * sd: the socket descriptor to have a new association added to. 38491da177e4SLinus Torvalds * 38501da177e4SLinus Torvalds * nam: the address structure (either struct sockaddr_in or struct 38511da177e4SLinus Torvalds * sockaddr_in6 defined in RFC2553 [7]). 38521da177e4SLinus Torvalds * 38531da177e4SLinus Torvalds * len: the size of the address. 38541da177e4SLinus Torvalds */ 3855dda91928SDaniel Borkmann static int sctp_connect(struct sock *sk, struct sockaddr *addr, 38561da177e4SLinus Torvalds int addr_len) 38571da177e4SLinus Torvalds { 38581da177e4SLinus Torvalds int err = 0; 38593f7a87d2SFrank Filz struct sctp_af *af; 38601da177e4SLinus Torvalds 3861048ed4b6Swangweidong lock_sock(sk); 38621da177e4SLinus Torvalds 3863bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk, 3864bb33381dSDaniel Borkmann addr, addr_len); 38651da177e4SLinus Torvalds 38663f7a87d2SFrank Filz /* Validate addr_len before calling common connect/connectx routine. */ 38673f7a87d2SFrank Filz af = sctp_get_af_specific(addr->sa_family); 38683f7a87d2SFrank Filz if (!af || addr_len < af->sockaddr_len) { 38693f7a87d2SFrank Filz err = -EINVAL; 38703f7a87d2SFrank Filz } else { 38713f7a87d2SFrank Filz /* Pass correct addr len to common routine (so it knows there 38723f7a87d2SFrank Filz * is only one address being passed. 38731da177e4SLinus Torvalds */ 387488a0a948SVlad Yasevich err = __sctp_connect(sk, addr, af->sockaddr_len, NULL); 38751da177e4SLinus Torvalds } 38761da177e4SLinus Torvalds 3877048ed4b6Swangweidong release_sock(sk); 38781da177e4SLinus Torvalds return err; 38791da177e4SLinus Torvalds } 38801da177e4SLinus Torvalds 38811da177e4SLinus Torvalds /* FIXME: Write comments. */ 3882dda91928SDaniel Borkmann static int sctp_disconnect(struct sock *sk, int flags) 38831da177e4SLinus Torvalds { 38841da177e4SLinus Torvalds return -EOPNOTSUPP; /* STUB */ 38851da177e4SLinus Torvalds } 38861da177e4SLinus Torvalds 38871da177e4SLinus Torvalds /* 4.1.4 accept() - TCP Style Syntax 38881da177e4SLinus Torvalds * 38891da177e4SLinus Torvalds * Applications use accept() call to remove an established SCTP 38901da177e4SLinus Torvalds * association from the accept queue of the endpoint. A new socket 38911da177e4SLinus Torvalds * descriptor will be returned from accept() to represent the newly 38921da177e4SLinus Torvalds * formed association. 38931da177e4SLinus Torvalds */ 3894dda91928SDaniel Borkmann static struct sock *sctp_accept(struct sock *sk, int flags, int *err) 38951da177e4SLinus Torvalds { 38961da177e4SLinus Torvalds struct sctp_sock *sp; 38971da177e4SLinus Torvalds struct sctp_endpoint *ep; 38981da177e4SLinus Torvalds struct sock *newsk = NULL; 38991da177e4SLinus Torvalds struct sctp_association *asoc; 39001da177e4SLinus Torvalds long timeo; 39011da177e4SLinus Torvalds int error = 0; 39021da177e4SLinus Torvalds 3903048ed4b6Swangweidong lock_sock(sk); 39041da177e4SLinus Torvalds 39051da177e4SLinus Torvalds sp = sctp_sk(sk); 39061da177e4SLinus Torvalds ep = sp->ep; 39071da177e4SLinus Torvalds 39081da177e4SLinus Torvalds if (!sctp_style(sk, TCP)) { 39091da177e4SLinus Torvalds error = -EOPNOTSUPP; 39101da177e4SLinus Torvalds goto out; 39111da177e4SLinus Torvalds } 39121da177e4SLinus Torvalds 39131da177e4SLinus Torvalds if (!sctp_sstate(sk, LISTENING)) { 39141da177e4SLinus Torvalds error = -EINVAL; 39151da177e4SLinus Torvalds goto out; 39161da177e4SLinus Torvalds } 39171da177e4SLinus Torvalds 39188abfedd8SSridhar Samudrala timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 39191da177e4SLinus Torvalds 39201da177e4SLinus Torvalds error = sctp_wait_for_accept(sk, timeo); 39211da177e4SLinus Torvalds if (error) 39221da177e4SLinus Torvalds goto out; 39231da177e4SLinus Torvalds 39241da177e4SLinus Torvalds /* We treat the list of associations on the endpoint as the accept 39251da177e4SLinus Torvalds * queue and pick the first association on the list. 39261da177e4SLinus Torvalds */ 39271da177e4SLinus Torvalds asoc = list_entry(ep->asocs.next, struct sctp_association, asocs); 39281da177e4SLinus Torvalds 39291da177e4SLinus Torvalds newsk = sp->pf->create_accept_sk(sk, asoc); 39301da177e4SLinus Torvalds if (!newsk) { 39311da177e4SLinus Torvalds error = -ENOMEM; 39321da177e4SLinus Torvalds goto out; 39331da177e4SLinus Torvalds } 39341da177e4SLinus Torvalds 39351da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the 39361da177e4SLinus Torvalds * asoc to the newsk. 39371da177e4SLinus Torvalds */ 39381da177e4SLinus Torvalds sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); 39391da177e4SLinus Torvalds 39401da177e4SLinus Torvalds out: 3941048ed4b6Swangweidong release_sock(sk); 39421da177e4SLinus Torvalds *err = error; 39431da177e4SLinus Torvalds return newsk; 39441da177e4SLinus Torvalds } 39451da177e4SLinus Torvalds 39461da177e4SLinus Torvalds /* The SCTP ioctl handler. */ 3947dda91928SDaniel Borkmann static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) 39481da177e4SLinus Torvalds { 394965040c33SDiego Elio 'Flameeyes' Pettenò int rc = -ENOTCONN; 395065040c33SDiego Elio 'Flameeyes' Pettenò 3951048ed4b6Swangweidong lock_sock(sk); 395265040c33SDiego Elio 'Flameeyes' Pettenò 395365040c33SDiego Elio 'Flameeyes' Pettenò /* 395465040c33SDiego Elio 'Flameeyes' Pettenò * SEQPACKET-style sockets in LISTENING state are valid, for 395565040c33SDiego Elio 'Flameeyes' Pettenò * SCTP, so only discard TCP-style sockets in LISTENING state. 395665040c33SDiego Elio 'Flameeyes' Pettenò */ 395765040c33SDiego Elio 'Flameeyes' Pettenò if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 395865040c33SDiego Elio 'Flameeyes' Pettenò goto out; 395965040c33SDiego Elio 'Flameeyes' Pettenò 396065040c33SDiego Elio 'Flameeyes' Pettenò switch (cmd) { 396165040c33SDiego Elio 'Flameeyes' Pettenò case SIOCINQ: { 396265040c33SDiego Elio 'Flameeyes' Pettenò struct sk_buff *skb; 396365040c33SDiego Elio 'Flameeyes' Pettenò unsigned int amount = 0; 396465040c33SDiego Elio 'Flameeyes' Pettenò 396565040c33SDiego Elio 'Flameeyes' Pettenò skb = skb_peek(&sk->sk_receive_queue); 396665040c33SDiego Elio 'Flameeyes' Pettenò if (skb != NULL) { 396765040c33SDiego Elio 'Flameeyes' Pettenò /* 396865040c33SDiego Elio 'Flameeyes' Pettenò * We will only return the amount of this packet since 396965040c33SDiego Elio 'Flameeyes' Pettenò * that is all that will be read. 397065040c33SDiego Elio 'Flameeyes' Pettenò */ 397165040c33SDiego Elio 'Flameeyes' Pettenò amount = skb->len; 397265040c33SDiego Elio 'Flameeyes' Pettenò } 397365040c33SDiego Elio 'Flameeyes' Pettenò rc = put_user(amount, (int __user *)arg); 397465040c33SDiego Elio 'Flameeyes' Pettenò break; 39759a7241c2SDavid S. Miller } 397665040c33SDiego Elio 'Flameeyes' Pettenò default: 397765040c33SDiego Elio 'Flameeyes' Pettenò rc = -ENOIOCTLCMD; 397865040c33SDiego Elio 'Flameeyes' Pettenò break; 397965040c33SDiego Elio 'Flameeyes' Pettenò } 398065040c33SDiego Elio 'Flameeyes' Pettenò out: 3981048ed4b6Swangweidong release_sock(sk); 398265040c33SDiego Elio 'Flameeyes' Pettenò return rc; 39831da177e4SLinus Torvalds } 39841da177e4SLinus Torvalds 39851da177e4SLinus Torvalds /* This is the function which gets called during socket creation to 39861da177e4SLinus Torvalds * initialized the SCTP-specific portion of the sock. 39871da177e4SLinus Torvalds * The sock structure should already be zero-filled memory. 39881da177e4SLinus Torvalds */ 3989dda91928SDaniel Borkmann static int sctp_init_sock(struct sock *sk) 39901da177e4SLinus Torvalds { 3991e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 39921da177e4SLinus Torvalds struct sctp_sock *sp; 39931da177e4SLinus Torvalds 3994bb33381dSDaniel Borkmann pr_debug("%s: sk:%p\n", __func__, sk); 39951da177e4SLinus Torvalds 39961da177e4SLinus Torvalds sp = sctp_sk(sk); 39971da177e4SLinus Torvalds 39981da177e4SLinus Torvalds /* Initialize the SCTP per socket area. */ 39991da177e4SLinus Torvalds switch (sk->sk_type) { 40001da177e4SLinus Torvalds case SOCK_SEQPACKET: 40011da177e4SLinus Torvalds sp->type = SCTP_SOCKET_UDP; 40021da177e4SLinus Torvalds break; 40031da177e4SLinus Torvalds case SOCK_STREAM: 40041da177e4SLinus Torvalds sp->type = SCTP_SOCKET_TCP; 40051da177e4SLinus Torvalds break; 40061da177e4SLinus Torvalds default: 40071da177e4SLinus Torvalds return -ESOCKTNOSUPPORT; 40081da177e4SLinus Torvalds } 40091da177e4SLinus Torvalds 40101da177e4SLinus Torvalds /* Initialize default send parameters. These parameters can be 40111da177e4SLinus Torvalds * modified with the SCTP_DEFAULT_SEND_PARAM socket option. 40121da177e4SLinus Torvalds */ 40131da177e4SLinus Torvalds sp->default_stream = 0; 40141da177e4SLinus Torvalds sp->default_ppid = 0; 40151da177e4SLinus Torvalds sp->default_flags = 0; 40161da177e4SLinus Torvalds sp->default_context = 0; 40171da177e4SLinus Torvalds sp->default_timetolive = 0; 40181da177e4SLinus Torvalds 40196ab792f5SIvan Skytte Jorgensen sp->default_rcv_context = 0; 4020e1fc3b14SEric W. Biederman sp->max_burst = net->sctp.max_burst; 40216ab792f5SIvan Skytte Jorgensen 40223c68198eSNeil Horman sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg; 40233c68198eSNeil Horman 40241da177e4SLinus Torvalds /* Initialize default setup parameters. These parameters 40251da177e4SLinus Torvalds * can be modified with the SCTP_INITMSG socket option or 40261da177e4SLinus Torvalds * overridden by the SCTP_INIT CMSG. 40271da177e4SLinus Torvalds */ 40281da177e4SLinus Torvalds sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; 40291da177e4SLinus Torvalds sp->initmsg.sinit_max_instreams = sctp_max_instreams; 4030e1fc3b14SEric W. Biederman sp->initmsg.sinit_max_attempts = net->sctp.max_retrans_init; 4031e1fc3b14SEric W. Biederman sp->initmsg.sinit_max_init_timeo = net->sctp.rto_max; 40321da177e4SLinus Torvalds 40331da177e4SLinus Torvalds /* Initialize default RTO related parameters. These parameters can 40341da177e4SLinus Torvalds * be modified for with the SCTP_RTOINFO socket option. 40351da177e4SLinus Torvalds */ 4036e1fc3b14SEric W. Biederman sp->rtoinfo.srto_initial = net->sctp.rto_initial; 4037e1fc3b14SEric W. Biederman sp->rtoinfo.srto_max = net->sctp.rto_max; 4038e1fc3b14SEric W. Biederman sp->rtoinfo.srto_min = net->sctp.rto_min; 40391da177e4SLinus Torvalds 40401da177e4SLinus Torvalds /* Initialize default association related parameters. These parameters 40411da177e4SLinus Torvalds * can be modified with the SCTP_ASSOCINFO socket option. 40421da177e4SLinus Torvalds */ 4043e1fc3b14SEric W. Biederman sp->assocparams.sasoc_asocmaxrxt = net->sctp.max_retrans_association; 40441da177e4SLinus Torvalds sp->assocparams.sasoc_number_peer_destinations = 0; 40451da177e4SLinus Torvalds sp->assocparams.sasoc_peer_rwnd = 0; 40461da177e4SLinus Torvalds sp->assocparams.sasoc_local_rwnd = 0; 4047e1fc3b14SEric W. Biederman sp->assocparams.sasoc_cookie_life = net->sctp.valid_cookie_life; 40481da177e4SLinus Torvalds 40491da177e4SLinus Torvalds /* Initialize default event subscriptions. By default, all the 40501da177e4SLinus Torvalds * options are off. 40511da177e4SLinus Torvalds */ 40521da177e4SLinus Torvalds memset(&sp->subscribe, 0, sizeof(struct sctp_event_subscribe)); 40531da177e4SLinus Torvalds 40541da177e4SLinus Torvalds /* Default Peer Address Parameters. These defaults can 40551da177e4SLinus Torvalds * be modified via SCTP_PEER_ADDR_PARAMS 40561da177e4SLinus Torvalds */ 4057e1fc3b14SEric W. Biederman sp->hbinterval = net->sctp.hb_interval; 4058e1fc3b14SEric W. Biederman sp->pathmaxrxt = net->sctp.max_retrans_path; 40594e2d52bfSwangweidong sp->pathmtu = 0; /* allow default discovery */ 4060e1fc3b14SEric W. Biederman sp->sackdelay = net->sctp.sack_timeout; 40617bfe8bdbSVlad Yasevich sp->sackfreq = 2; 406252ccb8e9SFrank Filz sp->param_flags = SPP_HB_ENABLE | 406352ccb8e9SFrank Filz SPP_PMTUD_ENABLE | 406452ccb8e9SFrank Filz SPP_SACKDELAY_ENABLE; 40651da177e4SLinus Torvalds 40661da177e4SLinus Torvalds /* If enabled no SCTP message fragmentation will be performed. 40671da177e4SLinus Torvalds * Configure through SCTP_DISABLE_FRAGMENTS socket option. 40681da177e4SLinus Torvalds */ 40691da177e4SLinus Torvalds sp->disable_fragments = 0; 40701da177e4SLinus Torvalds 4071208edef6SSridhar Samudrala /* Enable Nagle algorithm by default. */ 4072208edef6SSridhar Samudrala sp->nodelay = 0; 40731da177e4SLinus Torvalds 40740d3a421dSGeir Ola Vaagland sp->recvrcvinfo = 0; 40752347c80fSGeir Ola Vaagland sp->recvnxtinfo = 0; 40760d3a421dSGeir Ola Vaagland 40771da177e4SLinus Torvalds /* Enable by default. */ 40781da177e4SLinus Torvalds sp->v4mapped = 1; 40791da177e4SLinus Torvalds 40801da177e4SLinus Torvalds /* Auto-close idle associations after the configured 40811da177e4SLinus Torvalds * number of seconds. A value of 0 disables this 40821da177e4SLinus Torvalds * feature. Configure through the SCTP_AUTOCLOSE socket option, 40831da177e4SLinus Torvalds * for UDP-style sockets only. 40841da177e4SLinus Torvalds */ 40851da177e4SLinus Torvalds sp->autoclose = 0; 40861da177e4SLinus Torvalds 40871da177e4SLinus Torvalds /* User specified fragmentation limit. */ 40881da177e4SLinus Torvalds sp->user_frag = 0; 40891da177e4SLinus Torvalds 40900f3fffd8SIvan Skytte Jorgensen sp->adaptation_ind = 0; 40911da177e4SLinus Torvalds 40921da177e4SLinus Torvalds sp->pf = sctp_get_pf_specific(sk->sk_family); 40931da177e4SLinus Torvalds 40941da177e4SLinus Torvalds /* Control variables for partial data delivery. */ 4095b6e1331fSVlad Yasevich atomic_set(&sp->pd_mode, 0); 40961da177e4SLinus Torvalds skb_queue_head_init(&sp->pd_lobby); 4097b6e1331fSVlad Yasevich sp->frag_interleave = 0; 40981da177e4SLinus Torvalds 40991da177e4SLinus Torvalds /* Create a per socket endpoint structure. Even if we 41001da177e4SLinus Torvalds * change the data structure relationships, this may still 41011da177e4SLinus Torvalds * be useful for storing pre-connect address information. 41021da177e4SLinus Torvalds */ 4103c164b838SDaniel Borkmann sp->ep = sctp_endpoint_new(sk, GFP_KERNEL); 4104c164b838SDaniel Borkmann if (!sp->ep) 41051da177e4SLinus Torvalds return -ENOMEM; 41061da177e4SLinus Torvalds 41071da177e4SLinus Torvalds sp->hmac = NULL; 41081da177e4SLinus Torvalds 41090a2fbac1SDaniel Borkmann sk->sk_destruct = sctp_destruct_sock; 41100a2fbac1SDaniel Borkmann 41111da177e4SLinus Torvalds SCTP_DBG_OBJCNT_INC(sock); 41126f756a8cSDavid S. Miller 41136f756a8cSDavid S. Miller local_bh_disable(); 411481419d86SVlad Yasevich percpu_counter_inc(&sctp_sockets_allocated); 4115e1fc3b14SEric W. Biederman sock_prot_inuse_add(net, sk->sk_prot, 1); 41162d45a02dSMarcelo Ricardo Leitner 41172d45a02dSMarcelo Ricardo Leitner /* Nothing can fail after this block, otherwise 41182d45a02dSMarcelo Ricardo Leitner * sctp_destroy_sock() will be called without addr_wq_lock held 41192d45a02dSMarcelo Ricardo Leitner */ 4120e1fc3b14SEric W. Biederman if (net->sctp.default_auto_asconf) { 41212d45a02dSMarcelo Ricardo Leitner spin_lock(&sock_net(sk)->sctp.addr_wq_lock); 41229f7d653bSMichio Honda list_add_tail(&sp->auto_asconf_list, 4123e1fc3b14SEric W. Biederman &net->sctp.auto_asconf_splist); 41249f7d653bSMichio Honda sp->do_auto_asconf = 1; 41252d45a02dSMarcelo Ricardo Leitner spin_unlock(&sock_net(sk)->sctp.addr_wq_lock); 41262d45a02dSMarcelo Ricardo Leitner } else { 41279f7d653bSMichio Honda sp->do_auto_asconf = 0; 41282d45a02dSMarcelo Ricardo Leitner } 41292d45a02dSMarcelo Ricardo Leitner 41306f756a8cSDavid S. Miller local_bh_enable(); 41316f756a8cSDavid S. Miller 41321da177e4SLinus Torvalds return 0; 41331da177e4SLinus Torvalds } 41341da177e4SLinus Torvalds 41352d45a02dSMarcelo Ricardo Leitner /* Cleanup any SCTP per socket resources. Must be called with 41362d45a02dSMarcelo Ricardo Leitner * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true 41372d45a02dSMarcelo Ricardo Leitner */ 4138dda91928SDaniel Borkmann static void sctp_destroy_sock(struct sock *sk) 41391da177e4SLinus Torvalds { 41409f7d653bSMichio Honda struct sctp_sock *sp; 41411da177e4SLinus Torvalds 4142bb33381dSDaniel Borkmann pr_debug("%s: sk:%p\n", __func__, sk); 41431da177e4SLinus Torvalds 41441da177e4SLinus Torvalds /* Release our hold on the endpoint. */ 41459f7d653bSMichio Honda sp = sctp_sk(sk); 41461abd165eSDaniel Borkmann /* This could happen during socket init, thus we bail out 41471abd165eSDaniel Borkmann * early, since the rest of the below is not setup either. 41481abd165eSDaniel Borkmann */ 41491abd165eSDaniel Borkmann if (sp->ep == NULL) 41501abd165eSDaniel Borkmann return; 41511abd165eSDaniel Borkmann 41529f7d653bSMichio Honda if (sp->do_auto_asconf) { 41539f7d653bSMichio Honda sp->do_auto_asconf = 0; 41549f7d653bSMichio Honda list_del(&sp->auto_asconf_list); 41559f7d653bSMichio Honda } 41569f7d653bSMichio Honda sctp_endpoint_free(sp->ep); 41575bc0b3bfSEric Dumazet local_bh_disable(); 415881419d86SVlad Yasevich percpu_counter_dec(&sctp_sockets_allocated); 41599a57f7faSEric Dumazet sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 41605bc0b3bfSEric Dumazet local_bh_enable(); 41611da177e4SLinus Torvalds } 41621da177e4SLinus Torvalds 41630a2fbac1SDaniel Borkmann /* Triggered when there are no references on the socket anymore */ 41640a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk) 41650a2fbac1SDaniel Borkmann { 41660a2fbac1SDaniel Borkmann struct sctp_sock *sp = sctp_sk(sk); 41670a2fbac1SDaniel Borkmann 41680a2fbac1SDaniel Borkmann /* Free up the HMAC transform. */ 41690a2fbac1SDaniel Borkmann crypto_free_hash(sp->hmac); 41700a2fbac1SDaniel Borkmann 41710a2fbac1SDaniel Borkmann inet_sock_destruct(sk); 41720a2fbac1SDaniel Borkmann } 41730a2fbac1SDaniel Borkmann 41741da177e4SLinus Torvalds /* API 4.1.7 shutdown() - TCP Style Syntax 41751da177e4SLinus Torvalds * int shutdown(int socket, int how); 41761da177e4SLinus Torvalds * 41771da177e4SLinus Torvalds * sd - the socket descriptor of the association to be closed. 41781da177e4SLinus Torvalds * how - Specifies the type of shutdown. The values are 41791da177e4SLinus Torvalds * as follows: 41801da177e4SLinus Torvalds * SHUT_RD 41811da177e4SLinus Torvalds * Disables further receive operations. No SCTP 41821da177e4SLinus Torvalds * protocol action is taken. 41831da177e4SLinus Torvalds * SHUT_WR 41841da177e4SLinus Torvalds * Disables further send operations, and initiates 41851da177e4SLinus Torvalds * the SCTP shutdown sequence. 41861da177e4SLinus Torvalds * SHUT_RDWR 41871da177e4SLinus Torvalds * Disables further send and receive operations 41881da177e4SLinus Torvalds * and initiates the SCTP shutdown sequence. 41891da177e4SLinus Torvalds */ 4190dda91928SDaniel Borkmann static void sctp_shutdown(struct sock *sk, int how) 41911da177e4SLinus Torvalds { 419255e26eb9SEric W. Biederman struct net *net = sock_net(sk); 41931da177e4SLinus Torvalds struct sctp_endpoint *ep; 41941da177e4SLinus Torvalds struct sctp_association *asoc; 41951da177e4SLinus Torvalds 41961da177e4SLinus Torvalds if (!sctp_style(sk, TCP)) 41971da177e4SLinus Torvalds return; 41981da177e4SLinus Torvalds 41991da177e4SLinus Torvalds if (how & SEND_SHUTDOWN) { 42001da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 42011da177e4SLinus Torvalds if (!list_empty(&ep->asocs)) { 42021da177e4SLinus Torvalds asoc = list_entry(ep->asocs.next, 42031da177e4SLinus Torvalds struct sctp_association, asocs); 420455e26eb9SEric W. Biederman sctp_primitive_SHUTDOWN(net, asoc, NULL); 42051da177e4SLinus Torvalds } 42061da177e4SLinus Torvalds } 42071da177e4SLinus Torvalds } 42081da177e4SLinus Torvalds 42091da177e4SLinus Torvalds /* 7.2.1 Association Status (SCTP_STATUS) 42101da177e4SLinus Torvalds 42111da177e4SLinus Torvalds * Applications can retrieve current status information about an 42121da177e4SLinus Torvalds * association, including association state, peer receiver window size, 42131da177e4SLinus Torvalds * number of unacked data chunks, and number of data chunks pending 42141da177e4SLinus Torvalds * receipt. This information is read-only. 42151da177e4SLinus Torvalds */ 42161da177e4SLinus Torvalds static int sctp_getsockopt_sctp_status(struct sock *sk, int len, 42171da177e4SLinus Torvalds char __user *optval, 42181da177e4SLinus Torvalds int __user *optlen) 42191da177e4SLinus Torvalds { 42201da177e4SLinus Torvalds struct sctp_status status; 42211da177e4SLinus Torvalds struct sctp_association *asoc = NULL; 42221da177e4SLinus Torvalds struct sctp_transport *transport; 42231da177e4SLinus Torvalds sctp_assoc_t associd; 42241da177e4SLinus Torvalds int retval = 0; 42251da177e4SLinus Torvalds 4226408f22e8SNeil Horman if (len < sizeof(status)) { 42271da177e4SLinus Torvalds retval = -EINVAL; 42281da177e4SLinus Torvalds goto out; 42291da177e4SLinus Torvalds } 42301da177e4SLinus Torvalds 4231408f22e8SNeil Horman len = sizeof(status); 4232408f22e8SNeil Horman if (copy_from_user(&status, optval, len)) { 42331da177e4SLinus Torvalds retval = -EFAULT; 42341da177e4SLinus Torvalds goto out; 42351da177e4SLinus Torvalds } 42361da177e4SLinus Torvalds 42371da177e4SLinus Torvalds associd = status.sstat_assoc_id; 42381da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, associd); 42391da177e4SLinus Torvalds if (!asoc) { 42401da177e4SLinus Torvalds retval = -EINVAL; 42411da177e4SLinus Torvalds goto out; 42421da177e4SLinus Torvalds } 42431da177e4SLinus Torvalds 42441da177e4SLinus Torvalds transport = asoc->peer.primary_path; 42451da177e4SLinus Torvalds 42461da177e4SLinus Torvalds status.sstat_assoc_id = sctp_assoc2id(asoc); 424738ab1fa9SDaniel Borkmann status.sstat_state = sctp_assoc_to_state(asoc); 42481da177e4SLinus Torvalds status.sstat_rwnd = asoc->peer.rwnd; 42491da177e4SLinus Torvalds status.sstat_unackdata = asoc->unack_data; 42501da177e4SLinus Torvalds 42511da177e4SLinus Torvalds status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 42521da177e4SLinus Torvalds status.sstat_instrms = asoc->c.sinit_max_instreams; 42531da177e4SLinus Torvalds status.sstat_outstrms = asoc->c.sinit_num_ostreams; 42541da177e4SLinus Torvalds status.sstat_fragmentation_point = asoc->frag_point; 42551da177e4SLinus Torvalds status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 42568cec6b80SAl Viro memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, 42578cec6b80SAl Viro transport->af_specific->sockaddr_len); 42581da177e4SLinus Torvalds /* Map ipv4 address into v4-mapped-on-v6 address. */ 4259299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), 42601da177e4SLinus Torvalds (union sctp_addr *)&status.sstat_primary.spinfo_address); 42613f7a87d2SFrank Filz status.sstat_primary.spinfo_state = transport->state; 42621da177e4SLinus Torvalds status.sstat_primary.spinfo_cwnd = transport->cwnd; 42631da177e4SLinus Torvalds status.sstat_primary.spinfo_srtt = transport->srtt; 42641da177e4SLinus Torvalds status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto); 426552ccb8e9SFrank Filz status.sstat_primary.spinfo_mtu = transport->pathmtu; 42661da177e4SLinus Torvalds 42673f7a87d2SFrank Filz if (status.sstat_primary.spinfo_state == SCTP_UNKNOWN) 42683f7a87d2SFrank Filz status.sstat_primary.spinfo_state = SCTP_ACTIVE; 42693f7a87d2SFrank Filz 42701da177e4SLinus Torvalds if (put_user(len, optlen)) { 42711da177e4SLinus Torvalds retval = -EFAULT; 42721da177e4SLinus Torvalds goto out; 42731da177e4SLinus Torvalds } 42741da177e4SLinus Torvalds 4275bb33381dSDaniel Borkmann pr_debug("%s: len:%d, state:%d, rwnd:%d, assoc_id:%d\n", 4276bb33381dSDaniel Borkmann __func__, len, status.sstat_state, status.sstat_rwnd, 42771da177e4SLinus Torvalds status.sstat_assoc_id); 42781da177e4SLinus Torvalds 42791da177e4SLinus Torvalds if (copy_to_user(optval, &status, len)) { 42801da177e4SLinus Torvalds retval = -EFAULT; 42811da177e4SLinus Torvalds goto out; 42821da177e4SLinus Torvalds } 42831da177e4SLinus Torvalds 42841da177e4SLinus Torvalds out: 4285a02cec21SEric Dumazet return retval; 42861da177e4SLinus Torvalds } 42871da177e4SLinus Torvalds 42881da177e4SLinus Torvalds 42891da177e4SLinus Torvalds /* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO) 42901da177e4SLinus Torvalds * 42911da177e4SLinus Torvalds * Applications can retrieve information about a specific peer address 42921da177e4SLinus Torvalds * of an association, including its reachability state, congestion 42931da177e4SLinus Torvalds * window, and retransmission timer values. This information is 42941da177e4SLinus Torvalds * read-only. 42951da177e4SLinus Torvalds */ 42961da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, 42971da177e4SLinus Torvalds char __user *optval, 42981da177e4SLinus Torvalds int __user *optlen) 42991da177e4SLinus Torvalds { 43001da177e4SLinus Torvalds struct sctp_paddrinfo pinfo; 43011da177e4SLinus Torvalds struct sctp_transport *transport; 43021da177e4SLinus Torvalds int retval = 0; 43031da177e4SLinus Torvalds 4304408f22e8SNeil Horman if (len < sizeof(pinfo)) { 43051da177e4SLinus Torvalds retval = -EINVAL; 43061da177e4SLinus Torvalds goto out; 43071da177e4SLinus Torvalds } 43081da177e4SLinus Torvalds 4309408f22e8SNeil Horman len = sizeof(pinfo); 4310408f22e8SNeil Horman if (copy_from_user(&pinfo, optval, len)) { 43111da177e4SLinus Torvalds retval = -EFAULT; 43121da177e4SLinus Torvalds goto out; 43131da177e4SLinus Torvalds } 43141da177e4SLinus Torvalds 43151da177e4SLinus Torvalds transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address, 43161da177e4SLinus Torvalds pinfo.spinfo_assoc_id); 43171da177e4SLinus Torvalds if (!transport) 43181da177e4SLinus Torvalds return -EINVAL; 43191da177e4SLinus Torvalds 43201da177e4SLinus Torvalds pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 43213f7a87d2SFrank Filz pinfo.spinfo_state = transport->state; 43221da177e4SLinus Torvalds pinfo.spinfo_cwnd = transport->cwnd; 43231da177e4SLinus Torvalds pinfo.spinfo_srtt = transport->srtt; 43241da177e4SLinus Torvalds pinfo.spinfo_rto = jiffies_to_msecs(transport->rto); 432552ccb8e9SFrank Filz pinfo.spinfo_mtu = transport->pathmtu; 43261da177e4SLinus Torvalds 43273f7a87d2SFrank Filz if (pinfo.spinfo_state == SCTP_UNKNOWN) 43283f7a87d2SFrank Filz pinfo.spinfo_state = SCTP_ACTIVE; 43293f7a87d2SFrank Filz 43301da177e4SLinus Torvalds if (put_user(len, optlen)) { 43311da177e4SLinus Torvalds retval = -EFAULT; 43321da177e4SLinus Torvalds goto out; 43331da177e4SLinus Torvalds } 43341da177e4SLinus Torvalds 43351da177e4SLinus Torvalds if (copy_to_user(optval, &pinfo, len)) { 43361da177e4SLinus Torvalds retval = -EFAULT; 43371da177e4SLinus Torvalds goto out; 43381da177e4SLinus Torvalds } 43391da177e4SLinus Torvalds 43401da177e4SLinus Torvalds out: 4341a02cec21SEric Dumazet return retval; 43421da177e4SLinus Torvalds } 43431da177e4SLinus Torvalds 43441da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) 43451da177e4SLinus Torvalds * 43461da177e4SLinus Torvalds * This option is a on/off flag. If enabled no SCTP message 43471da177e4SLinus Torvalds * fragmentation will be performed. Instead if a message being sent 43481da177e4SLinus Torvalds * exceeds the current PMTU size, the message will NOT be sent and 43491da177e4SLinus Torvalds * instead a error will be indicated to the user. 43501da177e4SLinus Torvalds */ 43511da177e4SLinus Torvalds static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, 43521da177e4SLinus Torvalds char __user *optval, int __user *optlen) 43531da177e4SLinus Torvalds { 43541da177e4SLinus Torvalds int val; 43551da177e4SLinus Torvalds 43561da177e4SLinus Torvalds if (len < sizeof(int)) 43571da177e4SLinus Torvalds return -EINVAL; 43581da177e4SLinus Torvalds 43591da177e4SLinus Torvalds len = sizeof(int); 43601da177e4SLinus Torvalds val = (sctp_sk(sk)->disable_fragments == 1); 43611da177e4SLinus Torvalds if (put_user(len, optlen)) 43621da177e4SLinus Torvalds return -EFAULT; 43631da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 43641da177e4SLinus Torvalds return -EFAULT; 43651da177e4SLinus Torvalds return 0; 43661da177e4SLinus Torvalds } 43671da177e4SLinus Torvalds 43681da177e4SLinus Torvalds /* 7.1.15 Set notification and ancillary events (SCTP_EVENTS) 43691da177e4SLinus Torvalds * 43701da177e4SLinus Torvalds * This socket option is used to specify various notifications and 43711da177e4SLinus Torvalds * ancillary data the user wishes to receive. 43721da177e4SLinus Torvalds */ 43731da177e4SLinus Torvalds static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, 43741da177e4SLinus Torvalds int __user *optlen) 43751da177e4SLinus Torvalds { 4376acdd5985SThomas Graf if (len <= 0) 43771da177e4SLinus Torvalds return -EINVAL; 4378acdd5985SThomas Graf if (len > sizeof(struct sctp_event_subscribe)) 4379408f22e8SNeil Horman len = sizeof(struct sctp_event_subscribe); 4380408f22e8SNeil Horman if (put_user(len, optlen)) 4381408f22e8SNeil Horman return -EFAULT; 43821da177e4SLinus Torvalds if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len)) 43831da177e4SLinus Torvalds return -EFAULT; 43841da177e4SLinus Torvalds return 0; 43851da177e4SLinus Torvalds } 43861da177e4SLinus Torvalds 43871da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) 43881da177e4SLinus Torvalds * 43891da177e4SLinus Torvalds * This socket option is applicable to the UDP-style socket only. When 43901da177e4SLinus Torvalds * set it will cause associations that are idle for more than the 43911da177e4SLinus Torvalds * specified number of seconds to automatically close. An association 43921da177e4SLinus Torvalds * being idle is defined an association that has NOT sent or received 43931da177e4SLinus Torvalds * user data. The special value of '0' indicates that no automatic 43941da177e4SLinus Torvalds * close of any associations should be performed. The option expects an 43951da177e4SLinus Torvalds * integer defining the number of seconds of idle time before an 43961da177e4SLinus Torvalds * association is closed. 43971da177e4SLinus Torvalds */ 43981da177e4SLinus Torvalds static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optval, int __user *optlen) 43991da177e4SLinus Torvalds { 44001da177e4SLinus Torvalds /* Applicable to UDP-style socket only */ 44011da177e4SLinus Torvalds if (sctp_style(sk, TCP)) 44021da177e4SLinus Torvalds return -EOPNOTSUPP; 4403408f22e8SNeil Horman if (len < sizeof(int)) 44041da177e4SLinus Torvalds return -EINVAL; 4405408f22e8SNeil Horman len = sizeof(int); 4406408f22e8SNeil Horman if (put_user(len, optlen)) 4407408f22e8SNeil Horman return -EFAULT; 4408408f22e8SNeil Horman if (copy_to_user(optval, &sctp_sk(sk)->autoclose, sizeof(int))) 44091da177e4SLinus Torvalds return -EFAULT; 44101da177e4SLinus Torvalds return 0; 44111da177e4SLinus Torvalds } 44121da177e4SLinus Torvalds 44131da177e4SLinus Torvalds /* Helper routine to branch off an association to a new socket. */ 44140343c554SBenjamin Poirier int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) 44151da177e4SLinus Torvalds { 44160343c554SBenjamin Poirier struct sctp_association *asoc = sctp_id2assoc(sk, id); 4417299ee123SJason Gunthorpe struct sctp_sock *sp = sctp_sk(sk); 44181da177e4SLinus Torvalds struct socket *sock; 44191da177e4SLinus Torvalds int err = 0; 44201da177e4SLinus Torvalds 44210343c554SBenjamin Poirier if (!asoc) 44220343c554SBenjamin Poirier return -EINVAL; 44230343c554SBenjamin Poirier 44241da177e4SLinus Torvalds /* An association cannot be branched off from an already peeled-off 44251da177e4SLinus Torvalds * socket, nor is this supported for tcp style sockets. 44261da177e4SLinus Torvalds */ 44271da177e4SLinus Torvalds if (!sctp_style(sk, UDP)) 44281da177e4SLinus Torvalds return -EINVAL; 44291da177e4SLinus Torvalds 44301da177e4SLinus Torvalds /* Create a new socket. */ 44311da177e4SLinus Torvalds err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); 44321da177e4SLinus Torvalds if (err < 0) 44331da177e4SLinus Torvalds return err; 44341da177e4SLinus Torvalds 4435914e1c8bSVlad Yasevich sctp_copy_sock(sock->sk, sk, asoc); 44364f444308SVlad Yasevich 44374f444308SVlad Yasevich /* Make peeled-off sockets more like 1-1 accepted sockets. 44384f444308SVlad Yasevich * Set the daddr and initialize id to something more random 44394f444308SVlad Yasevich */ 4440299ee123SJason Gunthorpe sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk); 4441914e1c8bSVlad Yasevich 4442914e1c8bSVlad Yasevich /* Populate the fields of the newsk from the oldsk and migrate the 4443914e1c8bSVlad Yasevich * asoc to the newsk. 4444914e1c8bSVlad Yasevich */ 4445914e1c8bSVlad Yasevich sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); 44464f444308SVlad Yasevich 44471da177e4SLinus Torvalds *sockp = sock; 44481da177e4SLinus Torvalds 44491da177e4SLinus Torvalds return err; 44501da177e4SLinus Torvalds } 44510343c554SBenjamin Poirier EXPORT_SYMBOL(sctp_do_peeloff); 44521da177e4SLinus Torvalds 44531da177e4SLinus Torvalds static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) 44541da177e4SLinus Torvalds { 44551da177e4SLinus Torvalds sctp_peeloff_arg_t peeloff; 44561da177e4SLinus Torvalds struct socket *newsock; 445756b31d1cSAl Viro struct file *newfile; 44581da177e4SLinus Torvalds int retval = 0; 44591da177e4SLinus Torvalds 4460408f22e8SNeil Horman if (len < sizeof(sctp_peeloff_arg_t)) 44611da177e4SLinus Torvalds return -EINVAL; 4462408f22e8SNeil Horman len = sizeof(sctp_peeloff_arg_t); 44631da177e4SLinus Torvalds if (copy_from_user(&peeloff, optval, len)) 44641da177e4SLinus Torvalds return -EFAULT; 44651da177e4SLinus Torvalds 44660343c554SBenjamin Poirier retval = sctp_do_peeloff(sk, peeloff.associd, &newsock); 44671da177e4SLinus Torvalds if (retval < 0) 44681da177e4SLinus Torvalds goto out; 44691da177e4SLinus Torvalds 44701da177e4SLinus Torvalds /* Map the socket to an unused fd that can be returned to the user. */ 44718a59bd3eSYann Droneaud retval = get_unused_fd_flags(0); 44721da177e4SLinus Torvalds if (retval < 0) { 44731da177e4SLinus Torvalds sock_release(newsock); 44741da177e4SLinus Torvalds goto out; 44751da177e4SLinus Torvalds } 44761da177e4SLinus Torvalds 4477aab174f0SLinus Torvalds newfile = sock_alloc_file(newsock, 0, NULL); 4478b5ffe634SViresh Kumar if (IS_ERR(newfile)) { 447956b31d1cSAl Viro put_unused_fd(retval); 448056b31d1cSAl Viro sock_release(newsock); 448156b31d1cSAl Viro return PTR_ERR(newfile); 448256b31d1cSAl Viro } 448356b31d1cSAl Viro 4484bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk, 4485bb33381dSDaniel Borkmann retval); 44861da177e4SLinus Torvalds 44871da177e4SLinus Torvalds /* Return the fd mapped to the new socket. */ 448856b31d1cSAl Viro if (put_user(len, optlen)) { 448956b31d1cSAl Viro fput(newfile); 449056b31d1cSAl Viro put_unused_fd(retval); 4491408f22e8SNeil Horman return -EFAULT; 449256b31d1cSAl Viro } 449356b31d1cSAl Viro peeloff.sd = retval; 449456b31d1cSAl Viro if (copy_to_user(optval, &peeloff, len)) { 449556b31d1cSAl Viro fput(newfile); 449656b31d1cSAl Viro put_unused_fd(retval); 449756b31d1cSAl Viro return -EFAULT; 449856b31d1cSAl Viro } 449956b31d1cSAl Viro fd_install(retval, newfile); 45001da177e4SLinus Torvalds out: 45011da177e4SLinus Torvalds return retval; 45021da177e4SLinus Torvalds } 45031da177e4SLinus Torvalds 45041da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) 45051da177e4SLinus Torvalds * 45061da177e4SLinus Torvalds * Applications can enable or disable heartbeats for any peer address of 45071da177e4SLinus Torvalds * an association, modify an address's heartbeat interval, force a 45081da177e4SLinus Torvalds * heartbeat to be sent immediately, and adjust the address's maximum 45091da177e4SLinus Torvalds * number of retransmissions sent before an address is considered 45101da177e4SLinus Torvalds * unreachable. The following structure is used to access and modify an 45111da177e4SLinus Torvalds * address's parameters: 45121da177e4SLinus Torvalds * 45131da177e4SLinus Torvalds * struct sctp_paddrparams { 45141da177e4SLinus Torvalds * sctp_assoc_t spp_assoc_id; 45151da177e4SLinus Torvalds * struct sockaddr_storage spp_address; 45161da177e4SLinus Torvalds * uint32_t spp_hbinterval; 45171da177e4SLinus Torvalds * uint16_t spp_pathmaxrxt; 451852ccb8e9SFrank Filz * uint32_t spp_pathmtu; 451952ccb8e9SFrank Filz * uint32_t spp_sackdelay; 452052ccb8e9SFrank Filz * uint32_t spp_flags; 45211da177e4SLinus Torvalds * }; 45221da177e4SLinus Torvalds * 452352ccb8e9SFrank Filz * spp_assoc_id - (one-to-many style socket) This is filled in the 452452ccb8e9SFrank Filz * application, and identifies the association for 452552ccb8e9SFrank Filz * this query. 45261da177e4SLinus Torvalds * spp_address - This specifies which address is of interest. 45271da177e4SLinus Torvalds * spp_hbinterval - This contains the value of the heartbeat interval, 452852ccb8e9SFrank Filz * in milliseconds. If a value of zero 452952ccb8e9SFrank Filz * is present in this field then no changes are to 453052ccb8e9SFrank Filz * be made to this parameter. 45311da177e4SLinus Torvalds * spp_pathmaxrxt - This contains the maximum number of 45321da177e4SLinus Torvalds * retransmissions before this address shall be 453352ccb8e9SFrank Filz * considered unreachable. If a value of zero 453452ccb8e9SFrank Filz * is present in this field then no changes are to 453552ccb8e9SFrank Filz * be made to this parameter. 453652ccb8e9SFrank Filz * spp_pathmtu - When Path MTU discovery is disabled the value 453752ccb8e9SFrank Filz * specified here will be the "fixed" path mtu. 453852ccb8e9SFrank Filz * Note that if the spp_address field is empty 453952ccb8e9SFrank Filz * then all associations on this address will 454052ccb8e9SFrank Filz * have this fixed path mtu set upon them. 454152ccb8e9SFrank Filz * 454252ccb8e9SFrank Filz * spp_sackdelay - When delayed sack is enabled, this value specifies 454352ccb8e9SFrank Filz * the number of milliseconds that sacks will be delayed 454452ccb8e9SFrank Filz * for. This value will apply to all addresses of an 454552ccb8e9SFrank Filz * association if the spp_address field is empty. Note 454652ccb8e9SFrank Filz * also, that if delayed sack is enabled and this 454752ccb8e9SFrank Filz * value is set to 0, no change is made to the last 454852ccb8e9SFrank Filz * recorded delayed sack timer value. 454952ccb8e9SFrank Filz * 455052ccb8e9SFrank Filz * spp_flags - These flags are used to control various features 455152ccb8e9SFrank Filz * on an association. The flag field may contain 455252ccb8e9SFrank Filz * zero or more of the following options. 455352ccb8e9SFrank Filz * 455452ccb8e9SFrank Filz * SPP_HB_ENABLE - Enable heartbeats on the 455552ccb8e9SFrank Filz * specified address. Note that if the address 455652ccb8e9SFrank Filz * field is empty all addresses for the association 455752ccb8e9SFrank Filz * have heartbeats enabled upon them. 455852ccb8e9SFrank Filz * 455952ccb8e9SFrank Filz * SPP_HB_DISABLE - Disable heartbeats on the 456052ccb8e9SFrank Filz * speicifed address. Note that if the address 456152ccb8e9SFrank Filz * field is empty all addresses for the association 456252ccb8e9SFrank Filz * will have their heartbeats disabled. Note also 456352ccb8e9SFrank Filz * that SPP_HB_ENABLE and SPP_HB_DISABLE are 456452ccb8e9SFrank Filz * mutually exclusive, only one of these two should 456552ccb8e9SFrank Filz * be specified. Enabling both fields will have 456652ccb8e9SFrank Filz * undetermined results. 456752ccb8e9SFrank Filz * 456852ccb8e9SFrank Filz * SPP_HB_DEMAND - Request a user initiated heartbeat 456952ccb8e9SFrank Filz * to be made immediately. 457052ccb8e9SFrank Filz * 457152ccb8e9SFrank Filz * SPP_PMTUD_ENABLE - This field will enable PMTU 457252ccb8e9SFrank Filz * discovery upon the specified address. Note that 457352ccb8e9SFrank Filz * if the address feild is empty then all addresses 457452ccb8e9SFrank Filz * on the association are effected. 457552ccb8e9SFrank Filz * 457652ccb8e9SFrank Filz * SPP_PMTUD_DISABLE - This field will disable PMTU 457752ccb8e9SFrank Filz * discovery upon the specified address. Note that 457852ccb8e9SFrank Filz * if the address feild is empty then all addresses 457952ccb8e9SFrank Filz * on the association are effected. Not also that 458052ccb8e9SFrank Filz * SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually 458152ccb8e9SFrank Filz * exclusive. Enabling both will have undetermined 458252ccb8e9SFrank Filz * results. 458352ccb8e9SFrank Filz * 458452ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE - Setting this flag turns 458552ccb8e9SFrank Filz * on delayed sack. The time specified in spp_sackdelay 458652ccb8e9SFrank Filz * is used to specify the sack delay for this address. Note 458752ccb8e9SFrank Filz * that if spp_address is empty then all addresses will 458852ccb8e9SFrank Filz * enable delayed sack and take on the sack delay 458952ccb8e9SFrank Filz * value specified in spp_sackdelay. 459052ccb8e9SFrank Filz * SPP_SACKDELAY_DISABLE - Setting this flag turns 459152ccb8e9SFrank Filz * off delayed sack. If the spp_address field is blank then 459252ccb8e9SFrank Filz * delayed sack is disabled for the entire association. Note 459352ccb8e9SFrank Filz * also that this field is mutually exclusive to 459452ccb8e9SFrank Filz * SPP_SACKDELAY_ENABLE, setting both will have undefined 459552ccb8e9SFrank Filz * results. 45961da177e4SLinus Torvalds */ 45971da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, 45981da177e4SLinus Torvalds char __user *optval, int __user *optlen) 45991da177e4SLinus Torvalds { 46001da177e4SLinus Torvalds struct sctp_paddrparams params; 460152ccb8e9SFrank Filz struct sctp_transport *trans = NULL; 460252ccb8e9SFrank Filz struct sctp_association *asoc = NULL; 460352ccb8e9SFrank Filz struct sctp_sock *sp = sctp_sk(sk); 46041da177e4SLinus Torvalds 4605408f22e8SNeil Horman if (len < sizeof(struct sctp_paddrparams)) 46061da177e4SLinus Torvalds return -EINVAL; 4607408f22e8SNeil Horman len = sizeof(struct sctp_paddrparams); 46081da177e4SLinus Torvalds if (copy_from_user(¶ms, optval, len)) 46091da177e4SLinus Torvalds return -EFAULT; 46101da177e4SLinus Torvalds 461152ccb8e9SFrank Filz /* If an address other than INADDR_ANY is specified, and 461252ccb8e9SFrank Filz * no transport is found, then the request is invalid. 46131da177e4SLinus Torvalds */ 461452cae8f0SVlad Yasevich if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) { 46151da177e4SLinus Torvalds trans = sctp_addr_id2transport(sk, ¶ms.spp_address, 46161da177e4SLinus Torvalds params.spp_assoc_id); 461752ccb8e9SFrank Filz if (!trans) { 4618bb33381dSDaniel Borkmann pr_debug("%s: failed no transport\n", __func__); 46191da177e4SLinus Torvalds return -EINVAL; 462052ccb8e9SFrank Filz } 462152ccb8e9SFrank Filz } 46221da177e4SLinus Torvalds 462352ccb8e9SFrank Filz /* Get association, if assoc_id != 0 and the socket is a one 462452ccb8e9SFrank Filz * to many style socket, and an association was not found, then 462552ccb8e9SFrank Filz * the id was invalid. 46261da177e4SLinus Torvalds */ 462752ccb8e9SFrank Filz asoc = sctp_id2assoc(sk, params.spp_assoc_id); 462852ccb8e9SFrank Filz if (!asoc && params.spp_assoc_id && sctp_style(sk, UDP)) { 4629bb33381dSDaniel Borkmann pr_debug("%s: failed no association\n", __func__); 463052ccb8e9SFrank Filz return -EINVAL; 463152ccb8e9SFrank Filz } 46321da177e4SLinus Torvalds 463352ccb8e9SFrank Filz if (trans) { 463452ccb8e9SFrank Filz /* Fetch transport values. */ 463552ccb8e9SFrank Filz params.spp_hbinterval = jiffies_to_msecs(trans->hbinterval); 463652ccb8e9SFrank Filz params.spp_pathmtu = trans->pathmtu; 463752ccb8e9SFrank Filz params.spp_pathmaxrxt = trans->pathmaxrxt; 463852ccb8e9SFrank Filz params.spp_sackdelay = jiffies_to_msecs(trans->sackdelay); 46391da177e4SLinus Torvalds 464052ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 464152ccb8e9SFrank Filz params.spp_flags = trans->param_flags; 464252ccb8e9SFrank Filz } else if (asoc) { 464352ccb8e9SFrank Filz /* Fetch association values. */ 464452ccb8e9SFrank Filz params.spp_hbinterval = jiffies_to_msecs(asoc->hbinterval); 464552ccb8e9SFrank Filz params.spp_pathmtu = asoc->pathmtu; 464652ccb8e9SFrank Filz params.spp_pathmaxrxt = asoc->pathmaxrxt; 464752ccb8e9SFrank Filz params.spp_sackdelay = jiffies_to_msecs(asoc->sackdelay); 464852ccb8e9SFrank Filz 464952ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 465052ccb8e9SFrank Filz params.spp_flags = asoc->param_flags; 465152ccb8e9SFrank Filz } else { 465252ccb8e9SFrank Filz /* Fetch socket values. */ 465352ccb8e9SFrank Filz params.spp_hbinterval = sp->hbinterval; 465452ccb8e9SFrank Filz params.spp_pathmtu = sp->pathmtu; 465552ccb8e9SFrank Filz params.spp_sackdelay = sp->sackdelay; 465652ccb8e9SFrank Filz params.spp_pathmaxrxt = sp->pathmaxrxt; 465752ccb8e9SFrank Filz 465852ccb8e9SFrank Filz /*draft-11 doesn't say what to return in spp_flags*/ 465952ccb8e9SFrank Filz params.spp_flags = sp->param_flags; 466052ccb8e9SFrank Filz } 466152ccb8e9SFrank Filz 46621da177e4SLinus Torvalds if (copy_to_user(optval, ¶ms, len)) 46631da177e4SLinus Torvalds return -EFAULT; 46641da177e4SLinus Torvalds 46651da177e4SLinus Torvalds if (put_user(len, optlen)) 46661da177e4SLinus Torvalds return -EFAULT; 46671da177e4SLinus Torvalds 46681da177e4SLinus Torvalds return 0; 46691da177e4SLinus Torvalds } 46701da177e4SLinus Torvalds 4671d364d927SWei Yongjun /* 4672d364d927SWei Yongjun * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) 46737708610bSFrank Filz * 4674d364d927SWei Yongjun * This option will effect the way delayed acks are performed. This 4675d364d927SWei Yongjun * option allows you to get or set the delayed ack time, in 4676d364d927SWei Yongjun * milliseconds. It also allows changing the delayed ack frequency. 4677d364d927SWei Yongjun * Changing the frequency to 1 disables the delayed sack algorithm. If 4678d364d927SWei Yongjun * the assoc_id is 0, then this sets or gets the endpoints default 4679d364d927SWei Yongjun * values. If the assoc_id field is non-zero, then the set or get 4680d364d927SWei Yongjun * effects the specified association for the one to many model (the 4681d364d927SWei Yongjun * assoc_id field is ignored by the one to one model). Note that if 4682d364d927SWei Yongjun * sack_delay or sack_freq are 0 when setting this option, then the 4683d364d927SWei Yongjun * current values will remain unchanged. 46847708610bSFrank Filz * 4685d364d927SWei Yongjun * struct sctp_sack_info { 4686d364d927SWei Yongjun * sctp_assoc_t sack_assoc_id; 4687d364d927SWei Yongjun * uint32_t sack_delay; 4688d364d927SWei Yongjun * uint32_t sack_freq; 46897708610bSFrank Filz * }; 46907708610bSFrank Filz * 4691d364d927SWei Yongjun * sack_assoc_id - This parameter, indicates which association the user 4692d364d927SWei Yongjun * is performing an action upon. Note that if this field's value is 4693d364d927SWei Yongjun * zero then the endpoints default value is changed (effecting future 46947708610bSFrank Filz * associations only). 46957708610bSFrank Filz * 4696d364d927SWei Yongjun * sack_delay - This parameter contains the number of milliseconds that 4697d364d927SWei Yongjun * the user is requesting the delayed ACK timer be set to. Note that 4698d364d927SWei Yongjun * this value is defined in the standard to be between 200 and 500 4699d364d927SWei Yongjun * milliseconds. 47007708610bSFrank Filz * 4701d364d927SWei Yongjun * sack_freq - This parameter contains the number of packets that must 4702d364d927SWei Yongjun * be received before a sack is sent without waiting for the delay 4703d364d927SWei Yongjun * timer to expire. The default value for this is 2, setting this 4704d364d927SWei Yongjun * value to 1 will disable the delayed sack algorithm. 47057708610bSFrank Filz */ 4706d364d927SWei Yongjun static int sctp_getsockopt_delayed_ack(struct sock *sk, int len, 47077708610bSFrank Filz char __user *optval, 47087708610bSFrank Filz int __user *optlen) 47097708610bSFrank Filz { 4710d364d927SWei Yongjun struct sctp_sack_info params; 47117708610bSFrank Filz struct sctp_association *asoc = NULL; 47127708610bSFrank Filz struct sctp_sock *sp = sctp_sk(sk); 47137708610bSFrank Filz 4714d364d927SWei Yongjun if (len >= sizeof(struct sctp_sack_info)) { 4715d364d927SWei Yongjun len = sizeof(struct sctp_sack_info); 4716408f22e8SNeil Horman 47177708610bSFrank Filz if (copy_from_user(¶ms, optval, len)) 47187708610bSFrank Filz return -EFAULT; 4719d364d927SWei Yongjun } else if (len == sizeof(struct sctp_assoc_value)) { 472094f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 4721f916ec96SNeil Horman "%s (pid %d) " 472294f65193SNeil Horman "Use of struct sctp_assoc_value in delayed_ack socket option.\n" 4723f916ec96SNeil Horman "Use struct sctp_sack_info instead\n", 4724f916ec96SNeil Horman current->comm, task_pid_nr(current)); 4725d364d927SWei Yongjun if (copy_from_user(¶ms, optval, len)) 4726d364d927SWei Yongjun return -EFAULT; 4727d364d927SWei Yongjun } else 4728d364d927SWei Yongjun return -EINVAL; 47297708610bSFrank Filz 4730d364d927SWei Yongjun /* Get association, if sack_assoc_id != 0 and the socket is a one 47317708610bSFrank Filz * to many style socket, and an association was not found, then 47327708610bSFrank Filz * the id was invalid. 47337708610bSFrank Filz */ 4734d364d927SWei Yongjun asoc = sctp_id2assoc(sk, params.sack_assoc_id); 4735d364d927SWei Yongjun if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP)) 47367708610bSFrank Filz return -EINVAL; 47377708610bSFrank Filz 47387708610bSFrank Filz if (asoc) { 47397708610bSFrank Filz /* Fetch association values. */ 4740d364d927SWei Yongjun if (asoc->param_flags & SPP_SACKDELAY_ENABLE) { 4741d364d927SWei Yongjun params.sack_delay = jiffies_to_msecs( 47427708610bSFrank Filz asoc->sackdelay); 4743d364d927SWei Yongjun params.sack_freq = asoc->sackfreq; 4744d364d927SWei Yongjun 4745d364d927SWei Yongjun } else { 4746d364d927SWei Yongjun params.sack_delay = 0; 4747d364d927SWei Yongjun params.sack_freq = 1; 4748d364d927SWei Yongjun } 47497708610bSFrank Filz } else { 47507708610bSFrank Filz /* Fetch socket values. */ 4751d364d927SWei Yongjun if (sp->param_flags & SPP_SACKDELAY_ENABLE) { 4752d364d927SWei Yongjun params.sack_delay = sp->sackdelay; 4753d364d927SWei Yongjun params.sack_freq = sp->sackfreq; 4754d364d927SWei Yongjun } else { 4755d364d927SWei Yongjun params.sack_delay = 0; 4756d364d927SWei Yongjun params.sack_freq = 1; 4757d364d927SWei Yongjun } 47587708610bSFrank Filz } 47597708610bSFrank Filz 47607708610bSFrank Filz if (copy_to_user(optval, ¶ms, len)) 47617708610bSFrank Filz return -EFAULT; 47627708610bSFrank Filz 47637708610bSFrank Filz if (put_user(len, optlen)) 47647708610bSFrank Filz return -EFAULT; 47657708610bSFrank Filz 47667708610bSFrank Filz return 0; 47677708610bSFrank Filz } 47687708610bSFrank Filz 47691da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG) 47701da177e4SLinus Torvalds * 47711da177e4SLinus Torvalds * Applications can specify protocol parameters for the default association 47721da177e4SLinus Torvalds * initialization. The option name argument to setsockopt() and getsockopt() 47731da177e4SLinus Torvalds * is SCTP_INITMSG. 47741da177e4SLinus Torvalds * 47751da177e4SLinus Torvalds * Setting initialization parameters is effective only on an unconnected 47761da177e4SLinus Torvalds * socket (for UDP-style sockets only future associations are effected 47771da177e4SLinus Torvalds * by the change). With TCP-style sockets, this option is inherited by 47781da177e4SLinus Torvalds * sockets derived from a listener socket. 47791da177e4SLinus Torvalds */ 47801da177e4SLinus Torvalds static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen) 47811da177e4SLinus Torvalds { 4782408f22e8SNeil Horman if (len < sizeof(struct sctp_initmsg)) 47831da177e4SLinus Torvalds return -EINVAL; 4784408f22e8SNeil Horman len = sizeof(struct sctp_initmsg); 4785408f22e8SNeil Horman if (put_user(len, optlen)) 4786408f22e8SNeil Horman return -EFAULT; 47871da177e4SLinus Torvalds if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len)) 47881da177e4SLinus Torvalds return -EFAULT; 47891da177e4SLinus Torvalds return 0; 47901da177e4SLinus Torvalds } 47911da177e4SLinus Torvalds 47921da177e4SLinus Torvalds 47935fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, 47945fe467eeSIvan Skytte Jørgensen char __user *optval, int __user *optlen) 47955fe467eeSIvan Skytte Jørgensen { 47965fe467eeSIvan Skytte Jørgensen struct sctp_association *asoc; 47975fe467eeSIvan Skytte Jørgensen int cnt = 0; 47985fe467eeSIvan Skytte Jørgensen struct sctp_getaddrs getaddrs; 47995fe467eeSIvan Skytte Jørgensen struct sctp_transport *from; 48005fe467eeSIvan Skytte Jørgensen void __user *to; 48015fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 48025fe467eeSIvan Skytte Jørgensen struct sctp_sock *sp = sctp_sk(sk); 48035fe467eeSIvan Skytte Jørgensen int addrlen; 48045fe467eeSIvan Skytte Jørgensen size_t space_left; 48055fe467eeSIvan Skytte Jørgensen int bytes_copied; 48065fe467eeSIvan Skytte Jørgensen 48075fe467eeSIvan Skytte Jørgensen if (len < sizeof(struct sctp_getaddrs)) 48085fe467eeSIvan Skytte Jørgensen return -EINVAL; 48095fe467eeSIvan Skytte Jørgensen 48105fe467eeSIvan Skytte Jørgensen if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 48115fe467eeSIvan Skytte Jørgensen return -EFAULT; 48125fe467eeSIvan Skytte Jørgensen 48135fe467eeSIvan Skytte Jørgensen /* For UDP-style sockets, id specifies the association to query. */ 48145fe467eeSIvan Skytte Jørgensen asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 48155fe467eeSIvan Skytte Jørgensen if (!asoc) 48165fe467eeSIvan Skytte Jørgensen return -EINVAL; 48175fe467eeSIvan Skytte Jørgensen 48185fe467eeSIvan Skytte Jørgensen to = optval + offsetof(struct sctp_getaddrs, addrs); 4819186e2343SNeil Horman space_left = len - offsetof(struct sctp_getaddrs, addrs); 48205fe467eeSIvan Skytte Jørgensen 48219dbc15f0SRobert P. J. Day list_for_each_entry(from, &asoc->peer.transport_addr_list, 48229dbc15f0SRobert P. J. Day transports) { 4823b3f5b3b6SAl Viro memcpy(&temp, &from->ipaddr, sizeof(temp)); 4824299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 4825299ee123SJason Gunthorpe ->addr_to_user(sp, &temp); 48265fe467eeSIvan Skytte Jørgensen if (space_left < addrlen) 48275fe467eeSIvan Skytte Jørgensen return -ENOMEM; 48285fe467eeSIvan Skytte Jørgensen if (copy_to_user(to, &temp, addrlen)) 48295fe467eeSIvan Skytte Jørgensen return -EFAULT; 48305fe467eeSIvan Skytte Jørgensen to += addrlen; 48315fe467eeSIvan Skytte Jørgensen cnt++; 48325fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 48335fe467eeSIvan Skytte Jørgensen } 48345fe467eeSIvan Skytte Jørgensen 48355fe467eeSIvan Skytte Jørgensen if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) 48365fe467eeSIvan Skytte Jørgensen return -EFAULT; 48375fe467eeSIvan Skytte Jørgensen bytes_copied = ((char __user *)to) - optval; 48385fe467eeSIvan Skytte Jørgensen if (put_user(bytes_copied, optlen)) 48395fe467eeSIvan Skytte Jørgensen return -EFAULT; 48405fe467eeSIvan Skytte Jørgensen 48415fe467eeSIvan Skytte Jørgensen return 0; 48425fe467eeSIvan Skytte Jørgensen } 48435fe467eeSIvan Skytte Jørgensen 4844aad97f38SVlad Yasevich static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, 4845aad97f38SVlad Yasevich size_t space_left, int *bytes_copied) 48465fe467eeSIvan Skytte Jørgensen { 48475fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry *addr; 48485fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 48495fe467eeSIvan Skytte Jørgensen int cnt = 0; 48505fe467eeSIvan Skytte Jørgensen int addrlen; 48514db67e80SEric W. Biederman struct net *net = sock_net(sk); 48525fe467eeSIvan Skytte Jørgensen 485329303547SVlad Yasevich rcu_read_lock(); 48544db67e80SEric W. Biederman list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) { 485529303547SVlad Yasevich if (!addr->valid) 485629303547SVlad Yasevich continue; 485729303547SVlad Yasevich 48585fe467eeSIvan Skytte Jørgensen if ((PF_INET == sk->sk_family) && 48596244be4eSAl Viro (AF_INET6 == addr->a.sa.sa_family)) 48605fe467eeSIvan Skytte Jørgensen continue; 48617dab83deSVlad Yasevich if ((PF_INET6 == sk->sk_family) && 48627dab83deSVlad Yasevich inet_v6_ipv6only(sk) && 48637dab83deSVlad Yasevich (AF_INET == addr->a.sa.sa_family)) 48647dab83deSVlad Yasevich continue; 48656244be4eSAl Viro memcpy(&temp, &addr->a, sizeof(temp)); 4866b46ae36dSVlad Yasevich if (!temp.v4.sin_port) 4867b46ae36dSVlad Yasevich temp.v4.sin_port = htons(port); 4868b46ae36dSVlad Yasevich 4869299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 4870299ee123SJason Gunthorpe ->addr_to_user(sctp_sk(sk), &temp); 4871299ee123SJason Gunthorpe 487229303547SVlad Yasevich if (space_left < addrlen) { 487329303547SVlad Yasevich cnt = -ENOMEM; 487429303547SVlad Yasevich break; 487529303547SVlad Yasevich } 4876aad97f38SVlad Yasevich memcpy(to, &temp, addrlen); 487729c7cf96SSridhar Samudrala 4878aad97f38SVlad Yasevich to += addrlen; 48795fe467eeSIvan Skytte Jørgensen cnt++; 48805fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 48813663c306SVlad Yasevich *bytes_copied += addrlen; 48825fe467eeSIvan Skytte Jørgensen } 488329303547SVlad Yasevich rcu_read_unlock(); 48845fe467eeSIvan Skytte Jørgensen 48855fe467eeSIvan Skytte Jørgensen return cnt; 48865fe467eeSIvan Skytte Jørgensen } 48875fe467eeSIvan Skytte Jørgensen 48881da177e4SLinus Torvalds 48895fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_local_addrs(struct sock *sk, int len, 48905fe467eeSIvan Skytte Jørgensen char __user *optval, int __user *optlen) 48915fe467eeSIvan Skytte Jørgensen { 48925fe467eeSIvan Skytte Jørgensen struct sctp_bind_addr *bp; 48935fe467eeSIvan Skytte Jørgensen struct sctp_association *asoc; 48945fe467eeSIvan Skytte Jørgensen int cnt = 0; 48955fe467eeSIvan Skytte Jørgensen struct sctp_getaddrs getaddrs; 48965fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry *addr; 48975fe467eeSIvan Skytte Jørgensen void __user *to; 48985fe467eeSIvan Skytte Jørgensen union sctp_addr temp; 48995fe467eeSIvan Skytte Jørgensen struct sctp_sock *sp = sctp_sk(sk); 49005fe467eeSIvan Skytte Jørgensen int addrlen; 49015fe467eeSIvan Skytte Jørgensen int err = 0; 49025fe467eeSIvan Skytte Jørgensen size_t space_left; 4903aad97f38SVlad Yasevich int bytes_copied = 0; 4904aad97f38SVlad Yasevich void *addrs; 490570b57b81SVlad Yasevich void *buf; 49065fe467eeSIvan Skytte Jørgensen 4907408f22e8SNeil Horman if (len < sizeof(struct sctp_getaddrs)) 49085fe467eeSIvan Skytte Jørgensen return -EINVAL; 49095fe467eeSIvan Skytte Jørgensen 49105fe467eeSIvan Skytte Jørgensen if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 49115fe467eeSIvan Skytte Jørgensen return -EFAULT; 49125fe467eeSIvan Skytte Jørgensen 49135fe467eeSIvan Skytte Jørgensen /* 49145fe467eeSIvan Skytte Jørgensen * For UDP-style sockets, id specifies the association to query. 49155fe467eeSIvan Skytte Jørgensen * If the id field is set to the value '0' then the locally bound 49165fe467eeSIvan Skytte Jørgensen * addresses are returned without regard to any particular 49175fe467eeSIvan Skytte Jørgensen * association. 49185fe467eeSIvan Skytte Jørgensen */ 49195fe467eeSIvan Skytte Jørgensen if (0 == getaddrs.assoc_id) { 49205fe467eeSIvan Skytte Jørgensen bp = &sctp_sk(sk)->ep->base.bind_addr; 49215fe467eeSIvan Skytte Jørgensen } else { 49225fe467eeSIvan Skytte Jørgensen asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 49235fe467eeSIvan Skytte Jørgensen if (!asoc) 49245fe467eeSIvan Skytte Jørgensen return -EINVAL; 49255fe467eeSIvan Skytte Jørgensen bp = &asoc->base.bind_addr; 49265fe467eeSIvan Skytte Jørgensen } 49275fe467eeSIvan Skytte Jørgensen 49285fe467eeSIvan Skytte Jørgensen to = optval + offsetof(struct sctp_getaddrs, addrs); 4929186e2343SNeil Horman space_left = len - offsetof(struct sctp_getaddrs, addrs); 4930186e2343SNeil Horman 4931cacc0621SMarcelo Ricardo Leitner addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN); 4932aad97f38SVlad Yasevich if (!addrs) 4933aad97f38SVlad Yasevich return -ENOMEM; 49345fe467eeSIvan Skytte Jørgensen 49355fe467eeSIvan Skytte Jørgensen /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid 49365fe467eeSIvan Skytte Jørgensen * addresses from the global local address list. 49375fe467eeSIvan Skytte Jørgensen */ 49385fe467eeSIvan Skytte Jørgensen if (sctp_list_single_entry(&bp->address_list)) { 49395fe467eeSIvan Skytte Jørgensen addr = list_entry(bp->address_list.next, 49405fe467eeSIvan Skytte Jørgensen struct sctp_sockaddr_entry, list); 494152cae8f0SVlad Yasevich if (sctp_is_any(sk, &addr->a)) { 4942aad97f38SVlad Yasevich cnt = sctp_copy_laddrs(sk, bp->port, addrs, 4943aad97f38SVlad Yasevich space_left, &bytes_copied); 49445fe467eeSIvan Skytte Jørgensen if (cnt < 0) { 49455fe467eeSIvan Skytte Jørgensen err = cnt; 4946559cf710SVlad Yasevich goto out; 49475fe467eeSIvan Skytte Jørgensen } 49485fe467eeSIvan Skytte Jørgensen goto copy_getaddrs; 49495fe467eeSIvan Skytte Jørgensen } 49505fe467eeSIvan Skytte Jørgensen } 49515fe467eeSIvan Skytte Jørgensen 495270b57b81SVlad Yasevich buf = addrs; 4953559cf710SVlad Yasevich /* Protection on the bound address list is not needed since 4954559cf710SVlad Yasevich * in the socket option context we hold a socket lock and 4955559cf710SVlad Yasevich * thus the bound address list can't change. 4956559cf710SVlad Yasevich */ 4957559cf710SVlad Yasevich list_for_each_entry(addr, &bp->address_list, list) { 49586244be4eSAl Viro memcpy(&temp, &addr->a, sizeof(temp)); 4959299ee123SJason Gunthorpe addrlen = sctp_get_pf_specific(sk->sk_family) 4960299ee123SJason Gunthorpe ->addr_to_user(sp, &temp); 4961aad97f38SVlad Yasevich if (space_left < addrlen) { 4962aad97f38SVlad Yasevich err = -ENOMEM; /*fixme: right error?*/ 4963559cf710SVlad Yasevich goto out; 49645fe467eeSIvan Skytte Jørgensen } 496570b57b81SVlad Yasevich memcpy(buf, &temp, addrlen); 496670b57b81SVlad Yasevich buf += addrlen; 4967aad97f38SVlad Yasevich bytes_copied += addrlen; 49685fe467eeSIvan Skytte Jørgensen cnt++; 49695fe467eeSIvan Skytte Jørgensen space_left -= addrlen; 49705fe467eeSIvan Skytte Jørgensen } 49715fe467eeSIvan Skytte Jørgensen 49725fe467eeSIvan Skytte Jørgensen copy_getaddrs: 4973aad97f38SVlad Yasevich if (copy_to_user(to, addrs, bytes_copied)) { 4974aad97f38SVlad Yasevich err = -EFAULT; 4975d6f9fdafSSebastian Siewior goto out; 4976aad97f38SVlad Yasevich } 4977fe979ac1SVlad Yasevich if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) { 4978fe979ac1SVlad Yasevich err = -EFAULT; 4979d6f9fdafSSebastian Siewior goto out; 4980fe979ac1SVlad Yasevich } 49815fe467eeSIvan Skytte Jørgensen if (put_user(bytes_copied, optlen)) 4982fe979ac1SVlad Yasevich err = -EFAULT; 4983d6f9fdafSSebastian Siewior out: 4984aad97f38SVlad Yasevich kfree(addrs); 49855fe467eeSIvan Skytte Jørgensen return err; 49865fe467eeSIvan Skytte Jørgensen } 49875fe467eeSIvan Skytte Jørgensen 49881da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) 49891da177e4SLinus Torvalds * 49901da177e4SLinus Torvalds * Requests that the local SCTP stack use the enclosed peer address as 49911da177e4SLinus Torvalds * the association primary. The enclosed address must be one of the 49921da177e4SLinus Torvalds * association peer's addresses. 49931da177e4SLinus Torvalds */ 49941da177e4SLinus Torvalds static int sctp_getsockopt_primary_addr(struct sock *sk, int len, 49951da177e4SLinus Torvalds char __user *optval, int __user *optlen) 49961da177e4SLinus Torvalds { 49971da177e4SLinus Torvalds struct sctp_prim prim; 49981da177e4SLinus Torvalds struct sctp_association *asoc; 49991da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 50001da177e4SLinus Torvalds 5001408f22e8SNeil Horman if (len < sizeof(struct sctp_prim)) 50021da177e4SLinus Torvalds return -EINVAL; 50031da177e4SLinus Torvalds 5004408f22e8SNeil Horman len = sizeof(struct sctp_prim); 5005408f22e8SNeil Horman 5006408f22e8SNeil Horman if (copy_from_user(&prim, optval, len)) 50071da177e4SLinus Torvalds return -EFAULT; 50081da177e4SLinus Torvalds 50091da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); 50101da177e4SLinus Torvalds if (!asoc) 50111da177e4SLinus Torvalds return -EINVAL; 50121da177e4SLinus Torvalds 50131da177e4SLinus Torvalds if (!asoc->peer.primary_path) 50141da177e4SLinus Torvalds return -ENOTCONN; 50151da177e4SLinus Torvalds 50168cec6b80SAl Viro memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, 50178cec6b80SAl Viro asoc->peer.primary_path->af_specific->sockaddr_len); 50181da177e4SLinus Torvalds 5019299ee123SJason Gunthorpe sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp, 50201da177e4SLinus Torvalds (union sctp_addr *)&prim.ssp_addr); 50211da177e4SLinus Torvalds 5022408f22e8SNeil Horman if (put_user(len, optlen)) 5023408f22e8SNeil Horman return -EFAULT; 5024408f22e8SNeil Horman if (copy_to_user(optval, &prim, len)) 50251da177e4SLinus Torvalds return -EFAULT; 50261da177e4SLinus Torvalds 50271da177e4SLinus Torvalds return 0; 50281da177e4SLinus Torvalds } 50291da177e4SLinus Torvalds 50301da177e4SLinus Torvalds /* 50310f3fffd8SIvan Skytte Jorgensen * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) 50321da177e4SLinus Torvalds * 50330f3fffd8SIvan Skytte Jorgensen * Requests that the local endpoint set the specified Adaptation Layer 50341da177e4SLinus Torvalds * Indication parameter for all future INIT and INIT-ACK exchanges. 50351da177e4SLinus Torvalds */ 50360f3fffd8SIvan Skytte Jorgensen static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len, 50371da177e4SLinus Torvalds char __user *optval, int __user *optlen) 50381da177e4SLinus Torvalds { 50390f3fffd8SIvan Skytte Jorgensen struct sctp_setadaptation adaptation; 50401da177e4SLinus Torvalds 5041408f22e8SNeil Horman if (len < sizeof(struct sctp_setadaptation)) 50421da177e4SLinus Torvalds return -EINVAL; 50431da177e4SLinus Torvalds 5044408f22e8SNeil Horman len = sizeof(struct sctp_setadaptation); 5045408f22e8SNeil Horman 50460f3fffd8SIvan Skytte Jorgensen adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind; 5047408f22e8SNeil Horman 5048408f22e8SNeil Horman if (put_user(len, optlen)) 5049408f22e8SNeil Horman return -EFAULT; 50500f3fffd8SIvan Skytte Jorgensen if (copy_to_user(optval, &adaptation, len)) 50511da177e4SLinus Torvalds return -EFAULT; 5052a1ab3582SIvan Skytte Jorgensen 50531da177e4SLinus Torvalds return 0; 50541da177e4SLinus Torvalds } 50551da177e4SLinus Torvalds 50561da177e4SLinus Torvalds /* 50571da177e4SLinus Torvalds * 50581da177e4SLinus Torvalds * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) 50591da177e4SLinus Torvalds * 50601da177e4SLinus Torvalds * Applications that wish to use the sendto() system call may wish to 50611da177e4SLinus Torvalds * specify a default set of parameters that would normally be supplied 50621da177e4SLinus Torvalds * through the inclusion of ancillary data. This socket option allows 50631da177e4SLinus Torvalds * such an application to set the default sctp_sndrcvinfo structure. 50641da177e4SLinus Torvalds 50651da177e4SLinus Torvalds 50661da177e4SLinus Torvalds * The application that wishes to use this socket option simply passes 50671da177e4SLinus Torvalds * in to this call the sctp_sndrcvinfo structure defined in Section 50681da177e4SLinus Torvalds * 5.2.2) The input parameters accepted by this call include 50691da177e4SLinus Torvalds * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, 50701da177e4SLinus Torvalds * sinfo_timetolive. The user must provide the sinfo_assoc_id field in 50711da177e4SLinus Torvalds * to this call if the caller is using the UDP model. 50721da177e4SLinus Torvalds * 50731da177e4SLinus Torvalds * For getsockopt, it get the default sctp_sndrcvinfo structure. 50741da177e4SLinus Torvalds */ 50751da177e4SLinus Torvalds static int sctp_getsockopt_default_send_param(struct sock *sk, 50761da177e4SLinus Torvalds int len, char __user *optval, 50771da177e4SLinus Torvalds int __user *optlen) 50781da177e4SLinus Torvalds { 50791da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 50806b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 50816b3fd5f3SGeir Ola Vaagland struct sctp_sndrcvinfo info; 50821da177e4SLinus Torvalds 50836b3fd5f3SGeir Ola Vaagland if (len < sizeof(info)) 50841da177e4SLinus Torvalds return -EINVAL; 5085408f22e8SNeil Horman 50866b3fd5f3SGeir Ola Vaagland len = sizeof(info); 5087408f22e8SNeil Horman 5088408f22e8SNeil Horman if (copy_from_user(&info, optval, len)) 50891da177e4SLinus Torvalds return -EFAULT; 50901da177e4SLinus Torvalds 50911da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); 50921da177e4SLinus Torvalds if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) 50931da177e4SLinus Torvalds return -EINVAL; 50941da177e4SLinus Torvalds if (asoc) { 50951da177e4SLinus Torvalds info.sinfo_stream = asoc->default_stream; 50961da177e4SLinus Torvalds info.sinfo_flags = asoc->default_flags; 50971da177e4SLinus Torvalds info.sinfo_ppid = asoc->default_ppid; 50981da177e4SLinus Torvalds info.sinfo_context = asoc->default_context; 50991da177e4SLinus Torvalds info.sinfo_timetolive = asoc->default_timetolive; 51001da177e4SLinus Torvalds } else { 51011da177e4SLinus Torvalds info.sinfo_stream = sp->default_stream; 51021da177e4SLinus Torvalds info.sinfo_flags = sp->default_flags; 51031da177e4SLinus Torvalds info.sinfo_ppid = sp->default_ppid; 51041da177e4SLinus Torvalds info.sinfo_context = sp->default_context; 51051da177e4SLinus Torvalds info.sinfo_timetolive = sp->default_timetolive; 51061da177e4SLinus Torvalds } 51071da177e4SLinus Torvalds 5108408f22e8SNeil Horman if (put_user(len, optlen)) 5109408f22e8SNeil Horman return -EFAULT; 5110408f22e8SNeil Horman if (copy_to_user(optval, &info, len)) 51111da177e4SLinus Torvalds return -EFAULT; 51121da177e4SLinus Torvalds 51131da177e4SLinus Torvalds return 0; 51141da177e4SLinus Torvalds } 51151da177e4SLinus Torvalds 51166b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters 51176b3fd5f3SGeir Ola Vaagland * (SCTP_DEFAULT_SNDINFO) 51186b3fd5f3SGeir Ola Vaagland */ 51196b3fd5f3SGeir Ola Vaagland static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len, 51206b3fd5f3SGeir Ola Vaagland char __user *optval, 51216b3fd5f3SGeir Ola Vaagland int __user *optlen) 51226b3fd5f3SGeir Ola Vaagland { 51236b3fd5f3SGeir Ola Vaagland struct sctp_sock *sp = sctp_sk(sk); 51246b3fd5f3SGeir Ola Vaagland struct sctp_association *asoc; 51256b3fd5f3SGeir Ola Vaagland struct sctp_sndinfo info; 51266b3fd5f3SGeir Ola Vaagland 51276b3fd5f3SGeir Ola Vaagland if (len < sizeof(info)) 51286b3fd5f3SGeir Ola Vaagland return -EINVAL; 51296b3fd5f3SGeir Ola Vaagland 51306b3fd5f3SGeir Ola Vaagland len = sizeof(info); 51316b3fd5f3SGeir Ola Vaagland 51326b3fd5f3SGeir Ola Vaagland if (copy_from_user(&info, optval, len)) 51336b3fd5f3SGeir Ola Vaagland return -EFAULT; 51346b3fd5f3SGeir Ola Vaagland 51356b3fd5f3SGeir Ola Vaagland asoc = sctp_id2assoc(sk, info.snd_assoc_id); 51366b3fd5f3SGeir Ola Vaagland if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) 51376b3fd5f3SGeir Ola Vaagland return -EINVAL; 51386b3fd5f3SGeir Ola Vaagland if (asoc) { 51396b3fd5f3SGeir Ola Vaagland info.snd_sid = asoc->default_stream; 51406b3fd5f3SGeir Ola Vaagland info.snd_flags = asoc->default_flags; 51416b3fd5f3SGeir Ola Vaagland info.snd_ppid = asoc->default_ppid; 51426b3fd5f3SGeir Ola Vaagland info.snd_context = asoc->default_context; 51436b3fd5f3SGeir Ola Vaagland } else { 51446b3fd5f3SGeir Ola Vaagland info.snd_sid = sp->default_stream; 51456b3fd5f3SGeir Ola Vaagland info.snd_flags = sp->default_flags; 51466b3fd5f3SGeir Ola Vaagland info.snd_ppid = sp->default_ppid; 51476b3fd5f3SGeir Ola Vaagland info.snd_context = sp->default_context; 51486b3fd5f3SGeir Ola Vaagland } 51496b3fd5f3SGeir Ola Vaagland 51506b3fd5f3SGeir Ola Vaagland if (put_user(len, optlen)) 51516b3fd5f3SGeir Ola Vaagland return -EFAULT; 51526b3fd5f3SGeir Ola Vaagland if (copy_to_user(optval, &info, len)) 51536b3fd5f3SGeir Ola Vaagland return -EFAULT; 51546b3fd5f3SGeir Ola Vaagland 51556b3fd5f3SGeir Ola Vaagland return 0; 51566b3fd5f3SGeir Ola Vaagland } 51576b3fd5f3SGeir Ola Vaagland 51581da177e4SLinus Torvalds /* 51591da177e4SLinus Torvalds * 51601da177e4SLinus Torvalds * 7.1.5 SCTP_NODELAY 51611da177e4SLinus Torvalds * 51621da177e4SLinus Torvalds * Turn on/off any Nagle-like algorithm. This means that packets are 51631da177e4SLinus Torvalds * generally sent as soon as possible and no unnecessary delays are 51641da177e4SLinus Torvalds * introduced, at the cost of more packets in the network. Expects an 51651da177e4SLinus Torvalds * integer boolean flag. 51661da177e4SLinus Torvalds */ 51671da177e4SLinus Torvalds 51681da177e4SLinus Torvalds static int sctp_getsockopt_nodelay(struct sock *sk, int len, 51691da177e4SLinus Torvalds char __user *optval, int __user *optlen) 51701da177e4SLinus Torvalds { 51711da177e4SLinus Torvalds int val; 51721da177e4SLinus Torvalds 51731da177e4SLinus Torvalds if (len < sizeof(int)) 51741da177e4SLinus Torvalds return -EINVAL; 51751da177e4SLinus Torvalds 51761da177e4SLinus Torvalds len = sizeof(int); 51771da177e4SLinus Torvalds val = (sctp_sk(sk)->nodelay == 1); 51781da177e4SLinus Torvalds if (put_user(len, optlen)) 51791da177e4SLinus Torvalds return -EFAULT; 51801da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 51811da177e4SLinus Torvalds return -EFAULT; 51821da177e4SLinus Torvalds return 0; 51831da177e4SLinus Torvalds } 51841da177e4SLinus Torvalds 51851da177e4SLinus Torvalds /* 51861da177e4SLinus Torvalds * 51871da177e4SLinus Torvalds * 7.1.1 SCTP_RTOINFO 51881da177e4SLinus Torvalds * 51891da177e4SLinus Torvalds * The protocol parameters used to initialize and bound retransmission 51901da177e4SLinus Torvalds * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access 51911da177e4SLinus Torvalds * and modify these parameters. 51921da177e4SLinus Torvalds * All parameters are time values, in milliseconds. A value of 0, when 51931da177e4SLinus Torvalds * modifying the parameters, indicates that the current value should not 51941da177e4SLinus Torvalds * be changed. 51951da177e4SLinus Torvalds * 51961da177e4SLinus Torvalds */ 51971da177e4SLinus Torvalds static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, 51981da177e4SLinus Torvalds char __user *optval, 51991da177e4SLinus Torvalds int __user *optlen) { 52001da177e4SLinus Torvalds struct sctp_rtoinfo rtoinfo; 52011da177e4SLinus Torvalds struct sctp_association *asoc; 52021da177e4SLinus Torvalds 5203408f22e8SNeil Horman if (len < sizeof (struct sctp_rtoinfo)) 52041da177e4SLinus Torvalds return -EINVAL; 52051da177e4SLinus Torvalds 5206408f22e8SNeil Horman len = sizeof(struct sctp_rtoinfo); 5207408f22e8SNeil Horman 5208408f22e8SNeil Horman if (copy_from_user(&rtoinfo, optval, len)) 52091da177e4SLinus Torvalds return -EFAULT; 52101da177e4SLinus Torvalds 52111da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); 52121da177e4SLinus Torvalds 52131da177e4SLinus Torvalds if (!asoc && rtoinfo.srto_assoc_id && sctp_style(sk, UDP)) 52141da177e4SLinus Torvalds return -EINVAL; 52151da177e4SLinus Torvalds 52161da177e4SLinus Torvalds /* Values corresponding to the specific association. */ 52171da177e4SLinus Torvalds if (asoc) { 52181da177e4SLinus Torvalds rtoinfo.srto_initial = jiffies_to_msecs(asoc->rto_initial); 52191da177e4SLinus Torvalds rtoinfo.srto_max = jiffies_to_msecs(asoc->rto_max); 52201da177e4SLinus Torvalds rtoinfo.srto_min = jiffies_to_msecs(asoc->rto_min); 52211da177e4SLinus Torvalds } else { 52221da177e4SLinus Torvalds /* Values corresponding to the endpoint. */ 52231da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 52241da177e4SLinus Torvalds 52251da177e4SLinus Torvalds rtoinfo.srto_initial = sp->rtoinfo.srto_initial; 52261da177e4SLinus Torvalds rtoinfo.srto_max = sp->rtoinfo.srto_max; 52271da177e4SLinus Torvalds rtoinfo.srto_min = sp->rtoinfo.srto_min; 52281da177e4SLinus Torvalds } 52291da177e4SLinus Torvalds 52301da177e4SLinus Torvalds if (put_user(len, optlen)) 52311da177e4SLinus Torvalds return -EFAULT; 52321da177e4SLinus Torvalds 52331da177e4SLinus Torvalds if (copy_to_user(optval, &rtoinfo, len)) 52341da177e4SLinus Torvalds return -EFAULT; 52351da177e4SLinus Torvalds 52361da177e4SLinus Torvalds return 0; 52371da177e4SLinus Torvalds } 52381da177e4SLinus Torvalds 52391da177e4SLinus Torvalds /* 52401da177e4SLinus Torvalds * 52411da177e4SLinus Torvalds * 7.1.2 SCTP_ASSOCINFO 52421da177e4SLinus Torvalds * 524359c51591SMichael Opdenacker * This option is used to tune the maximum retransmission attempts 52441da177e4SLinus Torvalds * of the association. 52451da177e4SLinus Torvalds * Returns an error if the new association retransmission value is 52461da177e4SLinus Torvalds * greater than the sum of the retransmission value of the peer. 52471da177e4SLinus Torvalds * See [SCTP] for more information. 52481da177e4SLinus Torvalds * 52491da177e4SLinus Torvalds */ 52501da177e4SLinus Torvalds static int sctp_getsockopt_associnfo(struct sock *sk, int len, 52511da177e4SLinus Torvalds char __user *optval, 52521da177e4SLinus Torvalds int __user *optlen) 52531da177e4SLinus Torvalds { 52541da177e4SLinus Torvalds 52551da177e4SLinus Torvalds struct sctp_assocparams assocparams; 52561da177e4SLinus Torvalds struct sctp_association *asoc; 52571da177e4SLinus Torvalds struct list_head *pos; 52581da177e4SLinus Torvalds int cnt = 0; 52591da177e4SLinus Torvalds 5260408f22e8SNeil Horman if (len < sizeof (struct sctp_assocparams)) 52611da177e4SLinus Torvalds return -EINVAL; 52621da177e4SLinus Torvalds 5263408f22e8SNeil Horman len = sizeof(struct sctp_assocparams); 5264408f22e8SNeil Horman 5265408f22e8SNeil Horman if (copy_from_user(&assocparams, optval, len)) 52661da177e4SLinus Torvalds return -EFAULT; 52671da177e4SLinus Torvalds 52681da177e4SLinus Torvalds asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); 52691da177e4SLinus Torvalds 52701da177e4SLinus Torvalds if (!asoc && assocparams.sasoc_assoc_id && sctp_style(sk, UDP)) 52711da177e4SLinus Torvalds return -EINVAL; 52721da177e4SLinus Torvalds 52731da177e4SLinus Torvalds /* Values correspoinding to the specific association */ 527417337216SVladislav Yasevich if (asoc) { 52751da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt = asoc->max_retrans; 52761da177e4SLinus Torvalds assocparams.sasoc_peer_rwnd = asoc->peer.rwnd; 52771da177e4SLinus Torvalds assocparams.sasoc_local_rwnd = asoc->a_rwnd; 527852db882fSDaniel Borkmann assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life); 52791da177e4SLinus Torvalds 52801da177e4SLinus Torvalds list_for_each(pos, &asoc->peer.transport_addr_list) { 52811da177e4SLinus Torvalds cnt++; 52821da177e4SLinus Torvalds } 52831da177e4SLinus Torvalds 52841da177e4SLinus Torvalds assocparams.sasoc_number_peer_destinations = cnt; 52851da177e4SLinus Torvalds } else { 52861da177e4SLinus Torvalds /* Values corresponding to the endpoint */ 52871da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 52881da177e4SLinus Torvalds 52891da177e4SLinus Torvalds assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt; 52901da177e4SLinus Torvalds assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd; 52911da177e4SLinus Torvalds assocparams.sasoc_local_rwnd = sp->assocparams.sasoc_local_rwnd; 52921da177e4SLinus Torvalds assocparams.sasoc_cookie_life = 52931da177e4SLinus Torvalds sp->assocparams.sasoc_cookie_life; 52941da177e4SLinus Torvalds assocparams.sasoc_number_peer_destinations = 52951da177e4SLinus Torvalds sp->assocparams. 52961da177e4SLinus Torvalds sasoc_number_peer_destinations; 52971da177e4SLinus Torvalds } 52981da177e4SLinus Torvalds 52991da177e4SLinus Torvalds if (put_user(len, optlen)) 53001da177e4SLinus Torvalds return -EFAULT; 53011da177e4SLinus Torvalds 53021da177e4SLinus Torvalds if (copy_to_user(optval, &assocparams, len)) 53031da177e4SLinus Torvalds return -EFAULT; 53041da177e4SLinus Torvalds 53051da177e4SLinus Torvalds return 0; 53061da177e4SLinus Torvalds } 53071da177e4SLinus Torvalds 53081da177e4SLinus Torvalds /* 53091da177e4SLinus Torvalds * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) 53101da177e4SLinus Torvalds * 53111da177e4SLinus Torvalds * This socket option is a boolean flag which turns on or off mapped V4 53121da177e4SLinus Torvalds * addresses. If this option is turned on and the socket is type 53131da177e4SLinus Torvalds * PF_INET6, then IPv4 addresses will be mapped to V6 representation. 53141da177e4SLinus Torvalds * If this option is turned off, then no mapping will be done of V4 53151da177e4SLinus Torvalds * addresses and a user will receive both PF_INET6 and PF_INET type 53161da177e4SLinus Torvalds * addresses on the socket. 53171da177e4SLinus Torvalds */ 53181da177e4SLinus Torvalds static int sctp_getsockopt_mappedv4(struct sock *sk, int len, 53191da177e4SLinus Torvalds char __user *optval, int __user *optlen) 53201da177e4SLinus Torvalds { 53211da177e4SLinus Torvalds int val; 53221da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 53231da177e4SLinus Torvalds 53241da177e4SLinus Torvalds if (len < sizeof(int)) 53251da177e4SLinus Torvalds return -EINVAL; 53261da177e4SLinus Torvalds 53271da177e4SLinus Torvalds len = sizeof(int); 53281da177e4SLinus Torvalds val = sp->v4mapped; 53291da177e4SLinus Torvalds if (put_user(len, optlen)) 53301da177e4SLinus Torvalds return -EFAULT; 53311da177e4SLinus Torvalds if (copy_to_user(optval, &val, len)) 53321da177e4SLinus Torvalds return -EFAULT; 53331da177e4SLinus Torvalds 53341da177e4SLinus Torvalds return 0; 53351da177e4SLinus Torvalds } 53361da177e4SLinus Torvalds 53371da177e4SLinus Torvalds /* 53386ab792f5SIvan Skytte Jorgensen * 7.1.29. Set or Get the default context (SCTP_CONTEXT) 53396ab792f5SIvan Skytte Jorgensen * (chapter and verse is quoted at sctp_setsockopt_context()) 53406ab792f5SIvan Skytte Jorgensen */ 53416ab792f5SIvan Skytte Jorgensen static int sctp_getsockopt_context(struct sock *sk, int len, 53426ab792f5SIvan Skytte Jorgensen char __user *optval, int __user *optlen) 53436ab792f5SIvan Skytte Jorgensen { 53446ab792f5SIvan Skytte Jorgensen struct sctp_assoc_value params; 53456ab792f5SIvan Skytte Jorgensen struct sctp_sock *sp; 53466ab792f5SIvan Skytte Jorgensen struct sctp_association *asoc; 53476ab792f5SIvan Skytte Jorgensen 5348408f22e8SNeil Horman if (len < sizeof(struct sctp_assoc_value)) 53496ab792f5SIvan Skytte Jorgensen return -EINVAL; 53506ab792f5SIvan Skytte Jorgensen 5351408f22e8SNeil Horman len = sizeof(struct sctp_assoc_value); 5352408f22e8SNeil Horman 53536ab792f5SIvan Skytte Jorgensen if (copy_from_user(¶ms, optval, len)) 53546ab792f5SIvan Skytte Jorgensen return -EFAULT; 53556ab792f5SIvan Skytte Jorgensen 53566ab792f5SIvan Skytte Jorgensen sp = sctp_sk(sk); 53576ab792f5SIvan Skytte Jorgensen 53586ab792f5SIvan Skytte Jorgensen if (params.assoc_id != 0) { 53596ab792f5SIvan Skytte Jorgensen asoc = sctp_id2assoc(sk, params.assoc_id); 53606ab792f5SIvan Skytte Jorgensen if (!asoc) 53616ab792f5SIvan Skytte Jorgensen return -EINVAL; 53626ab792f5SIvan Skytte Jorgensen params.assoc_value = asoc->default_rcv_context; 53636ab792f5SIvan Skytte Jorgensen } else { 53646ab792f5SIvan Skytte Jorgensen params.assoc_value = sp->default_rcv_context; 53656ab792f5SIvan Skytte Jorgensen } 53666ab792f5SIvan Skytte Jorgensen 53676ab792f5SIvan Skytte Jorgensen if (put_user(len, optlen)) 53686ab792f5SIvan Skytte Jorgensen return -EFAULT; 53696ab792f5SIvan Skytte Jorgensen if (copy_to_user(optval, ¶ms, len)) 53706ab792f5SIvan Skytte Jorgensen return -EFAULT; 53716ab792f5SIvan Skytte Jorgensen 53726ab792f5SIvan Skytte Jorgensen return 0; 53736ab792f5SIvan Skytte Jorgensen } 53746ab792f5SIvan Skytte Jorgensen 53756ab792f5SIvan Skytte Jorgensen /* 5376e89c2095SWei Yongjun * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) 5377e89c2095SWei Yongjun * This option will get or set the maximum size to put in any outgoing 5378e89c2095SWei Yongjun * SCTP DATA chunk. If a message is larger than this size it will be 53791da177e4SLinus Torvalds * fragmented by SCTP into the specified size. Note that the underlying 53801da177e4SLinus Torvalds * SCTP implementation may fragment into smaller sized chunks when the 53811da177e4SLinus Torvalds * PMTU of the underlying association is smaller than the value set by 5382e89c2095SWei Yongjun * the user. The default value for this option is '0' which indicates 5383e89c2095SWei Yongjun * the user is NOT limiting fragmentation and only the PMTU will effect 5384e89c2095SWei Yongjun * SCTP's choice of DATA chunk size. Note also that values set larger 5385e89c2095SWei Yongjun * than the maximum size of an IP datagram will effectively let SCTP 5386e89c2095SWei Yongjun * control fragmentation (i.e. the same as setting this option to 0). 5387e89c2095SWei Yongjun * 5388e89c2095SWei Yongjun * The following structure is used to access and modify this parameter: 5389e89c2095SWei Yongjun * 5390e89c2095SWei Yongjun * struct sctp_assoc_value { 5391e89c2095SWei Yongjun * sctp_assoc_t assoc_id; 5392e89c2095SWei Yongjun * uint32_t assoc_value; 5393e89c2095SWei Yongjun * }; 5394e89c2095SWei Yongjun * 5395e89c2095SWei Yongjun * assoc_id: This parameter is ignored for one-to-one style sockets. 5396e89c2095SWei Yongjun * For one-to-many style sockets this parameter indicates which 5397e89c2095SWei Yongjun * association the user is performing an action upon. Note that if 5398e89c2095SWei Yongjun * this field's value is zero then the endpoints default value is 5399e89c2095SWei Yongjun * changed (effecting future associations only). 5400e89c2095SWei Yongjun * assoc_value: This parameter specifies the maximum size in bytes. 54011da177e4SLinus Torvalds */ 54021da177e4SLinus Torvalds static int sctp_getsockopt_maxseg(struct sock *sk, int len, 54031da177e4SLinus Torvalds char __user *optval, int __user *optlen) 54041da177e4SLinus Torvalds { 5405e89c2095SWei Yongjun struct sctp_assoc_value params; 5406e89c2095SWei Yongjun struct sctp_association *asoc; 54071da177e4SLinus Torvalds 5408e89c2095SWei Yongjun if (len == sizeof(int)) { 540994f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 5410f916ec96SNeil Horman "%s (pid %d) " 541194f65193SNeil Horman "Use of int in maxseg socket option.\n" 5412f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 5413f916ec96SNeil Horman current->comm, task_pid_nr(current)); 5414e89c2095SWei Yongjun params.assoc_id = 0; 5415e89c2095SWei Yongjun } else if (len >= sizeof(struct sctp_assoc_value)) { 5416e89c2095SWei Yongjun len = sizeof(struct sctp_assoc_value); 5417e89c2095SWei Yongjun if (copy_from_user(¶ms, optval, sizeof(params))) 5418e89c2095SWei Yongjun return -EFAULT; 5419e89c2095SWei Yongjun } else 54201da177e4SLinus Torvalds return -EINVAL; 54211da177e4SLinus Torvalds 5422e89c2095SWei Yongjun asoc = sctp_id2assoc(sk, params.assoc_id); 5423e89c2095SWei Yongjun if (!asoc && params.assoc_id && sctp_style(sk, UDP)) 5424e89c2095SWei Yongjun return -EINVAL; 54251da177e4SLinus Torvalds 5426e89c2095SWei Yongjun if (asoc) 5427e89c2095SWei Yongjun params.assoc_value = asoc->frag_point; 5428e89c2095SWei Yongjun else 5429e89c2095SWei Yongjun params.assoc_value = sctp_sk(sk)->user_frag; 5430e89c2095SWei Yongjun 54311da177e4SLinus Torvalds if (put_user(len, optlen)) 54321da177e4SLinus Torvalds return -EFAULT; 5433e89c2095SWei Yongjun if (len == sizeof(int)) { 5434e89c2095SWei Yongjun if (copy_to_user(optval, ¶ms.assoc_value, len)) 54351da177e4SLinus Torvalds return -EFAULT; 5436e89c2095SWei Yongjun } else { 5437e89c2095SWei Yongjun if (copy_to_user(optval, ¶ms, len)) 5438e89c2095SWei Yongjun return -EFAULT; 5439e89c2095SWei Yongjun } 54401da177e4SLinus Torvalds 54411da177e4SLinus Torvalds return 0; 54421da177e4SLinus Torvalds } 54431da177e4SLinus Torvalds 5444b6e1331fSVlad Yasevich /* 5445b6e1331fSVlad Yasevich * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE) 5446b6e1331fSVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_fragment_interleave()) 5447b6e1331fSVlad Yasevich */ 5448b6e1331fSVlad Yasevich static int sctp_getsockopt_fragment_interleave(struct sock *sk, int len, 5449b6e1331fSVlad Yasevich char __user *optval, int __user *optlen) 5450b6e1331fSVlad Yasevich { 5451b6e1331fSVlad Yasevich int val; 5452b6e1331fSVlad Yasevich 5453b6e1331fSVlad Yasevich if (len < sizeof(int)) 5454b6e1331fSVlad Yasevich return -EINVAL; 5455b6e1331fSVlad Yasevich 5456b6e1331fSVlad Yasevich len = sizeof(int); 5457b6e1331fSVlad Yasevich 5458b6e1331fSVlad Yasevich val = sctp_sk(sk)->frag_interleave; 5459b6e1331fSVlad Yasevich if (put_user(len, optlen)) 5460b6e1331fSVlad Yasevich return -EFAULT; 5461b6e1331fSVlad Yasevich if (copy_to_user(optval, &val, len)) 5462b6e1331fSVlad Yasevich return -EFAULT; 5463b6e1331fSVlad Yasevich 5464b6e1331fSVlad Yasevich return 0; 5465b6e1331fSVlad Yasevich } 5466b6e1331fSVlad Yasevich 5467d49d91d7SVlad Yasevich /* 5468d49d91d7SVlad Yasevich * 7.1.25. Set or Get the sctp partial delivery point 5469d49d91d7SVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_partial_delivery_point()) 5470d49d91d7SVlad Yasevich */ 5471d49d91d7SVlad Yasevich static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len, 5472d49d91d7SVlad Yasevich char __user *optval, 5473d49d91d7SVlad Yasevich int __user *optlen) 5474d49d91d7SVlad Yasevich { 5475d49d91d7SVlad Yasevich u32 val; 5476d49d91d7SVlad Yasevich 5477d49d91d7SVlad Yasevich if (len < sizeof(u32)) 5478d49d91d7SVlad Yasevich return -EINVAL; 5479d49d91d7SVlad Yasevich 5480d49d91d7SVlad Yasevich len = sizeof(u32); 5481d49d91d7SVlad Yasevich 5482d49d91d7SVlad Yasevich val = sctp_sk(sk)->pd_point; 5483d49d91d7SVlad Yasevich if (put_user(len, optlen)) 5484d49d91d7SVlad Yasevich return -EFAULT; 5485d49d91d7SVlad Yasevich if (copy_to_user(optval, &val, len)) 5486d49d91d7SVlad Yasevich return -EFAULT; 5487d49d91d7SVlad Yasevich 54887d743b7eSWei Yongjun return 0; 5489d49d91d7SVlad Yasevich } 5490d49d91d7SVlad Yasevich 549170331571SVlad Yasevich /* 549270331571SVlad Yasevich * 7.1.28. Set or Get the maximum burst (SCTP_MAX_BURST) 549370331571SVlad Yasevich * (chapter and verse is quoted at sctp_setsockopt_maxburst()) 549470331571SVlad Yasevich */ 549570331571SVlad Yasevich static int sctp_getsockopt_maxburst(struct sock *sk, int len, 549670331571SVlad Yasevich char __user *optval, 549770331571SVlad Yasevich int __user *optlen) 549870331571SVlad Yasevich { 5499219b99a9SNeil Horman struct sctp_assoc_value params; 5500219b99a9SNeil Horman struct sctp_sock *sp; 5501219b99a9SNeil Horman struct sctp_association *asoc; 550270331571SVlad Yasevich 5503219b99a9SNeil Horman if (len == sizeof(int)) { 550494f65193SNeil Horman pr_warn_ratelimited(DEPRECATED 5505f916ec96SNeil Horman "%s (pid %d) " 550694f65193SNeil Horman "Use of int in max_burst socket option.\n" 5507f916ec96SNeil Horman "Use struct sctp_assoc_value instead\n", 5508f916ec96SNeil Horman current->comm, task_pid_nr(current)); 5509219b99a9SNeil Horman params.assoc_id = 0; 5510c6db93a5SWei Yongjun } else if (len >= sizeof(struct sctp_assoc_value)) { 5511c6db93a5SWei Yongjun len = sizeof(struct sctp_assoc_value); 5512219b99a9SNeil Horman if (copy_from_user(¶ms, optval, len)) 551370331571SVlad Yasevich return -EFAULT; 5514219b99a9SNeil Horman } else 5515219b99a9SNeil Horman return -EINVAL; 551670331571SVlad Yasevich 5517219b99a9SNeil Horman sp = sctp_sk(sk); 5518219b99a9SNeil Horman 5519219b99a9SNeil Horman if (params.assoc_id != 0) { 5520219b99a9SNeil Horman asoc = sctp_id2assoc(sk, params.assoc_id); 5521219b99a9SNeil Horman if (!asoc) 5522219b99a9SNeil Horman return -EINVAL; 5523219b99a9SNeil Horman params.assoc_value = asoc->max_burst; 5524219b99a9SNeil Horman } else 5525219b99a9SNeil Horman params.assoc_value = sp->max_burst; 5526219b99a9SNeil Horman 5527219b99a9SNeil Horman if (len == sizeof(int)) { 5528219b99a9SNeil Horman if (copy_to_user(optval, ¶ms.assoc_value, len)) 5529219b99a9SNeil Horman return -EFAULT; 5530219b99a9SNeil Horman } else { 5531219b99a9SNeil Horman if (copy_to_user(optval, ¶ms, len)) 5532219b99a9SNeil Horman return -EFAULT; 5533219b99a9SNeil Horman } 5534219b99a9SNeil Horman 5535219b99a9SNeil Horman return 0; 5536219b99a9SNeil Horman 553770331571SVlad Yasevich } 553870331571SVlad Yasevich 553965b07e5dSVlad Yasevich static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, 554065b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 554165b07e5dSVlad Yasevich { 5542b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 55435e739d17SVlad Yasevich struct sctp_hmacalgo __user *p = (void __user *)optval; 554465b07e5dSVlad Yasevich struct sctp_hmac_algo_param *hmacs; 55455e739d17SVlad Yasevich __u16 data_len = 0; 55465e739d17SVlad Yasevich u32 num_idents; 55475e739d17SVlad Yasevich 5548b14878ccSVlad Yasevich if (!ep->auth_enable) 55495e739d17SVlad Yasevich return -EACCES; 555065b07e5dSVlad Yasevich 5551b14878ccSVlad Yasevich hmacs = ep->auth_hmacs_list; 55525e739d17SVlad Yasevich data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t); 555365b07e5dSVlad Yasevich 55545e739d17SVlad Yasevich if (len < sizeof(struct sctp_hmacalgo) + data_len) 555565b07e5dSVlad Yasevich return -EINVAL; 55565e739d17SVlad Yasevich 55575e739d17SVlad Yasevich len = sizeof(struct sctp_hmacalgo) + data_len; 55585e739d17SVlad Yasevich num_idents = data_len / sizeof(u16); 55595e739d17SVlad Yasevich 556065b07e5dSVlad Yasevich if (put_user(len, optlen)) 556165b07e5dSVlad Yasevich return -EFAULT; 55625e739d17SVlad Yasevich if (put_user(num_idents, &p->shmac_num_idents)) 556365b07e5dSVlad Yasevich return -EFAULT; 55645e739d17SVlad Yasevich if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len)) 55655e739d17SVlad Yasevich return -EFAULT; 556665b07e5dSVlad Yasevich return 0; 556765b07e5dSVlad Yasevich } 556865b07e5dSVlad Yasevich 556965b07e5dSVlad Yasevich static int sctp_getsockopt_active_key(struct sock *sk, int len, 557065b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 557165b07e5dSVlad Yasevich { 5572b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 557365b07e5dSVlad Yasevich struct sctp_authkeyid val; 557465b07e5dSVlad Yasevich struct sctp_association *asoc; 557565b07e5dSVlad Yasevich 5576b14878ccSVlad Yasevich if (!ep->auth_enable) 55775e739d17SVlad Yasevich return -EACCES; 55785e739d17SVlad Yasevich 557965b07e5dSVlad Yasevich if (len < sizeof(struct sctp_authkeyid)) 558065b07e5dSVlad Yasevich return -EINVAL; 558165b07e5dSVlad Yasevich if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) 558265b07e5dSVlad Yasevich return -EFAULT; 558365b07e5dSVlad Yasevich 558465b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.scact_assoc_id); 558565b07e5dSVlad Yasevich if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) 558665b07e5dSVlad Yasevich return -EINVAL; 558765b07e5dSVlad Yasevich 558865b07e5dSVlad Yasevich if (asoc) 558965b07e5dSVlad Yasevich val.scact_keynumber = asoc->active_key_id; 559065b07e5dSVlad Yasevich else 5591b14878ccSVlad Yasevich val.scact_keynumber = ep->active_key_id; 559265b07e5dSVlad Yasevich 55935e739d17SVlad Yasevich len = sizeof(struct sctp_authkeyid); 55945e739d17SVlad Yasevich if (put_user(len, optlen)) 55955e739d17SVlad Yasevich return -EFAULT; 55965e739d17SVlad Yasevich if (copy_to_user(optval, &val, len)) 55975e739d17SVlad Yasevich return -EFAULT; 55985e739d17SVlad Yasevich 559965b07e5dSVlad Yasevich return 0; 560065b07e5dSVlad Yasevich } 560165b07e5dSVlad Yasevich 560265b07e5dSVlad Yasevich static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, 560365b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 560465b07e5dSVlad Yasevich { 5605b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 5606411223c0SAl Viro struct sctp_authchunks __user *p = (void __user *)optval; 560765b07e5dSVlad Yasevich struct sctp_authchunks val; 560865b07e5dSVlad Yasevich struct sctp_association *asoc; 560965b07e5dSVlad Yasevich struct sctp_chunks_param *ch; 56105e739d17SVlad Yasevich u32 num_chunks = 0; 561165b07e5dSVlad Yasevich char __user *to; 561265b07e5dSVlad Yasevich 5613b14878ccSVlad Yasevich if (!ep->auth_enable) 56145e739d17SVlad Yasevich return -EACCES; 56155e739d17SVlad Yasevich 56165e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks)) 561765b07e5dSVlad Yasevich return -EINVAL; 561865b07e5dSVlad Yasevich 56195e739d17SVlad Yasevich if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) 562065b07e5dSVlad Yasevich return -EFAULT; 562165b07e5dSVlad Yasevich 5622411223c0SAl Viro to = p->gauth_chunks; 562365b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 562465b07e5dSVlad Yasevich if (!asoc) 562565b07e5dSVlad Yasevich return -EINVAL; 562665b07e5dSVlad Yasevich 562765b07e5dSVlad Yasevich ch = asoc->peer.peer_chunks; 56285e739d17SVlad Yasevich if (!ch) 56295e739d17SVlad Yasevich goto num; 563065b07e5dSVlad Yasevich 563165b07e5dSVlad Yasevich /* See if the user provided enough room for all the data */ 5632b40db684SVlad Yasevich num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); 5633b40db684SVlad Yasevich if (len < num_chunks) 563465b07e5dSVlad Yasevich return -EINVAL; 563565b07e5dSVlad Yasevich 56365e739d17SVlad Yasevich if (copy_to_user(to, ch->chunks, num_chunks)) 563765b07e5dSVlad Yasevich return -EFAULT; 56385e739d17SVlad Yasevich num: 56395e739d17SVlad Yasevich len = sizeof(struct sctp_authchunks) + num_chunks; 56408d72651dSwangweidong if (put_user(len, optlen)) 56418d72651dSwangweidong return -EFAULT; 56427e8616d8SVlad Yasevich if (put_user(num_chunks, &p->gauth_number_of_chunks)) 56437e8616d8SVlad Yasevich return -EFAULT; 564465b07e5dSVlad Yasevich return 0; 564565b07e5dSVlad Yasevich } 564665b07e5dSVlad Yasevich 564765b07e5dSVlad Yasevich static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, 564865b07e5dSVlad Yasevich char __user *optval, int __user *optlen) 564965b07e5dSVlad Yasevich { 5650b14878ccSVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 5651411223c0SAl Viro struct sctp_authchunks __user *p = (void __user *)optval; 565265b07e5dSVlad Yasevich struct sctp_authchunks val; 565365b07e5dSVlad Yasevich struct sctp_association *asoc; 565465b07e5dSVlad Yasevich struct sctp_chunks_param *ch; 56555e739d17SVlad Yasevich u32 num_chunks = 0; 565665b07e5dSVlad Yasevich char __user *to; 565765b07e5dSVlad Yasevich 5658b14878ccSVlad Yasevich if (!ep->auth_enable) 56595e739d17SVlad Yasevich return -EACCES; 56605e739d17SVlad Yasevich 56615e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks)) 566265b07e5dSVlad Yasevich return -EINVAL; 566365b07e5dSVlad Yasevich 56645e739d17SVlad Yasevich if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) 566565b07e5dSVlad Yasevich return -EFAULT; 566665b07e5dSVlad Yasevich 5667411223c0SAl Viro to = p->gauth_chunks; 566865b07e5dSVlad Yasevich asoc = sctp_id2assoc(sk, val.gauth_assoc_id); 566965b07e5dSVlad Yasevich if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP)) 567065b07e5dSVlad Yasevich return -EINVAL; 567165b07e5dSVlad Yasevich 567265b07e5dSVlad Yasevich if (asoc) 567365b07e5dSVlad Yasevich ch = (struct sctp_chunks_param *)asoc->c.auth_chunks; 567465b07e5dSVlad Yasevich else 5675b14878ccSVlad Yasevich ch = ep->auth_chunk_list; 567665b07e5dSVlad Yasevich 56775e739d17SVlad Yasevich if (!ch) 56785e739d17SVlad Yasevich goto num; 56795e739d17SVlad Yasevich 5680b40db684SVlad Yasevich num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); 56815e739d17SVlad Yasevich if (len < sizeof(struct sctp_authchunks) + num_chunks) 568265b07e5dSVlad Yasevich return -EINVAL; 568365b07e5dSVlad Yasevich 56845e739d17SVlad Yasevich if (copy_to_user(to, ch->chunks, num_chunks)) 56855e739d17SVlad Yasevich return -EFAULT; 56865e739d17SVlad Yasevich num: 56875e739d17SVlad Yasevich len = sizeof(struct sctp_authchunks) + num_chunks; 568865b07e5dSVlad Yasevich if (put_user(len, optlen)) 568965b07e5dSVlad Yasevich return -EFAULT; 56907e8616d8SVlad Yasevich if (put_user(num_chunks, &p->gauth_number_of_chunks)) 56917e8616d8SVlad Yasevich return -EFAULT; 569265b07e5dSVlad Yasevich 569365b07e5dSVlad Yasevich return 0; 569465b07e5dSVlad Yasevich } 569565b07e5dSVlad Yasevich 5696aea3c5c0SWei Yongjun /* 5697aea3c5c0SWei Yongjun * 8.2.5. Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER) 5698aea3c5c0SWei Yongjun * This option gets the current number of associations that are attached 5699aea3c5c0SWei Yongjun * to a one-to-many style socket. The option value is an uint32_t. 5700aea3c5c0SWei Yongjun */ 5701aea3c5c0SWei Yongjun static int sctp_getsockopt_assoc_number(struct sock *sk, int len, 5702aea3c5c0SWei Yongjun char __user *optval, int __user *optlen) 5703aea3c5c0SWei Yongjun { 5704aea3c5c0SWei Yongjun struct sctp_sock *sp = sctp_sk(sk); 5705aea3c5c0SWei Yongjun struct sctp_association *asoc; 5706aea3c5c0SWei Yongjun u32 val = 0; 5707aea3c5c0SWei Yongjun 5708aea3c5c0SWei Yongjun if (sctp_style(sk, TCP)) 5709aea3c5c0SWei Yongjun return -EOPNOTSUPP; 5710aea3c5c0SWei Yongjun 5711aea3c5c0SWei Yongjun if (len < sizeof(u32)) 5712aea3c5c0SWei Yongjun return -EINVAL; 5713aea3c5c0SWei Yongjun 5714aea3c5c0SWei Yongjun len = sizeof(u32); 5715aea3c5c0SWei Yongjun 5716aea3c5c0SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 5717aea3c5c0SWei Yongjun val++; 5718aea3c5c0SWei Yongjun } 5719aea3c5c0SWei Yongjun 5720aea3c5c0SWei Yongjun if (put_user(len, optlen)) 5721aea3c5c0SWei Yongjun return -EFAULT; 5722aea3c5c0SWei Yongjun if (copy_to_user(optval, &val, len)) 5723aea3c5c0SWei Yongjun return -EFAULT; 5724aea3c5c0SWei Yongjun 5725aea3c5c0SWei Yongjun return 0; 5726aea3c5c0SWei Yongjun } 5727aea3c5c0SWei Yongjun 5728209ba424SWei Yongjun /* 57297dc04d71SMichio Honda * 8.1.23 SCTP_AUTO_ASCONF 57307dc04d71SMichio Honda * See the corresponding setsockopt entry as description 57317dc04d71SMichio Honda */ 57327dc04d71SMichio Honda static int sctp_getsockopt_auto_asconf(struct sock *sk, int len, 57337dc04d71SMichio Honda char __user *optval, int __user *optlen) 57347dc04d71SMichio Honda { 57357dc04d71SMichio Honda int val = 0; 57367dc04d71SMichio Honda 57377dc04d71SMichio Honda if (len < sizeof(int)) 57387dc04d71SMichio Honda return -EINVAL; 57397dc04d71SMichio Honda 57407dc04d71SMichio Honda len = sizeof(int); 57417dc04d71SMichio Honda if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk)) 57427dc04d71SMichio Honda val = 1; 57437dc04d71SMichio Honda if (put_user(len, optlen)) 57447dc04d71SMichio Honda return -EFAULT; 57457dc04d71SMichio Honda if (copy_to_user(optval, &val, len)) 57467dc04d71SMichio Honda return -EFAULT; 57477dc04d71SMichio Honda return 0; 57487dc04d71SMichio Honda } 57497dc04d71SMichio Honda 57507dc04d71SMichio Honda /* 5751209ba424SWei Yongjun * 8.2.6. Get the Current Identifiers of Associations 5752209ba424SWei Yongjun * (SCTP_GET_ASSOC_ID_LIST) 5753209ba424SWei Yongjun * 5754209ba424SWei Yongjun * This option gets the current list of SCTP association identifiers of 5755209ba424SWei Yongjun * the SCTP associations handled by a one-to-many style socket. 5756209ba424SWei Yongjun */ 5757209ba424SWei Yongjun static int sctp_getsockopt_assoc_ids(struct sock *sk, int len, 5758209ba424SWei Yongjun char __user *optval, int __user *optlen) 5759209ba424SWei Yongjun { 5760209ba424SWei Yongjun struct sctp_sock *sp = sctp_sk(sk); 5761209ba424SWei Yongjun struct sctp_association *asoc; 5762209ba424SWei Yongjun struct sctp_assoc_ids *ids; 5763209ba424SWei Yongjun u32 num = 0; 5764209ba424SWei Yongjun 5765209ba424SWei Yongjun if (sctp_style(sk, TCP)) 5766209ba424SWei Yongjun return -EOPNOTSUPP; 5767209ba424SWei Yongjun 5768209ba424SWei Yongjun if (len < sizeof(struct sctp_assoc_ids)) 5769209ba424SWei Yongjun return -EINVAL; 5770209ba424SWei Yongjun 5771209ba424SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 5772209ba424SWei Yongjun num++; 5773209ba424SWei Yongjun } 5774209ba424SWei Yongjun 5775209ba424SWei Yongjun if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num) 5776209ba424SWei Yongjun return -EINVAL; 5777209ba424SWei Yongjun 5778209ba424SWei Yongjun len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num; 5779209ba424SWei Yongjun 5780209ba424SWei Yongjun ids = kmalloc(len, GFP_KERNEL); 5781209ba424SWei Yongjun if (unlikely(!ids)) 5782209ba424SWei Yongjun return -ENOMEM; 5783209ba424SWei Yongjun 5784209ba424SWei Yongjun ids->gaids_number_of_ids = num; 5785209ba424SWei Yongjun num = 0; 5786209ba424SWei Yongjun list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { 5787209ba424SWei Yongjun ids->gaids_assoc_id[num++] = asoc->assoc_id; 5788209ba424SWei Yongjun } 5789209ba424SWei Yongjun 5790209ba424SWei Yongjun if (put_user(len, optlen) || copy_to_user(optval, ids, len)) { 5791209ba424SWei Yongjun kfree(ids); 5792209ba424SWei Yongjun return -EFAULT; 5793209ba424SWei Yongjun } 5794209ba424SWei Yongjun 5795209ba424SWei Yongjun kfree(ids); 5796209ba424SWei Yongjun return 0; 5797209ba424SWei Yongjun } 5798209ba424SWei Yongjun 57995aa93bcfSNeil Horman /* 58005aa93bcfSNeil Horman * SCTP_PEER_ADDR_THLDS 58015aa93bcfSNeil Horman * 58025aa93bcfSNeil Horman * This option allows us to fetch the partially failed threshold for one or all 58035aa93bcfSNeil Horman * transports in an association. See Section 6.1 of: 58045aa93bcfSNeil Horman * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt 58055aa93bcfSNeil Horman */ 58065aa93bcfSNeil Horman static int sctp_getsockopt_paddr_thresholds(struct sock *sk, 58075aa93bcfSNeil Horman char __user *optval, 58085aa93bcfSNeil Horman int len, 58095aa93bcfSNeil Horman int __user *optlen) 58105aa93bcfSNeil Horman { 58115aa93bcfSNeil Horman struct sctp_paddrthlds val; 58125aa93bcfSNeil Horman struct sctp_transport *trans; 58135aa93bcfSNeil Horman struct sctp_association *asoc; 58145aa93bcfSNeil Horman 58155aa93bcfSNeil Horman if (len < sizeof(struct sctp_paddrthlds)) 58165aa93bcfSNeil Horman return -EINVAL; 58175aa93bcfSNeil Horman len = sizeof(struct sctp_paddrthlds); 58185aa93bcfSNeil Horman if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, len)) 58195aa93bcfSNeil Horman return -EFAULT; 58205aa93bcfSNeil Horman 58215aa93bcfSNeil Horman if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { 58225aa93bcfSNeil Horman asoc = sctp_id2assoc(sk, val.spt_assoc_id); 58235aa93bcfSNeil Horman if (!asoc) 58245aa93bcfSNeil Horman return -ENOENT; 58255aa93bcfSNeil Horman 58265aa93bcfSNeil Horman val.spt_pathpfthld = asoc->pf_retrans; 58275aa93bcfSNeil Horman val.spt_pathmaxrxt = asoc->pathmaxrxt; 58285aa93bcfSNeil Horman } else { 58295aa93bcfSNeil Horman trans = sctp_addr_id2transport(sk, &val.spt_address, 58305aa93bcfSNeil Horman val.spt_assoc_id); 58315aa93bcfSNeil Horman if (!trans) 58325aa93bcfSNeil Horman return -ENOENT; 58335aa93bcfSNeil Horman 58345aa93bcfSNeil Horman val.spt_pathmaxrxt = trans->pathmaxrxt; 58355aa93bcfSNeil Horman val.spt_pathpfthld = trans->pf_retrans; 58365aa93bcfSNeil Horman } 58375aa93bcfSNeil Horman 58385aa93bcfSNeil Horman if (put_user(len, optlen) || copy_to_user(optval, &val, len)) 58395aa93bcfSNeil Horman return -EFAULT; 58405aa93bcfSNeil Horman 58415aa93bcfSNeil Horman return 0; 58425aa93bcfSNeil Horman } 58435aa93bcfSNeil Horman 5844196d6759SMichele Baldessari /* 5845196d6759SMichele Baldessari * SCTP_GET_ASSOC_STATS 5846196d6759SMichele Baldessari * 5847196d6759SMichele Baldessari * This option retrieves local per endpoint statistics. It is modeled 5848196d6759SMichele Baldessari * after OpenSolaris' implementation 5849196d6759SMichele Baldessari */ 5850196d6759SMichele Baldessari static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, 5851196d6759SMichele Baldessari char __user *optval, 5852196d6759SMichele Baldessari int __user *optlen) 5853196d6759SMichele Baldessari { 5854196d6759SMichele Baldessari struct sctp_assoc_stats sas; 5855196d6759SMichele Baldessari struct sctp_association *asoc = NULL; 5856196d6759SMichele Baldessari 5857196d6759SMichele Baldessari /* User must provide at least the assoc id */ 5858196d6759SMichele Baldessari if (len < sizeof(sctp_assoc_t)) 5859196d6759SMichele Baldessari return -EINVAL; 5860196d6759SMichele Baldessari 5861726bc6b0SGuenter Roeck /* Allow the struct to grow and fill in as much as possible */ 5862726bc6b0SGuenter Roeck len = min_t(size_t, len, sizeof(sas)); 5863726bc6b0SGuenter Roeck 5864196d6759SMichele Baldessari if (copy_from_user(&sas, optval, len)) 5865196d6759SMichele Baldessari return -EFAULT; 5866196d6759SMichele Baldessari 5867196d6759SMichele Baldessari asoc = sctp_id2assoc(sk, sas.sas_assoc_id); 5868196d6759SMichele Baldessari if (!asoc) 5869196d6759SMichele Baldessari return -EINVAL; 5870196d6759SMichele Baldessari 5871196d6759SMichele Baldessari sas.sas_rtxchunks = asoc->stats.rtxchunks; 5872196d6759SMichele Baldessari sas.sas_gapcnt = asoc->stats.gapcnt; 5873196d6759SMichele Baldessari sas.sas_outofseqtsns = asoc->stats.outofseqtsns; 5874196d6759SMichele Baldessari sas.sas_osacks = asoc->stats.osacks; 5875196d6759SMichele Baldessari sas.sas_isacks = asoc->stats.isacks; 5876196d6759SMichele Baldessari sas.sas_octrlchunks = asoc->stats.octrlchunks; 5877196d6759SMichele Baldessari sas.sas_ictrlchunks = asoc->stats.ictrlchunks; 5878196d6759SMichele Baldessari sas.sas_oodchunks = asoc->stats.oodchunks; 5879196d6759SMichele Baldessari sas.sas_iodchunks = asoc->stats.iodchunks; 5880196d6759SMichele Baldessari sas.sas_ouodchunks = asoc->stats.ouodchunks; 5881196d6759SMichele Baldessari sas.sas_iuodchunks = asoc->stats.iuodchunks; 5882196d6759SMichele Baldessari sas.sas_idupchunks = asoc->stats.idupchunks; 5883196d6759SMichele Baldessari sas.sas_opackets = asoc->stats.opackets; 5884196d6759SMichele Baldessari sas.sas_ipackets = asoc->stats.ipackets; 5885196d6759SMichele Baldessari 5886196d6759SMichele Baldessari /* New high max rto observed, will return 0 if not a single 5887196d6759SMichele Baldessari * RTO update took place. obs_rto_ipaddr will be bogus 5888196d6759SMichele Baldessari * in such a case 5889196d6759SMichele Baldessari */ 5890196d6759SMichele Baldessari sas.sas_maxrto = asoc->stats.max_obs_rto; 5891196d6759SMichele Baldessari memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr, 5892196d6759SMichele Baldessari sizeof(struct sockaddr_storage)); 5893196d6759SMichele Baldessari 5894196d6759SMichele Baldessari /* Mark beginning of a new observation period */ 5895196d6759SMichele Baldessari asoc->stats.max_obs_rto = asoc->rto_min; 5896196d6759SMichele Baldessari 5897196d6759SMichele Baldessari if (put_user(len, optlen)) 5898196d6759SMichele Baldessari return -EFAULT; 5899196d6759SMichele Baldessari 5900bb33381dSDaniel Borkmann pr_debug("%s: len:%d, assoc_id:%d\n", __func__, len, sas.sas_assoc_id); 5901196d6759SMichele Baldessari 5902196d6759SMichele Baldessari if (copy_to_user(optval, &sas, len)) 5903196d6759SMichele Baldessari return -EFAULT; 5904196d6759SMichele Baldessari 5905196d6759SMichele Baldessari return 0; 5906196d6759SMichele Baldessari } 5907196d6759SMichele Baldessari 59080d3a421dSGeir Ola Vaagland static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, 59090d3a421dSGeir Ola Vaagland char __user *optval, 59100d3a421dSGeir Ola Vaagland int __user *optlen) 59110d3a421dSGeir Ola Vaagland { 59120d3a421dSGeir Ola Vaagland int val = 0; 59130d3a421dSGeir Ola Vaagland 59140d3a421dSGeir Ola Vaagland if (len < sizeof(int)) 59150d3a421dSGeir Ola Vaagland return -EINVAL; 59160d3a421dSGeir Ola Vaagland 59170d3a421dSGeir Ola Vaagland len = sizeof(int); 59180d3a421dSGeir Ola Vaagland if (sctp_sk(sk)->recvrcvinfo) 59190d3a421dSGeir Ola Vaagland val = 1; 59200d3a421dSGeir Ola Vaagland if (put_user(len, optlen)) 59210d3a421dSGeir Ola Vaagland return -EFAULT; 59220d3a421dSGeir Ola Vaagland if (copy_to_user(optval, &val, len)) 59230d3a421dSGeir Ola Vaagland return -EFAULT; 59240d3a421dSGeir Ola Vaagland 59250d3a421dSGeir Ola Vaagland return 0; 59260d3a421dSGeir Ola Vaagland } 59270d3a421dSGeir Ola Vaagland 59282347c80fSGeir Ola Vaagland static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len, 59292347c80fSGeir Ola Vaagland char __user *optval, 59302347c80fSGeir Ola Vaagland int __user *optlen) 59312347c80fSGeir Ola Vaagland { 59322347c80fSGeir Ola Vaagland int val = 0; 59332347c80fSGeir Ola Vaagland 59342347c80fSGeir Ola Vaagland if (len < sizeof(int)) 59352347c80fSGeir Ola Vaagland return -EINVAL; 59362347c80fSGeir Ola Vaagland 59372347c80fSGeir Ola Vaagland len = sizeof(int); 59382347c80fSGeir Ola Vaagland if (sctp_sk(sk)->recvnxtinfo) 59392347c80fSGeir Ola Vaagland val = 1; 59402347c80fSGeir Ola Vaagland if (put_user(len, optlen)) 59412347c80fSGeir Ola Vaagland return -EFAULT; 59422347c80fSGeir Ola Vaagland if (copy_to_user(optval, &val, len)) 59432347c80fSGeir Ola Vaagland return -EFAULT; 59442347c80fSGeir Ola Vaagland 59452347c80fSGeir Ola Vaagland return 0; 59462347c80fSGeir Ola Vaagland } 59472347c80fSGeir Ola Vaagland 5948dda91928SDaniel Borkmann static int sctp_getsockopt(struct sock *sk, int level, int optname, 59491da177e4SLinus Torvalds char __user *optval, int __user *optlen) 59501da177e4SLinus Torvalds { 59511da177e4SLinus Torvalds int retval = 0; 59521da177e4SLinus Torvalds int len; 59531da177e4SLinus Torvalds 5954bb33381dSDaniel Borkmann pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); 59551da177e4SLinus Torvalds 59561da177e4SLinus Torvalds /* I can hardly begin to describe how wrong this is. This is 59571da177e4SLinus Torvalds * so broken as to be worse than useless. The API draft 59581da177e4SLinus Torvalds * REALLY is NOT helpful here... I am not convinced that the 59591da177e4SLinus Torvalds * semantics of getsockopt() with a level OTHER THAN SOL_SCTP 59601da177e4SLinus Torvalds * are at all well-founded. 59611da177e4SLinus Torvalds */ 59621da177e4SLinus Torvalds if (level != SOL_SCTP) { 59631da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 59641da177e4SLinus Torvalds 59651da177e4SLinus Torvalds retval = af->getsockopt(sk, level, optname, optval, optlen); 59661da177e4SLinus Torvalds return retval; 59671da177e4SLinus Torvalds } 59681da177e4SLinus Torvalds 59691da177e4SLinus Torvalds if (get_user(len, optlen)) 59701da177e4SLinus Torvalds return -EFAULT; 59711da177e4SLinus Torvalds 5972048ed4b6Swangweidong lock_sock(sk); 59731da177e4SLinus Torvalds 59741da177e4SLinus Torvalds switch (optname) { 59751da177e4SLinus Torvalds case SCTP_STATUS: 59761da177e4SLinus Torvalds retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); 59771da177e4SLinus Torvalds break; 59781da177e4SLinus Torvalds case SCTP_DISABLE_FRAGMENTS: 59791da177e4SLinus Torvalds retval = sctp_getsockopt_disable_fragments(sk, len, optval, 59801da177e4SLinus Torvalds optlen); 59811da177e4SLinus Torvalds break; 59821da177e4SLinus Torvalds case SCTP_EVENTS: 59831da177e4SLinus Torvalds retval = sctp_getsockopt_events(sk, len, optval, optlen); 59841da177e4SLinus Torvalds break; 59851da177e4SLinus Torvalds case SCTP_AUTOCLOSE: 59861da177e4SLinus Torvalds retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); 59871da177e4SLinus Torvalds break; 59881da177e4SLinus Torvalds case SCTP_SOCKOPT_PEELOFF: 59891da177e4SLinus Torvalds retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); 59901da177e4SLinus Torvalds break; 59911da177e4SLinus Torvalds case SCTP_PEER_ADDR_PARAMS: 59921da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addr_params(sk, len, optval, 59931da177e4SLinus Torvalds optlen); 59941da177e4SLinus Torvalds break; 59954580ccc0SShan Wei case SCTP_DELAYED_SACK: 5996d364d927SWei Yongjun retval = sctp_getsockopt_delayed_ack(sk, len, optval, 59977708610bSFrank Filz optlen); 59987708610bSFrank Filz break; 59991da177e4SLinus Torvalds case SCTP_INITMSG: 60001da177e4SLinus Torvalds retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); 60011da177e4SLinus Torvalds break; 60021da177e4SLinus Torvalds case SCTP_GET_PEER_ADDRS: 60031da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addrs(sk, len, optval, 60041da177e4SLinus Torvalds optlen); 60051da177e4SLinus Torvalds break; 60061da177e4SLinus Torvalds case SCTP_GET_LOCAL_ADDRS: 60071da177e4SLinus Torvalds retval = sctp_getsockopt_local_addrs(sk, len, optval, 60081da177e4SLinus Torvalds optlen); 60091da177e4SLinus Torvalds break; 6010c6ba68a2SVlad Yasevich case SCTP_SOCKOPT_CONNECTX3: 6011c6ba68a2SVlad Yasevich retval = sctp_getsockopt_connectx3(sk, len, optval, optlen); 6012c6ba68a2SVlad Yasevich break; 60131da177e4SLinus Torvalds case SCTP_DEFAULT_SEND_PARAM: 60141da177e4SLinus Torvalds retval = sctp_getsockopt_default_send_param(sk, len, 60151da177e4SLinus Torvalds optval, optlen); 60161da177e4SLinus Torvalds break; 60176b3fd5f3SGeir Ola Vaagland case SCTP_DEFAULT_SNDINFO: 60186b3fd5f3SGeir Ola Vaagland retval = sctp_getsockopt_default_sndinfo(sk, len, 60196b3fd5f3SGeir Ola Vaagland optval, optlen); 60206b3fd5f3SGeir Ola Vaagland break; 60211da177e4SLinus Torvalds case SCTP_PRIMARY_ADDR: 60221da177e4SLinus Torvalds retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); 60231da177e4SLinus Torvalds break; 60241da177e4SLinus Torvalds case SCTP_NODELAY: 60251da177e4SLinus Torvalds retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); 60261da177e4SLinus Torvalds break; 60271da177e4SLinus Torvalds case SCTP_RTOINFO: 60281da177e4SLinus Torvalds retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen); 60291da177e4SLinus Torvalds break; 60301da177e4SLinus Torvalds case SCTP_ASSOCINFO: 60311da177e4SLinus Torvalds retval = sctp_getsockopt_associnfo(sk, len, optval, optlen); 60321da177e4SLinus Torvalds break; 60331da177e4SLinus Torvalds case SCTP_I_WANT_MAPPED_V4_ADDR: 60341da177e4SLinus Torvalds retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); 60351da177e4SLinus Torvalds break; 60361da177e4SLinus Torvalds case SCTP_MAXSEG: 60371da177e4SLinus Torvalds retval = sctp_getsockopt_maxseg(sk, len, optval, optlen); 60381da177e4SLinus Torvalds break; 60391da177e4SLinus Torvalds case SCTP_GET_PEER_ADDR_INFO: 60401da177e4SLinus Torvalds retval = sctp_getsockopt_peer_addr_info(sk, len, optval, 60411da177e4SLinus Torvalds optlen); 60421da177e4SLinus Torvalds break; 60430f3fffd8SIvan Skytte Jorgensen case SCTP_ADAPTATION_LAYER: 60440f3fffd8SIvan Skytte Jorgensen retval = sctp_getsockopt_adaptation_layer(sk, len, optval, 60451da177e4SLinus Torvalds optlen); 60461da177e4SLinus Torvalds break; 60476ab792f5SIvan Skytte Jorgensen case SCTP_CONTEXT: 60486ab792f5SIvan Skytte Jorgensen retval = sctp_getsockopt_context(sk, len, optval, optlen); 60496ab792f5SIvan Skytte Jorgensen break; 6050b6e1331fSVlad Yasevich case SCTP_FRAGMENT_INTERLEAVE: 6051b6e1331fSVlad Yasevich retval = sctp_getsockopt_fragment_interleave(sk, len, optval, 6052b6e1331fSVlad Yasevich optlen); 6053b6e1331fSVlad Yasevich break; 6054d49d91d7SVlad Yasevich case SCTP_PARTIAL_DELIVERY_POINT: 6055d49d91d7SVlad Yasevich retval = sctp_getsockopt_partial_delivery_point(sk, len, optval, 6056d49d91d7SVlad Yasevich optlen); 6057d49d91d7SVlad Yasevich break; 605870331571SVlad Yasevich case SCTP_MAX_BURST: 605970331571SVlad Yasevich retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); 606070331571SVlad Yasevich break; 606165b07e5dSVlad Yasevich case SCTP_AUTH_KEY: 606265b07e5dSVlad Yasevich case SCTP_AUTH_CHUNK: 606365b07e5dSVlad Yasevich case SCTP_AUTH_DELETE_KEY: 606465b07e5dSVlad Yasevich retval = -EOPNOTSUPP; 606565b07e5dSVlad Yasevich break; 606665b07e5dSVlad Yasevich case SCTP_HMAC_IDENT: 606765b07e5dSVlad Yasevich retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen); 606865b07e5dSVlad Yasevich break; 606965b07e5dSVlad Yasevich case SCTP_AUTH_ACTIVE_KEY: 607065b07e5dSVlad Yasevich retval = sctp_getsockopt_active_key(sk, len, optval, optlen); 607165b07e5dSVlad Yasevich break; 607265b07e5dSVlad Yasevich case SCTP_PEER_AUTH_CHUNKS: 607365b07e5dSVlad Yasevich retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval, 607465b07e5dSVlad Yasevich optlen); 607565b07e5dSVlad Yasevich break; 607665b07e5dSVlad Yasevich case SCTP_LOCAL_AUTH_CHUNKS: 607765b07e5dSVlad Yasevich retval = sctp_getsockopt_local_auth_chunks(sk, len, optval, 607865b07e5dSVlad Yasevich optlen); 607965b07e5dSVlad Yasevich break; 6080aea3c5c0SWei Yongjun case SCTP_GET_ASSOC_NUMBER: 6081aea3c5c0SWei Yongjun retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); 6082aea3c5c0SWei Yongjun break; 6083209ba424SWei Yongjun case SCTP_GET_ASSOC_ID_LIST: 6084209ba424SWei Yongjun retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); 6085209ba424SWei Yongjun break; 60867dc04d71SMichio Honda case SCTP_AUTO_ASCONF: 60877dc04d71SMichio Honda retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); 60887dc04d71SMichio Honda break; 60895aa93bcfSNeil Horman case SCTP_PEER_ADDR_THLDS: 60905aa93bcfSNeil Horman retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); 60915aa93bcfSNeil Horman break; 6092196d6759SMichele Baldessari case SCTP_GET_ASSOC_STATS: 6093196d6759SMichele Baldessari retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); 6094196d6759SMichele Baldessari break; 60950d3a421dSGeir Ola Vaagland case SCTP_RECVRCVINFO: 60960d3a421dSGeir Ola Vaagland retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); 60970d3a421dSGeir Ola Vaagland break; 60982347c80fSGeir Ola Vaagland case SCTP_RECVNXTINFO: 60992347c80fSGeir Ola Vaagland retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen); 61002347c80fSGeir Ola Vaagland break; 61011da177e4SLinus Torvalds default: 61021da177e4SLinus Torvalds retval = -ENOPROTOOPT; 61031da177e4SLinus Torvalds break; 61043ff50b79SStephen Hemminger } 61051da177e4SLinus Torvalds 6106048ed4b6Swangweidong release_sock(sk); 61071da177e4SLinus Torvalds return retval; 61081da177e4SLinus Torvalds } 61091da177e4SLinus Torvalds 61101da177e4SLinus Torvalds static void sctp_hash(struct sock *sk) 61111da177e4SLinus Torvalds { 61121da177e4SLinus Torvalds /* STUB */ 61131da177e4SLinus Torvalds } 61141da177e4SLinus Torvalds 61151da177e4SLinus Torvalds static void sctp_unhash(struct sock *sk) 61161da177e4SLinus Torvalds { 61171da177e4SLinus Torvalds /* STUB */ 61181da177e4SLinus Torvalds } 61191da177e4SLinus Torvalds 61201da177e4SLinus Torvalds /* Check if port is acceptable. Possibly find first available port. 61211da177e4SLinus Torvalds * 61221da177e4SLinus Torvalds * The port hash table (contained in the 'global' SCTP protocol storage 61231da177e4SLinus Torvalds * returned by struct sctp_protocol *sctp_get_protocol()). The hash 61241da177e4SLinus Torvalds * table is an array of 4096 lists (sctp_bind_hashbucket). Each 61251da177e4SLinus Torvalds * list (the list number is the port number hashed out, so as you 61261da177e4SLinus Torvalds * would expect from a hash function, all the ports in a given list have 61271da177e4SLinus Torvalds * such a number that hashes out to the same list number; you were 61281da177e4SLinus Torvalds * expecting that, right?); so each list has a set of ports, with a 61291da177e4SLinus Torvalds * link to the socket (struct sock) that uses it, the port number and 61301da177e4SLinus Torvalds * a fastreuse flag (FIXME: NPI ipg). 61311da177e4SLinus Torvalds */ 61321da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create( 6133f1f43763SEric W. Biederman struct sctp_bind_hashbucket *head, struct net *, unsigned short snum); 61341da177e4SLinus Torvalds 61351da177e4SLinus Torvalds static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) 61361da177e4SLinus Torvalds { 61371da177e4SLinus Torvalds struct sctp_bind_hashbucket *head; /* hash list */ 6138b67bfe0dSSasha Levin struct sctp_bind_bucket *pp; 61391da177e4SLinus Torvalds unsigned short snum; 61401da177e4SLinus Torvalds int ret; 61411da177e4SLinus Torvalds 614204afd8b2SAl Viro snum = ntohs(addr->v4.sin_port); 61431da177e4SLinus Torvalds 6144bb33381dSDaniel Borkmann pr_debug("%s: begins, snum:%d\n", __func__, snum); 6145bb33381dSDaniel Borkmann 614679b91130Swangweidong local_bh_disable(); 61471da177e4SLinus Torvalds 61481da177e4SLinus Torvalds if (snum == 0) { 614906393009SStephen Hemminger /* Search for an available port. */ 6150227b60f5SStephen Hemminger int low, high, remaining, index; 6151227b60f5SStephen Hemminger unsigned int rover; 6152122ff243SWANG Cong struct net *net = sock_net(sk); 6153227b60f5SStephen Hemminger 6154122ff243SWANG Cong inet_get_local_port_range(net, &low, &high); 6155227b60f5SStephen Hemminger remaining = (high - low) + 1; 615663862b5bSAruna-Hewapathirane rover = prandom_u32() % remaining + low; 61571da177e4SLinus Torvalds 61581da177e4SLinus Torvalds do { 61591da177e4SLinus Torvalds rover++; 61601da177e4SLinus Torvalds if ((rover < low) || (rover > high)) 61611da177e4SLinus Torvalds rover = low; 6162122ff243SWANG Cong if (inet_is_local_reserved_port(net, rover)) 6163e3826f1eSAmerigo Wang continue; 6164f1f43763SEric W. Biederman index = sctp_phashfn(sock_net(sk), rover); 61651da177e4SLinus Torvalds head = &sctp_port_hashtable[index]; 61663c8e43baSwangweidong spin_lock(&head->lock); 6167b67bfe0dSSasha Levin sctp_for_each_hentry(pp, &head->chain) 6168f1f43763SEric W. Biederman if ((pp->port == rover) && 6169f1f43763SEric W. Biederman net_eq(sock_net(sk), pp->net)) 61701da177e4SLinus Torvalds goto next; 61711da177e4SLinus Torvalds break; 61721da177e4SLinus Torvalds next: 61733c8e43baSwangweidong spin_unlock(&head->lock); 61741da177e4SLinus Torvalds } while (--remaining > 0); 61751da177e4SLinus Torvalds 61761da177e4SLinus Torvalds /* Exhausted local port range during search? */ 61771da177e4SLinus Torvalds ret = 1; 61781da177e4SLinus Torvalds if (remaining <= 0) 61791da177e4SLinus Torvalds goto fail; 61801da177e4SLinus Torvalds 61811da177e4SLinus Torvalds /* OK, here is the one we will use. HEAD (the port 61821da177e4SLinus Torvalds * hash table list entry) is non-NULL and we hold it's 61831da177e4SLinus Torvalds * mutex. 61841da177e4SLinus Torvalds */ 61851da177e4SLinus Torvalds snum = rover; 61861da177e4SLinus Torvalds } else { 61871da177e4SLinus Torvalds /* We are given an specific port number; we verify 61881da177e4SLinus Torvalds * that it is not being used. If it is used, we will 61891da177e4SLinus Torvalds * exahust the search in the hash list corresponding 61901da177e4SLinus Torvalds * to the port number (snum) - we detect that with the 61911da177e4SLinus Torvalds * port iterator, pp being NULL. 61921da177e4SLinus Torvalds */ 6193f1f43763SEric W. Biederman head = &sctp_port_hashtable[sctp_phashfn(sock_net(sk), snum)]; 61943c8e43baSwangweidong spin_lock(&head->lock); 6195b67bfe0dSSasha Levin sctp_for_each_hentry(pp, &head->chain) { 6196f1f43763SEric W. Biederman if ((pp->port == snum) && net_eq(pp->net, sock_net(sk))) 61971da177e4SLinus Torvalds goto pp_found; 61981da177e4SLinus Torvalds } 61991da177e4SLinus Torvalds } 62001da177e4SLinus Torvalds pp = NULL; 62011da177e4SLinus Torvalds goto pp_not_found; 62021da177e4SLinus Torvalds pp_found: 62031da177e4SLinus Torvalds if (!hlist_empty(&pp->owner)) { 62041da177e4SLinus Torvalds /* We had a port hash table hit - there is an 62051da177e4SLinus Torvalds * available port (pp != NULL) and it is being 62061da177e4SLinus Torvalds * used by other socket (pp->owner not empty); that other 62071da177e4SLinus Torvalds * socket is going to be sk2. 62081da177e4SLinus Torvalds */ 62091da177e4SLinus Torvalds int reuse = sk->sk_reuse; 62101da177e4SLinus Torvalds struct sock *sk2; 62111da177e4SLinus Torvalds 6212bb33381dSDaniel Borkmann pr_debug("%s: found a possible match\n", __func__); 6213bb33381dSDaniel Borkmann 6214ce5325c1SVlad Yasevich if (pp->fastreuse && sk->sk_reuse && 6215ce5325c1SVlad Yasevich sk->sk_state != SCTP_SS_LISTENING) 62161da177e4SLinus Torvalds goto success; 62171da177e4SLinus Torvalds 62181da177e4SLinus Torvalds /* Run through the list of sockets bound to the port 62191da177e4SLinus Torvalds * (pp->port) [via the pointers bind_next and 62201da177e4SLinus Torvalds * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one, 62211da177e4SLinus Torvalds * we get the endpoint they describe and run through 62221da177e4SLinus Torvalds * the endpoint's list of IP (v4 or v6) addresses, 62231da177e4SLinus Torvalds * comparing each of the addresses with the address of 62241da177e4SLinus Torvalds * the socket sk. If we find a match, then that means 62251da177e4SLinus Torvalds * that this port/socket (sk) combination are already 62261da177e4SLinus Torvalds * in an endpoint. 62271da177e4SLinus Torvalds */ 6228b67bfe0dSSasha Levin sk_for_each_bound(sk2, &pp->owner) { 62291da177e4SLinus Torvalds struct sctp_endpoint *ep2; 62301da177e4SLinus Torvalds ep2 = sctp_sk(sk2)->ep; 62311da177e4SLinus Torvalds 62324e54064eSVlad Yasevich if (sk == sk2 || 62334e54064eSVlad Yasevich (reuse && sk2->sk_reuse && 62344e54064eSVlad Yasevich sk2->sk_state != SCTP_SS_LISTENING)) 62351da177e4SLinus Torvalds continue; 62361da177e4SLinus Torvalds 62377dab83deSVlad Yasevich if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr, 62387dab83deSVlad Yasevich sctp_sk(sk2), sctp_sk(sk))) { 62391da177e4SLinus Torvalds ret = (long)sk2; 62401da177e4SLinus Torvalds goto fail_unlock; 62411da177e4SLinus Torvalds } 62421da177e4SLinus Torvalds } 6243bb33381dSDaniel Borkmann 6244bb33381dSDaniel Borkmann pr_debug("%s: found a match\n", __func__); 62451da177e4SLinus Torvalds } 62461da177e4SLinus Torvalds pp_not_found: 62471da177e4SLinus Torvalds /* If there was a hash table miss, create a new port. */ 62481da177e4SLinus Torvalds ret = 1; 6249f1f43763SEric W. Biederman if (!pp && !(pp = sctp_bucket_create(head, sock_net(sk), snum))) 62501da177e4SLinus Torvalds goto fail_unlock; 62511da177e4SLinus Torvalds 62521da177e4SLinus Torvalds /* In either case (hit or miss), make sure fastreuse is 1 only 62531da177e4SLinus Torvalds * if sk->sk_reuse is too (that is, if the caller requested 62541da177e4SLinus Torvalds * SO_REUSEADDR on this socket -sk-). 62551da177e4SLinus Torvalds */ 6256ce5325c1SVlad Yasevich if (hlist_empty(&pp->owner)) { 6257ce5325c1SVlad Yasevich if (sk->sk_reuse && sk->sk_state != SCTP_SS_LISTENING) 6258ce5325c1SVlad Yasevich pp->fastreuse = 1; 6259ce5325c1SVlad Yasevich else 6260ce5325c1SVlad Yasevich pp->fastreuse = 0; 6261ce5325c1SVlad Yasevich } else if (pp->fastreuse && 6262ce5325c1SVlad Yasevich (!sk->sk_reuse || sk->sk_state == SCTP_SS_LISTENING)) 62631da177e4SLinus Torvalds pp->fastreuse = 0; 62641da177e4SLinus Torvalds 62651da177e4SLinus Torvalds /* We are set, so fill up all the data in the hash table 62661da177e4SLinus Torvalds * entry, tie the socket list information with the rest of the 62671da177e4SLinus Torvalds * sockets FIXME: Blurry, NPI (ipg). 62681da177e4SLinus Torvalds */ 62691da177e4SLinus Torvalds success: 62701da177e4SLinus Torvalds if (!sctp_sk(sk)->bind_hash) { 6271c720c7e8SEric Dumazet inet_sk(sk)->inet_num = snum; 62721da177e4SLinus Torvalds sk_add_bind_node(sk, &pp->owner); 62731da177e4SLinus Torvalds sctp_sk(sk)->bind_hash = pp; 62741da177e4SLinus Torvalds } 62751da177e4SLinus Torvalds ret = 0; 62761da177e4SLinus Torvalds 62771da177e4SLinus Torvalds fail_unlock: 62783c8e43baSwangweidong spin_unlock(&head->lock); 62791da177e4SLinus Torvalds 62801da177e4SLinus Torvalds fail: 628179b91130Swangweidong local_bh_enable(); 62821da177e4SLinus Torvalds return ret; 62831da177e4SLinus Torvalds } 62841da177e4SLinus Torvalds 62851da177e4SLinus Torvalds /* Assign a 'snum' port to the socket. If snum == 0, an ephemeral 62861da177e4SLinus Torvalds * port is requested. 62871da177e4SLinus Torvalds */ 62881da177e4SLinus Torvalds static int sctp_get_port(struct sock *sk, unsigned short snum) 62891da177e4SLinus Torvalds { 62901da177e4SLinus Torvalds union sctp_addr addr; 62911da177e4SLinus Torvalds struct sctp_af *af = sctp_sk(sk)->pf->af; 62921da177e4SLinus Torvalds 62931da177e4SLinus Torvalds /* Set up a dummy address struct from the sk. */ 62941da177e4SLinus Torvalds af->from_sk(&addr, sk); 62951da177e4SLinus Torvalds addr.v4.sin_port = htons(snum); 62961da177e4SLinus Torvalds 62971da177e4SLinus Torvalds /* Note: sk->sk_num gets filled in if ephemeral port request. */ 629862208f12SDaniel Borkmann return !!sctp_get_port_local(sk, &addr); 62991da177e4SLinus Torvalds } 63001da177e4SLinus Torvalds 63011da177e4SLinus Torvalds /* 63021da177e4SLinus Torvalds * Move a socket to LISTENING state. 63031da177e4SLinus Torvalds */ 6304dda91928SDaniel Borkmann static int sctp_listen_start(struct sock *sk, int backlog) 63051da177e4SLinus Torvalds { 63065e8f3f70SVlad Yasevich struct sctp_sock *sp = sctp_sk(sk); 63075e8f3f70SVlad Yasevich struct sctp_endpoint *ep = sp->ep; 63081b489e11SHerbert Xu struct crypto_hash *tfm = NULL; 63093c68198eSNeil Horman char alg[32]; 63101da177e4SLinus Torvalds 63111da177e4SLinus Torvalds /* Allocate HMAC for generating cookie. */ 63123c68198eSNeil Horman if (!sp->hmac && sp->sctp_hmac_alg) { 63133c68198eSNeil Horman sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg); 63143c68198eSNeil Horman tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC); 63158dc4984aSVlad Yasevich if (IS_ERR(tfm)) { 6316e87cc472SJoe Perches net_info_ratelimited("failed to load transform for %s: %ld\n", 63173c68198eSNeil Horman sp->sctp_hmac_alg, PTR_ERR(tfm)); 63185e8f3f70SVlad Yasevich return -ENOSYS; 63195e8f3f70SVlad Yasevich } 63205e8f3f70SVlad Yasevich sctp_sk(sk)->hmac = tfm; 63215e8f3f70SVlad Yasevich } 63225e8f3f70SVlad Yasevich 63235e8f3f70SVlad Yasevich /* 63245e8f3f70SVlad Yasevich * If a bind() or sctp_bindx() is not called prior to a listen() 63255e8f3f70SVlad Yasevich * call that allows new associations to be accepted, the system 63265e8f3f70SVlad Yasevich * picks an ephemeral port and will choose an address set equivalent 63275e8f3f70SVlad Yasevich * to binding with a wildcard address. 63285e8f3f70SVlad Yasevich * 63295e8f3f70SVlad Yasevich * This is not currently spelled out in the SCTP sockets 63305e8f3f70SVlad Yasevich * extensions draft, but follows the practice as seen in TCP 63315e8f3f70SVlad Yasevich * sockets. 63325e8f3f70SVlad Yasevich * 63335e8f3f70SVlad Yasevich */ 63345e8f3f70SVlad Yasevich sk->sk_state = SCTP_SS_LISTENING; 63355e8f3f70SVlad Yasevich if (!ep->base.bind_addr.port) { 63365e8f3f70SVlad Yasevich if (sctp_autobind(sk)) 63375e8f3f70SVlad Yasevich return -EAGAIN; 63385e8f3f70SVlad Yasevich } else { 6339c720c7e8SEric Dumazet if (sctp_get_port(sk, inet_sk(sk)->inet_num)) { 63405e8f3f70SVlad Yasevich sk->sk_state = SCTP_SS_CLOSED; 63415e8f3f70SVlad Yasevich return -EADDRINUSE; 63425e8f3f70SVlad Yasevich } 63435e8f3f70SVlad Yasevich } 63445e8f3f70SVlad Yasevich 63455e8f3f70SVlad Yasevich sk->sk_max_ack_backlog = backlog; 63465e8f3f70SVlad Yasevich sctp_hash_endpoint(ep); 63475e8f3f70SVlad Yasevich return 0; 63485e8f3f70SVlad Yasevich } 63495e8f3f70SVlad Yasevich 63505e8f3f70SVlad Yasevich /* 63515e8f3f70SVlad Yasevich * 4.1.3 / 5.1.3 listen() 63525e8f3f70SVlad Yasevich * 63535e8f3f70SVlad Yasevich * By default, new associations are not accepted for UDP style sockets. 63545e8f3f70SVlad Yasevich * An application uses listen() to mark a socket as being able to 63555e8f3f70SVlad Yasevich * accept new associations. 63565e8f3f70SVlad Yasevich * 63575e8f3f70SVlad Yasevich * On TCP style sockets, applications use listen() to ready the SCTP 63585e8f3f70SVlad Yasevich * endpoint for accepting inbound associations. 63595e8f3f70SVlad Yasevich * 63605e8f3f70SVlad Yasevich * On both types of endpoints a backlog of '0' disables listening. 63615e8f3f70SVlad Yasevich * 63625e8f3f70SVlad Yasevich * Move a socket to LISTENING state. 63635e8f3f70SVlad Yasevich */ 63645e8f3f70SVlad Yasevich int sctp_inet_listen(struct socket *sock, int backlog) 63655e8f3f70SVlad Yasevich { 63665e8f3f70SVlad Yasevich struct sock *sk = sock->sk; 63675e8f3f70SVlad Yasevich struct sctp_endpoint *ep = sctp_sk(sk)->ep; 63685e8f3f70SVlad Yasevich int err = -EINVAL; 63695e8f3f70SVlad Yasevich 63705e8f3f70SVlad Yasevich if (unlikely(backlog < 0)) 63715e8f3f70SVlad Yasevich return err; 63725e8f3f70SVlad Yasevich 6373048ed4b6Swangweidong lock_sock(sk); 63745e8f3f70SVlad Yasevich 63755e8f3f70SVlad Yasevich /* Peeled-off sockets are not allowed to listen(). */ 63765e8f3f70SVlad Yasevich if (sctp_style(sk, UDP_HIGH_BANDWIDTH)) 63775e8f3f70SVlad Yasevich goto out; 63785e8f3f70SVlad Yasevich 63795e8f3f70SVlad Yasevich if (sock->state != SS_UNCONNECTED) 63805e8f3f70SVlad Yasevich goto out; 63815e8f3f70SVlad Yasevich 63825e8f3f70SVlad Yasevich /* If backlog is zero, disable listening. */ 63835e8f3f70SVlad Yasevich if (!backlog) { 63845e8f3f70SVlad Yasevich if (sctp_sstate(sk, CLOSED)) 63855e8f3f70SVlad Yasevich goto out; 63865e8f3f70SVlad Yasevich 63875e8f3f70SVlad Yasevich err = 0; 63885e8f3f70SVlad Yasevich sctp_unhash_endpoint(ep); 63895e8f3f70SVlad Yasevich sk->sk_state = SCTP_SS_CLOSED; 63905e8f3f70SVlad Yasevich if (sk->sk_reuse) 63915e8f3f70SVlad Yasevich sctp_sk(sk)->bind_hash->fastreuse = 1; 63921da177e4SLinus Torvalds goto out; 63931da177e4SLinus Torvalds } 63941da177e4SLinus Torvalds 63955e8f3f70SVlad Yasevich /* If we are already listening, just update the backlog */ 63965e8f3f70SVlad Yasevich if (sctp_sstate(sk, LISTENING)) 63975e8f3f70SVlad Yasevich sk->sk_max_ack_backlog = backlog; 63985e8f3f70SVlad Yasevich else { 63995e8f3f70SVlad Yasevich err = sctp_listen_start(sk, backlog); 64001da177e4SLinus Torvalds if (err) 64015e8f3f70SVlad Yasevich goto out; 64025e8f3f70SVlad Yasevich } 64031da177e4SLinus Torvalds 64045e8f3f70SVlad Yasevich err = 0; 64051da177e4SLinus Torvalds out: 6406048ed4b6Swangweidong release_sock(sk); 64071da177e4SLinus Torvalds return err; 64081da177e4SLinus Torvalds } 64091da177e4SLinus Torvalds 64101da177e4SLinus Torvalds /* 64111da177e4SLinus Torvalds * This function is done by modeling the current datagram_poll() and the 64121da177e4SLinus Torvalds * tcp_poll(). Note that, based on these implementations, we don't 64131da177e4SLinus Torvalds * lock the socket in this function, even though it seems that, 64141da177e4SLinus Torvalds * ideally, locking or some other mechanisms can be used to ensure 64159bffc4acSNeil Horman * the integrity of the counters (sndbuf and wmem_alloc) used 64161da177e4SLinus Torvalds * in this place. We assume that we don't need locks either until proven 64171da177e4SLinus Torvalds * otherwise. 64181da177e4SLinus Torvalds * 64191da177e4SLinus Torvalds * Another thing to note is that we include the Async I/O support 64201da177e4SLinus Torvalds * here, again, by modeling the current TCP/UDP code. We don't have 64211da177e4SLinus Torvalds * a good way to test with it yet. 64221da177e4SLinus Torvalds */ 64231da177e4SLinus Torvalds unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) 64241da177e4SLinus Torvalds { 64251da177e4SLinus Torvalds struct sock *sk = sock->sk; 64261da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 64271da177e4SLinus Torvalds unsigned int mask; 64281da177e4SLinus Torvalds 6429aa395145SEric Dumazet poll_wait(file, sk_sleep(sk), wait); 64301da177e4SLinus Torvalds 64311da177e4SLinus Torvalds /* A TCP-style listening socket becomes readable when the accept queue 64321da177e4SLinus Torvalds * is not empty. 64331da177e4SLinus Torvalds */ 64341da177e4SLinus Torvalds if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 64351da177e4SLinus Torvalds return (!list_empty(&sp->ep->asocs)) ? 64361da177e4SLinus Torvalds (POLLIN | POLLRDNORM) : 0; 64371da177e4SLinus Torvalds 64381da177e4SLinus Torvalds mask = 0; 64391da177e4SLinus Torvalds 64401da177e4SLinus Torvalds /* Is there any exceptional events? */ 64411da177e4SLinus Torvalds if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) 64427d4c04fcSKeller, Jacob E mask |= POLLERR | 6443a0fb05d1SDaniel Borkmann (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0); 6444f348d70aSDavide Libenzi if (sk->sk_shutdown & RCV_SHUTDOWN) 6445db40980fSEric Dumazet mask |= POLLRDHUP | POLLIN | POLLRDNORM; 64461da177e4SLinus Torvalds if (sk->sk_shutdown == SHUTDOWN_MASK) 64471da177e4SLinus Torvalds mask |= POLLHUP; 64481da177e4SLinus Torvalds 64491da177e4SLinus Torvalds /* Is it readable? Reconsider this code with TCP-style support. */ 6450db40980fSEric Dumazet if (!skb_queue_empty(&sk->sk_receive_queue)) 64511da177e4SLinus Torvalds mask |= POLLIN | POLLRDNORM; 64521da177e4SLinus Torvalds 64531da177e4SLinus Torvalds /* The association is either gone or not ready. */ 64541da177e4SLinus Torvalds if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED)) 64551da177e4SLinus Torvalds return mask; 64561da177e4SLinus Torvalds 64571da177e4SLinus Torvalds /* Is it writable? */ 64581da177e4SLinus Torvalds if (sctp_writeable(sk)) { 64591da177e4SLinus Torvalds mask |= POLLOUT | POLLWRNORM; 64601da177e4SLinus Torvalds } else { 64619cd3e072SEric Dumazet sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 64621da177e4SLinus Torvalds /* 64631da177e4SLinus Torvalds * Since the socket is not locked, the buffer 64641da177e4SLinus Torvalds * might be made available after the writeable check and 64651da177e4SLinus Torvalds * before the bit is set. This could cause a lost I/O 64661da177e4SLinus Torvalds * signal. tcp_poll() has a race breaker for this race 64671da177e4SLinus Torvalds * condition. Based on their implementation, we put 64681da177e4SLinus Torvalds * in the following code to cover it as well. 64691da177e4SLinus Torvalds */ 64701da177e4SLinus Torvalds if (sctp_writeable(sk)) 64711da177e4SLinus Torvalds mask |= POLLOUT | POLLWRNORM; 64721da177e4SLinus Torvalds } 64731da177e4SLinus Torvalds return mask; 64741da177e4SLinus Torvalds } 64751da177e4SLinus Torvalds 64761da177e4SLinus Torvalds /******************************************************************** 64771da177e4SLinus Torvalds * 2nd Level Abstractions 64781da177e4SLinus Torvalds ********************************************************************/ 64791da177e4SLinus Torvalds 64801da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create( 6481f1f43763SEric W. Biederman struct sctp_bind_hashbucket *head, struct net *net, unsigned short snum) 64821da177e4SLinus Torvalds { 64831da177e4SLinus Torvalds struct sctp_bind_bucket *pp; 64841da177e4SLinus Torvalds 648554e6ecb2SChristoph Lameter pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC); 64861da177e4SLinus Torvalds if (pp) { 6487935a7f6eSLi Zefan SCTP_DBG_OBJCNT_INC(bind_bucket); 64881da177e4SLinus Torvalds pp->port = snum; 64891da177e4SLinus Torvalds pp->fastreuse = 0; 64901da177e4SLinus Torvalds INIT_HLIST_HEAD(&pp->owner); 6491f1f43763SEric W. Biederman pp->net = net; 6492d970dbf8SVlad Yasevich hlist_add_head(&pp->node, &head->chain); 64931da177e4SLinus Torvalds } 64941da177e4SLinus Torvalds return pp; 64951da177e4SLinus Torvalds } 64961da177e4SLinus Torvalds 64971da177e4SLinus Torvalds /* Caller must hold hashbucket lock for this tb with local BH disabled */ 64981da177e4SLinus Torvalds static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) 64991da177e4SLinus Torvalds { 650037fa6878SSridhar Samudrala if (pp && hlist_empty(&pp->owner)) { 6501d970dbf8SVlad Yasevich __hlist_del(&pp->node); 65021da177e4SLinus Torvalds kmem_cache_free(sctp_bucket_cachep, pp); 65031da177e4SLinus Torvalds SCTP_DBG_OBJCNT_DEC(bind_bucket); 65041da177e4SLinus Torvalds } 65051da177e4SLinus Torvalds } 65061da177e4SLinus Torvalds 65071da177e4SLinus Torvalds /* Release this socket's reference to a local port. */ 65081da177e4SLinus Torvalds static inline void __sctp_put_port(struct sock *sk) 65091da177e4SLinus Torvalds { 65101da177e4SLinus Torvalds struct sctp_bind_hashbucket *head = 6511f1f43763SEric W. Biederman &sctp_port_hashtable[sctp_phashfn(sock_net(sk), 6512f1f43763SEric W. Biederman inet_sk(sk)->inet_num)]; 65131da177e4SLinus Torvalds struct sctp_bind_bucket *pp; 65141da177e4SLinus Torvalds 65153c8e43baSwangweidong spin_lock(&head->lock); 65161da177e4SLinus Torvalds pp = sctp_sk(sk)->bind_hash; 65171da177e4SLinus Torvalds __sk_del_bind_node(sk); 65181da177e4SLinus Torvalds sctp_sk(sk)->bind_hash = NULL; 6519c720c7e8SEric Dumazet inet_sk(sk)->inet_num = 0; 65201da177e4SLinus Torvalds sctp_bucket_destroy(pp); 65213c8e43baSwangweidong spin_unlock(&head->lock); 65221da177e4SLinus Torvalds } 65231da177e4SLinus Torvalds 65241da177e4SLinus Torvalds void sctp_put_port(struct sock *sk) 65251da177e4SLinus Torvalds { 652679b91130Swangweidong local_bh_disable(); 65271da177e4SLinus Torvalds __sctp_put_port(sk); 652879b91130Swangweidong local_bh_enable(); 65291da177e4SLinus Torvalds } 65301da177e4SLinus Torvalds 65311da177e4SLinus Torvalds /* 65321da177e4SLinus Torvalds * The system picks an ephemeral port and choose an address set equivalent 65331da177e4SLinus Torvalds * to binding with a wildcard address. 65341da177e4SLinus Torvalds * One of those addresses will be the primary address for the association. 65351da177e4SLinus Torvalds * This automatically enables the multihoming capability of SCTP. 65361da177e4SLinus Torvalds */ 65371da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk) 65381da177e4SLinus Torvalds { 65391da177e4SLinus Torvalds union sctp_addr autoaddr; 65401da177e4SLinus Torvalds struct sctp_af *af; 65416fbfa9f9SAl Viro __be16 port; 65421da177e4SLinus Torvalds 65431da177e4SLinus Torvalds /* Initialize a local sockaddr structure to INADDR_ANY. */ 65441da177e4SLinus Torvalds af = sctp_sk(sk)->pf->af; 65451da177e4SLinus Torvalds 6546c720c7e8SEric Dumazet port = htons(inet_sk(sk)->inet_num); 65471da177e4SLinus Torvalds af->inaddr_any(&autoaddr, port); 65481da177e4SLinus Torvalds 65491da177e4SLinus Torvalds return sctp_do_bind(sk, &autoaddr, af->sockaddr_len); 65501da177e4SLinus Torvalds } 65511da177e4SLinus Torvalds 65521da177e4SLinus Torvalds /* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. 65531da177e4SLinus Torvalds * 65541da177e4SLinus Torvalds * From RFC 2292 65551da177e4SLinus Torvalds * 4.2 The cmsghdr Structure * 65561da177e4SLinus Torvalds * 65571da177e4SLinus Torvalds * When ancillary data is sent or received, any number of ancillary data 65581da177e4SLinus Torvalds * objects can be specified by the msg_control and msg_controllen members of 65591da177e4SLinus Torvalds * the msghdr structure, because each object is preceded by 65601da177e4SLinus Torvalds * a cmsghdr structure defining the object's length (the cmsg_len member). 65611da177e4SLinus Torvalds * Historically Berkeley-derived implementations have passed only one object 65621da177e4SLinus Torvalds * at a time, but this API allows multiple objects to be 65631da177e4SLinus Torvalds * passed in a single call to sendmsg() or recvmsg(). The following example 65641da177e4SLinus Torvalds * shows two ancillary data objects in a control buffer. 65651da177e4SLinus Torvalds * 65661da177e4SLinus Torvalds * |<--------------------------- msg_controllen -------------------------->| 65671da177e4SLinus Torvalds * | | 65681da177e4SLinus Torvalds * 65691da177e4SLinus Torvalds * |<----- ancillary data object ----->|<----- ancillary data object ----->| 65701da177e4SLinus Torvalds * 65711da177e4SLinus Torvalds * |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->| 65721da177e4SLinus Torvalds * | | | 65731da177e4SLinus Torvalds * 65741da177e4SLinus Torvalds * |<---------- cmsg_len ---------->| |<--------- cmsg_len ----------->| | 65751da177e4SLinus Torvalds * 65761da177e4SLinus Torvalds * |<--------- CMSG_LEN() --------->| |<-------- CMSG_LEN() ---------->| | 65771da177e4SLinus Torvalds * | | | | | 65781da177e4SLinus Torvalds * 65791da177e4SLinus Torvalds * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 65801da177e4SLinus Torvalds * |cmsg_|cmsg_|cmsg_|XX| |XX|cmsg_|cmsg_|cmsg_|XX| |XX| 65811da177e4SLinus Torvalds * 65821da177e4SLinus Torvalds * |len |level|type |XX|cmsg_data[]|XX|len |level|type |XX|cmsg_data[]|XX| 65831da177e4SLinus Torvalds * 65841da177e4SLinus Torvalds * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ 65851da177e4SLinus Torvalds * ^ 65861da177e4SLinus Torvalds * | 65871da177e4SLinus Torvalds * 65881da177e4SLinus Torvalds * msg_control 65891da177e4SLinus Torvalds * points here 65901da177e4SLinus Torvalds */ 6591dda91928SDaniel Borkmann static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) 65921da177e4SLinus Torvalds { 65931da177e4SLinus Torvalds struct cmsghdr *cmsg; 6594ab38fb04SVlad Yasevich struct msghdr *my_msg = (struct msghdr *)msg; 65951da177e4SLinus Torvalds 6596f95b414eSGu Zheng for_each_cmsghdr(cmsg, my_msg) { 6597ab38fb04SVlad Yasevich if (!CMSG_OK(my_msg, cmsg)) 65981da177e4SLinus Torvalds return -EINVAL; 65991da177e4SLinus Torvalds 66001da177e4SLinus Torvalds /* Should we parse this header or ignore? */ 66011da177e4SLinus Torvalds if (cmsg->cmsg_level != IPPROTO_SCTP) 66021da177e4SLinus Torvalds continue; 66031da177e4SLinus Torvalds 66041da177e4SLinus Torvalds /* Strictly check lengths following example in SCM code. */ 66051da177e4SLinus Torvalds switch (cmsg->cmsg_type) { 66061da177e4SLinus Torvalds case SCTP_INIT: 66071da177e4SLinus Torvalds /* SCTP Socket API Extension 660863b94938SGeir Ola Vaagland * 5.3.1 SCTP Initiation Structure (SCTP_INIT) 66091da177e4SLinus Torvalds * 66101da177e4SLinus Torvalds * This cmsghdr structure provides information for 66111da177e4SLinus Torvalds * initializing new SCTP associations with sendmsg(). 66121da177e4SLinus Torvalds * The SCTP_INITMSG socket option uses this same data 66131da177e4SLinus Torvalds * structure. This structure is not used for 66141da177e4SLinus Torvalds * recvmsg(). 66151da177e4SLinus Torvalds * 66161da177e4SLinus Torvalds * cmsg_level cmsg_type cmsg_data[] 66171da177e4SLinus Torvalds * ------------ ------------ ---------------------- 66181da177e4SLinus Torvalds * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg 66191da177e4SLinus Torvalds */ 662063b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg))) 66211da177e4SLinus Torvalds return -EINVAL; 662263b94938SGeir Ola Vaagland 662363b94938SGeir Ola Vaagland cmsgs->init = CMSG_DATA(cmsg); 66241da177e4SLinus Torvalds break; 66251da177e4SLinus Torvalds 66261da177e4SLinus Torvalds case SCTP_SNDRCV: 66271da177e4SLinus Torvalds /* SCTP Socket API Extension 662863b94938SGeir Ola Vaagland * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV) 66291da177e4SLinus Torvalds * 66301da177e4SLinus Torvalds * This cmsghdr structure specifies SCTP options for 66311da177e4SLinus Torvalds * sendmsg() and describes SCTP header information 66321da177e4SLinus Torvalds * about a received message through recvmsg(). 66331da177e4SLinus Torvalds * 66341da177e4SLinus Torvalds * cmsg_level cmsg_type cmsg_data[] 66351da177e4SLinus Torvalds * ------------ ------------ ---------------------- 66361da177e4SLinus Torvalds * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo 66371da177e4SLinus Torvalds */ 663863b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) 66391da177e4SLinus Torvalds return -EINVAL; 66401da177e4SLinus Torvalds 664163b94938SGeir Ola Vaagland cmsgs->srinfo = CMSG_DATA(cmsg); 66421da177e4SLinus Torvalds 664363b94938SGeir Ola Vaagland if (cmsgs->srinfo->sinfo_flags & 6644eaa5c54dSIvan Skytte Jorgensen ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 6645eaa5c54dSIvan Skytte Jorgensen SCTP_ABORT | SCTP_EOF)) 66461da177e4SLinus Torvalds return -EINVAL; 66471da177e4SLinus Torvalds break; 66481da177e4SLinus Torvalds 664963b94938SGeir Ola Vaagland case SCTP_SNDINFO: 665063b94938SGeir Ola Vaagland /* SCTP Socket API Extension 665163b94938SGeir Ola Vaagland * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) 665263b94938SGeir Ola Vaagland * 665363b94938SGeir Ola Vaagland * This cmsghdr structure specifies SCTP options for 665463b94938SGeir Ola Vaagland * sendmsg(). This structure and SCTP_RCVINFO replaces 665563b94938SGeir Ola Vaagland * SCTP_SNDRCV which has been deprecated. 665663b94938SGeir Ola Vaagland * 665763b94938SGeir Ola Vaagland * cmsg_level cmsg_type cmsg_data[] 665863b94938SGeir Ola Vaagland * ------------ ------------ --------------------- 665963b94938SGeir Ola Vaagland * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo 666063b94938SGeir Ola Vaagland */ 666163b94938SGeir Ola Vaagland if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo))) 666263b94938SGeir Ola Vaagland return -EINVAL; 666363b94938SGeir Ola Vaagland 666463b94938SGeir Ola Vaagland cmsgs->sinfo = CMSG_DATA(cmsg); 666563b94938SGeir Ola Vaagland 666663b94938SGeir Ola Vaagland if (cmsgs->sinfo->snd_flags & 666763b94938SGeir Ola Vaagland ~(SCTP_UNORDERED | SCTP_ADDR_OVER | 666863b94938SGeir Ola Vaagland SCTP_ABORT | SCTP_EOF)) 666963b94938SGeir Ola Vaagland return -EINVAL; 667063b94938SGeir Ola Vaagland break; 66711da177e4SLinus Torvalds default: 66721da177e4SLinus Torvalds return -EINVAL; 66733ff50b79SStephen Hemminger } 66741da177e4SLinus Torvalds } 667563b94938SGeir Ola Vaagland 66761da177e4SLinus Torvalds return 0; 66771da177e4SLinus Torvalds } 66781da177e4SLinus Torvalds 66791da177e4SLinus Torvalds /* 66801da177e4SLinus Torvalds * Wait for a packet.. 66811da177e4SLinus Torvalds * Note: This function is the same function as in core/datagram.c 66821da177e4SLinus Torvalds * with a few modifications to make lksctp work. 66831da177e4SLinus Torvalds */ 66841da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p) 66851da177e4SLinus Torvalds { 66861da177e4SLinus Torvalds int error; 66871da177e4SLinus Torvalds DEFINE_WAIT(wait); 66881da177e4SLinus Torvalds 6689aa395145SEric Dumazet prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 66901da177e4SLinus Torvalds 66911da177e4SLinus Torvalds /* Socket errors? */ 66921da177e4SLinus Torvalds error = sock_error(sk); 66931da177e4SLinus Torvalds if (error) 66941da177e4SLinus Torvalds goto out; 66951da177e4SLinus Torvalds 66961da177e4SLinus Torvalds if (!skb_queue_empty(&sk->sk_receive_queue)) 66971da177e4SLinus Torvalds goto ready; 66981da177e4SLinus Torvalds 66991da177e4SLinus Torvalds /* Socket shut down? */ 67001da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 67011da177e4SLinus Torvalds goto out; 67021da177e4SLinus Torvalds 67031da177e4SLinus Torvalds /* Sequenced packets can come disconnected. If so we report the 67041da177e4SLinus Torvalds * problem. 67051da177e4SLinus Torvalds */ 67061da177e4SLinus Torvalds error = -ENOTCONN; 67071da177e4SLinus Torvalds 67081da177e4SLinus Torvalds /* Is there a good reason to think that we may receive some data? */ 67091da177e4SLinus Torvalds if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING)) 67101da177e4SLinus Torvalds goto out; 67111da177e4SLinus Torvalds 67121da177e4SLinus Torvalds /* Handle signals. */ 67131da177e4SLinus Torvalds if (signal_pending(current)) 67141da177e4SLinus Torvalds goto interrupted; 67151da177e4SLinus Torvalds 67161da177e4SLinus Torvalds /* Let another process have a go. Since we are going to sleep 67171da177e4SLinus Torvalds * anyway. Note: This may cause odd behaviors if the message 67181da177e4SLinus Torvalds * does not fit in the user's buffer, but this seems to be the 67191da177e4SLinus Torvalds * only way to honor MSG_DONTWAIT realistically. 67201da177e4SLinus Torvalds */ 6721048ed4b6Swangweidong release_sock(sk); 67221da177e4SLinus Torvalds *timeo_p = schedule_timeout(*timeo_p); 6723048ed4b6Swangweidong lock_sock(sk); 67241da177e4SLinus Torvalds 67251da177e4SLinus Torvalds ready: 6726aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 67271da177e4SLinus Torvalds return 0; 67281da177e4SLinus Torvalds 67291da177e4SLinus Torvalds interrupted: 67301da177e4SLinus Torvalds error = sock_intr_errno(*timeo_p); 67311da177e4SLinus Torvalds 67321da177e4SLinus Torvalds out: 6733aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 67341da177e4SLinus Torvalds *err = error; 67351da177e4SLinus Torvalds return error; 67361da177e4SLinus Torvalds } 67371da177e4SLinus Torvalds 67381da177e4SLinus Torvalds /* Receive a datagram. 67391da177e4SLinus Torvalds * Note: This is pretty much the same routine as in core/datagram.c 67401da177e4SLinus Torvalds * with a few changes to make lksctp work. 67411da177e4SLinus Torvalds */ 67422347c80fSGeir Ola Vaagland struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, 67431da177e4SLinus Torvalds int noblock, int *err) 67441da177e4SLinus Torvalds { 67451da177e4SLinus Torvalds int error; 67461da177e4SLinus Torvalds struct sk_buff *skb; 67471da177e4SLinus Torvalds long timeo; 67481da177e4SLinus Torvalds 67491da177e4SLinus Torvalds timeo = sock_rcvtimeo(sk, noblock); 67501da177e4SLinus Torvalds 6751bb33381dSDaniel Borkmann pr_debug("%s: timeo:%ld, max:%ld\n", __func__, timeo, 6752bb33381dSDaniel Borkmann MAX_SCHEDULE_TIMEOUT); 67531da177e4SLinus Torvalds 67541da177e4SLinus Torvalds do { 67551da177e4SLinus Torvalds /* Again only user level code calls this function, 67561da177e4SLinus Torvalds * so nothing interrupt level 67571da177e4SLinus Torvalds * will suddenly eat the receive_queue. 67581da177e4SLinus Torvalds * 67591da177e4SLinus Torvalds * Look at current nfs client by the way... 67608917a3c0SDavid Shwatrz * However, this function was correct in any case. 8) 67611da177e4SLinus Torvalds */ 67621da177e4SLinus Torvalds if (flags & MSG_PEEK) { 67631e061ab2SHerbert Xu spin_lock_bh(&sk->sk_receive_queue.lock); 67641da177e4SLinus Torvalds skb = skb_peek(&sk->sk_receive_queue); 67651da177e4SLinus Torvalds if (skb) 67661da177e4SLinus Torvalds atomic_inc(&skb->users); 67671e061ab2SHerbert Xu spin_unlock_bh(&sk->sk_receive_queue.lock); 67681da177e4SLinus Torvalds } else { 67691da177e4SLinus Torvalds skb = skb_dequeue(&sk->sk_receive_queue); 67701da177e4SLinus Torvalds } 67711da177e4SLinus Torvalds 67721da177e4SLinus Torvalds if (skb) 67731da177e4SLinus Torvalds return skb; 67741da177e4SLinus Torvalds 67756736dc35SNeil Horman /* Caller is allowed not to check sk->sk_err before calling. */ 67766736dc35SNeil Horman error = sock_error(sk); 67776736dc35SNeil Horman if (error) 67786736dc35SNeil Horman goto no_packet; 67796736dc35SNeil Horman 67801da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 67811da177e4SLinus Torvalds break; 67821da177e4SLinus Torvalds 67838465a5fcSNeil Horman if (sk_can_busy_loop(sk) && 67848465a5fcSNeil Horman sk_busy_loop(sk, noblock)) 67858465a5fcSNeil Horman continue; 67868465a5fcSNeil Horman 67871da177e4SLinus Torvalds /* User doesn't want to wait. */ 67881da177e4SLinus Torvalds error = -EAGAIN; 67891da177e4SLinus Torvalds if (!timeo) 67901da177e4SLinus Torvalds goto no_packet; 67911da177e4SLinus Torvalds } while (sctp_wait_for_packet(sk, err, &timeo) == 0); 67921da177e4SLinus Torvalds 67931da177e4SLinus Torvalds return NULL; 67941da177e4SLinus Torvalds 67951da177e4SLinus Torvalds no_packet: 67961da177e4SLinus Torvalds *err = error; 67971da177e4SLinus Torvalds return NULL; 67981da177e4SLinus Torvalds } 67991da177e4SLinus Torvalds 68001da177e4SLinus Torvalds /* If sndbuf has changed, wake up per association sndbuf waiters. */ 68011da177e4SLinus Torvalds static void __sctp_write_space(struct sctp_association *asoc) 68021da177e4SLinus Torvalds { 68031da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 68041da177e4SLinus Torvalds 6805ceb5d58bSEric Dumazet if (sctp_wspace(asoc) <= 0) 6806ceb5d58bSEric Dumazet return; 6807ceb5d58bSEric Dumazet 68081da177e4SLinus Torvalds if (waitqueue_active(&asoc->wait)) 68091da177e4SLinus Torvalds wake_up_interruptible(&asoc->wait); 68101da177e4SLinus Torvalds 68111da177e4SLinus Torvalds if (sctp_writeable(sk)) { 6812ceb5d58bSEric Dumazet struct socket_wq *wq; 6813eaefd110SEric Dumazet 6814ceb5d58bSEric Dumazet rcu_read_lock(); 6815ceb5d58bSEric Dumazet wq = rcu_dereference(sk->sk_wq); 6816ceb5d58bSEric Dumazet if (wq) { 6817ceb5d58bSEric Dumazet if (waitqueue_active(&wq->wait)) 6818ceb5d58bSEric Dumazet wake_up_interruptible(&wq->wait); 68191da177e4SLinus Torvalds 68201da177e4SLinus Torvalds /* Note that we try to include the Async I/O support 68211da177e4SLinus Torvalds * here by modeling from the current TCP/UDP code. 68221da177e4SLinus Torvalds * We have not tested with it yet. 68231da177e4SLinus Torvalds */ 6824eaefd110SEric Dumazet if (!(sk->sk_shutdown & SEND_SHUTDOWN)) 6825ceb5d58bSEric Dumazet sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT); 68261da177e4SLinus Torvalds } 6827ceb5d58bSEric Dumazet rcu_read_unlock(); 68281da177e4SLinus Torvalds } 68291da177e4SLinus Torvalds } 68301da177e4SLinus Torvalds 683152c35befSDaniel Borkmann static void sctp_wake_up_waiters(struct sock *sk, 683252c35befSDaniel Borkmann struct sctp_association *asoc) 683352c35befSDaniel Borkmann { 683452c35befSDaniel Borkmann struct sctp_association *tmp = asoc; 683552c35befSDaniel Borkmann 683652c35befSDaniel Borkmann /* We do accounting for the sndbuf space per association, 683752c35befSDaniel Borkmann * so we only need to wake our own association. 683852c35befSDaniel Borkmann */ 683952c35befSDaniel Borkmann if (asoc->ep->sndbuf_policy) 684052c35befSDaniel Borkmann return __sctp_write_space(asoc); 684152c35befSDaniel Borkmann 68421e1cdf8aSDaniel Borkmann /* If association goes down and is just flushing its 68431e1cdf8aSDaniel Borkmann * outq, then just normally notify others. 68441e1cdf8aSDaniel Borkmann */ 68451e1cdf8aSDaniel Borkmann if (asoc->base.dead) 68461e1cdf8aSDaniel Borkmann return sctp_write_space(sk); 68471e1cdf8aSDaniel Borkmann 684852c35befSDaniel Borkmann /* Accounting for the sndbuf space is per socket, so we 684952c35befSDaniel Borkmann * need to wake up others, try to be fair and in case of 685052c35befSDaniel Borkmann * other associations, let them have a go first instead 685152c35befSDaniel Borkmann * of just doing a sctp_write_space() call. 685252c35befSDaniel Borkmann * 685352c35befSDaniel Borkmann * Note that we reach sctp_wake_up_waiters() only when 685452c35befSDaniel Borkmann * associations free up queued chunks, thus we are under 685552c35befSDaniel Borkmann * lock and the list of associations on a socket is 685652c35befSDaniel Borkmann * guaranteed not to change. 685752c35befSDaniel Borkmann */ 685852c35befSDaniel Borkmann for (tmp = list_next_entry(tmp, asocs); 1; 685952c35befSDaniel Borkmann tmp = list_next_entry(tmp, asocs)) { 686052c35befSDaniel Borkmann /* Manually skip the head element. */ 686152c35befSDaniel Borkmann if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs)) 686252c35befSDaniel Borkmann continue; 686352c35befSDaniel Borkmann /* Wake up association. */ 686452c35befSDaniel Borkmann __sctp_write_space(tmp); 686552c35befSDaniel Borkmann /* We've reached the end. */ 686652c35befSDaniel Borkmann if (tmp == asoc) 686752c35befSDaniel Borkmann break; 686852c35befSDaniel Borkmann } 686952c35befSDaniel Borkmann } 687052c35befSDaniel Borkmann 68711da177e4SLinus Torvalds /* Do accounting for the sndbuf space. 68721da177e4SLinus Torvalds * Decrement the used sndbuf space of the corresponding association by the 68731da177e4SLinus Torvalds * data size which was just transmitted(freed). 68741da177e4SLinus Torvalds */ 68751da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb) 68761da177e4SLinus Torvalds { 6877f869c912SDaniel Borkmann struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg; 6878f869c912SDaniel Borkmann struct sctp_association *asoc = chunk->asoc; 6879f869c912SDaniel Borkmann struct sock *sk = asoc->base.sk; 68801da177e4SLinus Torvalds 68814eb701dfSNeil Horman asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) + 68824eb701dfSNeil Horman sizeof(struct sk_buff) + 68834eb701dfSNeil Horman sizeof(struct sctp_chunk); 68844eb701dfSNeil Horman 68854eb701dfSNeil Horman atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); 68864eb701dfSNeil Horman 68874d93df0aSNeil Horman /* 68883ab224beSHideo Aoki * This undoes what is done via sctp_set_owner_w and sk_mem_charge 68894d93df0aSNeil Horman */ 68904d93df0aSNeil Horman sk->sk_wmem_queued -= skb->truesize; 68913ab224beSHideo Aoki sk_mem_uncharge(sk, skb->truesize); 68924d93df0aSNeil Horman 68934eb701dfSNeil Horman sock_wfree(skb); 689452c35befSDaniel Borkmann sctp_wake_up_waiters(sk, asoc); 68951da177e4SLinus Torvalds 68961da177e4SLinus Torvalds sctp_association_put(asoc); 68971da177e4SLinus Torvalds } 68981da177e4SLinus Torvalds 6899331c4ee7SVlad Yasevich /* Do accounting for the receive space on the socket. 6900331c4ee7SVlad Yasevich * Accounting for the association is done in ulpevent.c 6901331c4ee7SVlad Yasevich * We set this as a destructor for the cloned data skbs so that 6902331c4ee7SVlad Yasevich * accounting is done at the correct time. 6903331c4ee7SVlad Yasevich */ 6904331c4ee7SVlad Yasevich void sctp_sock_rfree(struct sk_buff *skb) 6905331c4ee7SVlad Yasevich { 6906331c4ee7SVlad Yasevich struct sock *sk = skb->sk; 6907331c4ee7SVlad Yasevich struct sctp_ulpevent *event = sctp_skb2event(skb); 6908331c4ee7SVlad Yasevich 6909331c4ee7SVlad Yasevich atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); 69104d93df0aSNeil Horman 69114d93df0aSNeil Horman /* 69123ab224beSHideo Aoki * Mimic the behavior of sock_rfree 69134d93df0aSNeil Horman */ 69143ab224beSHideo Aoki sk_mem_uncharge(sk, event->rmem_len); 6915331c4ee7SVlad Yasevich } 6916331c4ee7SVlad Yasevich 6917331c4ee7SVlad Yasevich 69181da177e4SLinus Torvalds /* Helper function to wait for space in the sndbuf. */ 69191da177e4SLinus Torvalds static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 69201da177e4SLinus Torvalds size_t msg_len) 69211da177e4SLinus Torvalds { 69221da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 69231da177e4SLinus Torvalds int err = 0; 69241da177e4SLinus Torvalds long current_timeo = *timeo_p; 69251da177e4SLinus Torvalds DEFINE_WAIT(wait); 69261da177e4SLinus Torvalds 6927bb33381dSDaniel Borkmann pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc, 6928bb33381dSDaniel Borkmann *timeo_p, msg_len); 69291da177e4SLinus Torvalds 69301da177e4SLinus Torvalds /* Increment the association's refcnt. */ 69311da177e4SLinus Torvalds sctp_association_hold(asoc); 69321da177e4SLinus Torvalds 69331da177e4SLinus Torvalds /* Wait on the association specific sndbuf space. */ 69341da177e4SLinus Torvalds for (;;) { 69351da177e4SLinus Torvalds prepare_to_wait_exclusive(&asoc->wait, &wait, 69361da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 69371da177e4SLinus Torvalds if (!*timeo_p) 69381da177e4SLinus Torvalds goto do_nonblock; 69391da177e4SLinus Torvalds if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || 69401da177e4SLinus Torvalds asoc->base.dead) 69411da177e4SLinus Torvalds goto do_error; 69421da177e4SLinus Torvalds if (signal_pending(current)) 69431da177e4SLinus Torvalds goto do_interrupted; 69441da177e4SLinus Torvalds if (msg_len <= sctp_wspace(asoc)) 69451da177e4SLinus Torvalds break; 69461da177e4SLinus Torvalds 69471da177e4SLinus Torvalds /* Let another process have a go. Since we are going 69481da177e4SLinus Torvalds * to sleep anyway. 69491da177e4SLinus Torvalds */ 6950048ed4b6Swangweidong release_sock(sk); 69511da177e4SLinus Torvalds current_timeo = schedule_timeout(current_timeo); 695261c9fed4SVladislav Yasevich BUG_ON(sk != asoc->base.sk); 6953048ed4b6Swangweidong lock_sock(sk); 69541da177e4SLinus Torvalds 69551da177e4SLinus Torvalds *timeo_p = current_timeo; 69561da177e4SLinus Torvalds } 69571da177e4SLinus Torvalds 69581da177e4SLinus Torvalds out: 69591da177e4SLinus Torvalds finish_wait(&asoc->wait, &wait); 69601da177e4SLinus Torvalds 69611da177e4SLinus Torvalds /* Release the association's refcnt. */ 69621da177e4SLinus Torvalds sctp_association_put(asoc); 69631da177e4SLinus Torvalds 69641da177e4SLinus Torvalds return err; 69651da177e4SLinus Torvalds 69661da177e4SLinus Torvalds do_error: 69671da177e4SLinus Torvalds err = -EPIPE; 69681da177e4SLinus Torvalds goto out; 69691da177e4SLinus Torvalds 69701da177e4SLinus Torvalds do_interrupted: 69711da177e4SLinus Torvalds err = sock_intr_errno(*timeo_p); 69721da177e4SLinus Torvalds goto out; 69731da177e4SLinus Torvalds 69741da177e4SLinus Torvalds do_nonblock: 69751da177e4SLinus Torvalds err = -EAGAIN; 69761da177e4SLinus Torvalds goto out; 69771da177e4SLinus Torvalds } 69781da177e4SLinus Torvalds 6979676d2369SDavid S. Miller void sctp_data_ready(struct sock *sk) 6980561b1733SWei Yongjun { 69817ef52737SDavid S. Miller struct socket_wq *wq; 69827ef52737SDavid S. Miller 69837ef52737SDavid S. Miller rcu_read_lock(); 69847ef52737SDavid S. Miller wq = rcu_dereference(sk->sk_wq); 69857ef52737SDavid S. Miller if (wq_has_sleeper(wq)) 69867ef52737SDavid S. Miller wake_up_interruptible_sync_poll(&wq->wait, POLLIN | 6987561b1733SWei Yongjun POLLRDNORM | POLLRDBAND); 6988561b1733SWei Yongjun sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); 69897ef52737SDavid S. Miller rcu_read_unlock(); 6990561b1733SWei Yongjun } 6991561b1733SWei Yongjun 69921da177e4SLinus Torvalds /* If socket sndbuf has changed, wake up all per association waiters. */ 69931da177e4SLinus Torvalds void sctp_write_space(struct sock *sk) 69941da177e4SLinus Torvalds { 69951da177e4SLinus Torvalds struct sctp_association *asoc; 69961da177e4SLinus Torvalds 69971da177e4SLinus Torvalds /* Wake up the tasks in each wait queue. */ 69989dbc15f0SRobert P. J. Day list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) { 69991da177e4SLinus Torvalds __sctp_write_space(asoc); 70001da177e4SLinus Torvalds } 70011da177e4SLinus Torvalds } 70021da177e4SLinus Torvalds 70031da177e4SLinus Torvalds /* Is there any sndbuf space available on the socket? 70041da177e4SLinus Torvalds * 70059bffc4acSNeil Horman * Note that sk_wmem_alloc is the sum of the send buffers on all of the 70061da177e4SLinus Torvalds * associations on the same socket. For a UDP-style socket with 70071da177e4SLinus Torvalds * multiple associations, it is possible for it to be "unwriteable" 70081da177e4SLinus Torvalds * prematurely. I assume that this is acceptable because 70091da177e4SLinus Torvalds * a premature "unwriteable" is better than an accidental "writeable" which 70101da177e4SLinus Torvalds * would cause an unwanted block under certain circumstances. For the 1-1 70111da177e4SLinus Torvalds * UDP-style sockets or TCP-style sockets, this code should work. 70121da177e4SLinus Torvalds * - Daisy 70131da177e4SLinus Torvalds */ 70141da177e4SLinus Torvalds static int sctp_writeable(struct sock *sk) 70151da177e4SLinus Torvalds { 70161da177e4SLinus Torvalds int amt = 0; 70171da177e4SLinus Torvalds 701831e6d363SEric Dumazet amt = sk->sk_sndbuf - sk_wmem_alloc_get(sk); 70191da177e4SLinus Torvalds if (amt < 0) 70201da177e4SLinus Torvalds amt = 0; 70211da177e4SLinus Torvalds return amt; 70221da177e4SLinus Torvalds } 70231da177e4SLinus Torvalds 70241da177e4SLinus Torvalds /* Wait for an association to go into ESTABLISHED state. If timeout is 0, 70251da177e4SLinus Torvalds * returns immediately with EINPROGRESS. 70261da177e4SLinus Torvalds */ 70271da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) 70281da177e4SLinus Torvalds { 70291da177e4SLinus Torvalds struct sock *sk = asoc->base.sk; 70301da177e4SLinus Torvalds int err = 0; 70311da177e4SLinus Torvalds long current_timeo = *timeo_p; 70321da177e4SLinus Torvalds DEFINE_WAIT(wait); 70331da177e4SLinus Torvalds 7034bb33381dSDaniel Borkmann pr_debug("%s: asoc:%p, timeo:%ld\n", __func__, asoc, *timeo_p); 70351da177e4SLinus Torvalds 70361da177e4SLinus Torvalds /* Increment the association's refcnt. */ 70371da177e4SLinus Torvalds sctp_association_hold(asoc); 70381da177e4SLinus Torvalds 70391da177e4SLinus Torvalds for (;;) { 70401da177e4SLinus Torvalds prepare_to_wait_exclusive(&asoc->wait, &wait, 70411da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 70421da177e4SLinus Torvalds if (!*timeo_p) 70431da177e4SLinus Torvalds goto do_nonblock; 70441da177e4SLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 70451da177e4SLinus Torvalds break; 70461da177e4SLinus Torvalds if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || 70471da177e4SLinus Torvalds asoc->base.dead) 70481da177e4SLinus Torvalds goto do_error; 70491da177e4SLinus Torvalds if (signal_pending(current)) 70501da177e4SLinus Torvalds goto do_interrupted; 70511da177e4SLinus Torvalds 70521da177e4SLinus Torvalds if (sctp_state(asoc, ESTABLISHED)) 70531da177e4SLinus Torvalds break; 70541da177e4SLinus Torvalds 70551da177e4SLinus Torvalds /* Let another process have a go. Since we are going 70561da177e4SLinus Torvalds * to sleep anyway. 70571da177e4SLinus Torvalds */ 7058048ed4b6Swangweidong release_sock(sk); 70591da177e4SLinus Torvalds current_timeo = schedule_timeout(current_timeo); 7060048ed4b6Swangweidong lock_sock(sk); 70611da177e4SLinus Torvalds 70621da177e4SLinus Torvalds *timeo_p = current_timeo; 70631da177e4SLinus Torvalds } 70641da177e4SLinus Torvalds 70651da177e4SLinus Torvalds out: 70661da177e4SLinus Torvalds finish_wait(&asoc->wait, &wait); 70671da177e4SLinus Torvalds 70681da177e4SLinus Torvalds /* Release the association's refcnt. */ 70691da177e4SLinus Torvalds sctp_association_put(asoc); 70701da177e4SLinus Torvalds 70711da177e4SLinus Torvalds return err; 70721da177e4SLinus Torvalds 70731da177e4SLinus Torvalds do_error: 707481845c21SVlad Yasevich if (asoc->init_err_counter + 1 > asoc->max_init_attempts) 70751da177e4SLinus Torvalds err = -ETIMEDOUT; 70761da177e4SLinus Torvalds else 70771da177e4SLinus Torvalds err = -ECONNREFUSED; 70781da177e4SLinus Torvalds goto out; 70791da177e4SLinus Torvalds 70801da177e4SLinus Torvalds do_interrupted: 70811da177e4SLinus Torvalds err = sock_intr_errno(*timeo_p); 70821da177e4SLinus Torvalds goto out; 70831da177e4SLinus Torvalds 70841da177e4SLinus Torvalds do_nonblock: 70851da177e4SLinus Torvalds err = -EINPROGRESS; 70861da177e4SLinus Torvalds goto out; 70871da177e4SLinus Torvalds } 70881da177e4SLinus Torvalds 70891da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo) 70901da177e4SLinus Torvalds { 70911da177e4SLinus Torvalds struct sctp_endpoint *ep; 70921da177e4SLinus Torvalds int err = 0; 70931da177e4SLinus Torvalds DEFINE_WAIT(wait); 70941da177e4SLinus Torvalds 70951da177e4SLinus Torvalds ep = sctp_sk(sk)->ep; 70961da177e4SLinus Torvalds 70971da177e4SLinus Torvalds 70981da177e4SLinus Torvalds for (;;) { 7099aa395145SEric Dumazet prepare_to_wait_exclusive(sk_sleep(sk), &wait, 71001da177e4SLinus Torvalds TASK_INTERRUPTIBLE); 71011da177e4SLinus Torvalds 71021da177e4SLinus Torvalds if (list_empty(&ep->asocs)) { 7103048ed4b6Swangweidong release_sock(sk); 71041da177e4SLinus Torvalds timeo = schedule_timeout(timeo); 7105048ed4b6Swangweidong lock_sock(sk); 71061da177e4SLinus Torvalds } 71071da177e4SLinus Torvalds 71081da177e4SLinus Torvalds err = -EINVAL; 71091da177e4SLinus Torvalds if (!sctp_sstate(sk, LISTENING)) 71101da177e4SLinus Torvalds break; 71111da177e4SLinus Torvalds 71121da177e4SLinus Torvalds err = 0; 71131da177e4SLinus Torvalds if (!list_empty(&ep->asocs)) 71141da177e4SLinus Torvalds break; 71151da177e4SLinus Torvalds 71161da177e4SLinus Torvalds err = sock_intr_errno(timeo); 71171da177e4SLinus Torvalds if (signal_pending(current)) 71181da177e4SLinus Torvalds break; 71191da177e4SLinus Torvalds 71201da177e4SLinus Torvalds err = -EAGAIN; 71211da177e4SLinus Torvalds if (!timeo) 71221da177e4SLinus Torvalds break; 71231da177e4SLinus Torvalds } 71241da177e4SLinus Torvalds 7125aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 71261da177e4SLinus Torvalds 71271da177e4SLinus Torvalds return err; 71281da177e4SLinus Torvalds } 71291da177e4SLinus Torvalds 713004675210Ssebastian@breakpoint.cc static void sctp_wait_for_close(struct sock *sk, long timeout) 71311da177e4SLinus Torvalds { 71321da177e4SLinus Torvalds DEFINE_WAIT(wait); 71331da177e4SLinus Torvalds 71341da177e4SLinus Torvalds do { 7135aa395145SEric Dumazet prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 71361da177e4SLinus Torvalds if (list_empty(&sctp_sk(sk)->ep->asocs)) 71371da177e4SLinus Torvalds break; 7138048ed4b6Swangweidong release_sock(sk); 71391da177e4SLinus Torvalds timeout = schedule_timeout(timeout); 7140048ed4b6Swangweidong lock_sock(sk); 71411da177e4SLinus Torvalds } while (!signal_pending(current) && timeout); 71421da177e4SLinus Torvalds 7143aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait); 71441da177e4SLinus Torvalds } 71451da177e4SLinus Torvalds 7146ea2bc483STsutomu Fujii static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) 7147ea2bc483STsutomu Fujii { 7148ea2bc483STsutomu Fujii struct sk_buff *frag; 7149ea2bc483STsutomu Fujii 7150ea2bc483STsutomu Fujii if (!skb->data_len) 7151ea2bc483STsutomu Fujii goto done; 7152ea2bc483STsutomu Fujii 7153ea2bc483STsutomu Fujii /* Don't forget the fragments. */ 71541b003be3SDavid S. Miller skb_walk_frags(skb, frag) 7155ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(frag, sk); 7156ea2bc483STsutomu Fujii 7157ea2bc483STsutomu Fujii done: 7158ea2bc483STsutomu Fujii sctp_skb_set_owner_r(skb, sk); 7159ea2bc483STsutomu Fujii } 7160ea2bc483STsutomu Fujii 7161914e1c8bSVlad Yasevich void sctp_copy_sock(struct sock *newsk, struct sock *sk, 7162914e1c8bSVlad Yasevich struct sctp_association *asoc) 7163914e1c8bSVlad Yasevich { 7164914e1c8bSVlad Yasevich struct inet_sock *inet = inet_sk(sk); 716509cb47a2SJulia Lawall struct inet_sock *newinet; 7166914e1c8bSVlad Yasevich 7167914e1c8bSVlad Yasevich newsk->sk_type = sk->sk_type; 7168914e1c8bSVlad Yasevich newsk->sk_bound_dev_if = sk->sk_bound_dev_if; 7169914e1c8bSVlad Yasevich newsk->sk_flags = sk->sk_flags; 717028448b80STom Herbert newsk->sk_no_check_tx = sk->sk_no_check_tx; 717128448b80STom Herbert newsk->sk_no_check_rx = sk->sk_no_check_rx; 7172914e1c8bSVlad Yasevich newsk->sk_reuse = sk->sk_reuse; 7173914e1c8bSVlad Yasevich 7174914e1c8bSVlad Yasevich newsk->sk_shutdown = sk->sk_shutdown; 71750a2fbac1SDaniel Borkmann newsk->sk_destruct = sctp_destruct_sock; 7176914e1c8bSVlad Yasevich newsk->sk_family = sk->sk_family; 7177914e1c8bSVlad Yasevich newsk->sk_protocol = IPPROTO_SCTP; 7178914e1c8bSVlad Yasevich newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; 7179914e1c8bSVlad Yasevich newsk->sk_sndbuf = sk->sk_sndbuf; 7180914e1c8bSVlad Yasevich newsk->sk_rcvbuf = sk->sk_rcvbuf; 7181914e1c8bSVlad Yasevich newsk->sk_lingertime = sk->sk_lingertime; 7182914e1c8bSVlad Yasevich newsk->sk_rcvtimeo = sk->sk_rcvtimeo; 7183914e1c8bSVlad Yasevich newsk->sk_sndtimeo = sk->sk_sndtimeo; 7184914e1c8bSVlad Yasevich 7185914e1c8bSVlad Yasevich newinet = inet_sk(newsk); 7186914e1c8bSVlad Yasevich 7187914e1c8bSVlad Yasevich /* Initialize sk's sport, dport, rcv_saddr and daddr for 7188914e1c8bSVlad Yasevich * getsockname() and getpeername() 7189914e1c8bSVlad Yasevich */ 7190c720c7e8SEric Dumazet newinet->inet_sport = inet->inet_sport; 7191c720c7e8SEric Dumazet newinet->inet_saddr = inet->inet_saddr; 7192c720c7e8SEric Dumazet newinet->inet_rcv_saddr = inet->inet_rcv_saddr; 7193c720c7e8SEric Dumazet newinet->inet_dport = htons(asoc->peer.port); 7194914e1c8bSVlad Yasevich newinet->pmtudisc = inet->pmtudisc; 7195c720c7e8SEric Dumazet newinet->inet_id = asoc->next_tsn ^ jiffies; 7196914e1c8bSVlad Yasevich 7197914e1c8bSVlad Yasevich newinet->uc_ttl = inet->uc_ttl; 7198914e1c8bSVlad Yasevich newinet->mc_loop = 1; 7199914e1c8bSVlad Yasevich newinet->mc_ttl = 1; 7200914e1c8bSVlad Yasevich newinet->mc_index = 0; 7201914e1c8bSVlad Yasevich newinet->mc_list = NULL; 7202*01ce63c9SMarcelo Ricardo Leitner 7203*01ce63c9SMarcelo Ricardo Leitner if (newsk->sk_flags & SK_FLAGS_TIMESTAMP) 7204*01ce63c9SMarcelo Ricardo Leitner net_enable_timestamp(); 7205914e1c8bSVlad Yasevich } 7206914e1c8bSVlad Yasevich 72072d45a02dSMarcelo Ricardo Leitner static inline void sctp_copy_descendant(struct sock *sk_to, 72082d45a02dSMarcelo Ricardo Leitner const struct sock *sk_from) 72092d45a02dSMarcelo Ricardo Leitner { 72102d45a02dSMarcelo Ricardo Leitner int ancestor_size = sizeof(struct inet_sock) + 72112d45a02dSMarcelo Ricardo Leitner sizeof(struct sctp_sock) - 72122d45a02dSMarcelo Ricardo Leitner offsetof(struct sctp_sock, auto_asconf_list); 72132d45a02dSMarcelo Ricardo Leitner 72142d45a02dSMarcelo Ricardo Leitner if (sk_from->sk_family == PF_INET6) 72152d45a02dSMarcelo Ricardo Leitner ancestor_size += sizeof(struct ipv6_pinfo); 72162d45a02dSMarcelo Ricardo Leitner 72172d45a02dSMarcelo Ricardo Leitner __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); 72182d45a02dSMarcelo Ricardo Leitner } 72192d45a02dSMarcelo Ricardo Leitner 72201da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the assoc 72211da177e4SLinus Torvalds * and its messages to the newsk. 72221da177e4SLinus Torvalds */ 72231da177e4SLinus Torvalds static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, 72241da177e4SLinus Torvalds struct sctp_association *assoc, 72251da177e4SLinus Torvalds sctp_socket_type_t type) 72261da177e4SLinus Torvalds { 72271da177e4SLinus Torvalds struct sctp_sock *oldsp = sctp_sk(oldsk); 72281da177e4SLinus Torvalds struct sctp_sock *newsp = sctp_sk(newsk); 72291da177e4SLinus Torvalds struct sctp_bind_bucket *pp; /* hash list port iterator */ 72301da177e4SLinus Torvalds struct sctp_endpoint *newep = newsp->ep; 72311da177e4SLinus Torvalds struct sk_buff *skb, *tmp; 72321da177e4SLinus Torvalds struct sctp_ulpevent *event; 7233f26f7c48SVlad Yasevich struct sctp_bind_hashbucket *head; 72341da177e4SLinus Torvalds 72351da177e4SLinus Torvalds /* Migrate socket buffer sizes and all the socket level options to the 72361da177e4SLinus Torvalds * new socket. 72371da177e4SLinus Torvalds */ 72381da177e4SLinus Torvalds newsk->sk_sndbuf = oldsk->sk_sndbuf; 72391da177e4SLinus Torvalds newsk->sk_rcvbuf = oldsk->sk_rcvbuf; 72401da177e4SLinus Torvalds /* Brute force copy old sctp opt. */ 72412d45a02dSMarcelo Ricardo Leitner sctp_copy_descendant(newsk, oldsk); 72421da177e4SLinus Torvalds 72431da177e4SLinus Torvalds /* Restore the ep value that was overwritten with the above structure 72441da177e4SLinus Torvalds * copy. 72451da177e4SLinus Torvalds */ 72461da177e4SLinus Torvalds newsp->ep = newep; 72471da177e4SLinus Torvalds newsp->hmac = NULL; 72481da177e4SLinus Torvalds 72491da177e4SLinus Torvalds /* Hook this new socket in to the bind_hash list. */ 7250f1f43763SEric W. Biederman head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk), 7251f1f43763SEric W. Biederman inet_sk(oldsk)->inet_num)]; 725279b91130Swangweidong local_bh_disable(); 72533c8e43baSwangweidong spin_lock(&head->lock); 72541da177e4SLinus Torvalds pp = sctp_sk(oldsk)->bind_hash; 72551da177e4SLinus Torvalds sk_add_bind_node(newsk, &pp->owner); 72561da177e4SLinus Torvalds sctp_sk(newsk)->bind_hash = pp; 7257c720c7e8SEric Dumazet inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num; 72583c8e43baSwangweidong spin_unlock(&head->lock); 725979b91130Swangweidong local_bh_enable(); 72601da177e4SLinus Torvalds 72614243cac1SVladislav Yasevich /* Copy the bind_addr list from the original endpoint to the new 72624243cac1SVladislav Yasevich * endpoint so that we can handle restarts properly 72634243cac1SVladislav Yasevich */ 72648e71a11cSVlad Yasevich sctp_bind_addr_dup(&newsp->ep->base.bind_addr, 72658e71a11cSVlad Yasevich &oldsp->ep->base.bind_addr, GFP_KERNEL); 72664243cac1SVladislav Yasevich 72671da177e4SLinus Torvalds /* Move any messages in the old socket's receive queue that are for the 72681da177e4SLinus Torvalds * peeled off association to the new socket's receive queue. 72691da177e4SLinus Torvalds */ 72701da177e4SLinus Torvalds sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { 72711da177e4SLinus Torvalds event = sctp_skb2event(skb); 72721da177e4SLinus Torvalds if (event->asoc == assoc) { 72738728b834SDavid S. Miller __skb_unlink(skb, &oldsk->sk_receive_queue); 72741da177e4SLinus Torvalds __skb_queue_tail(&newsk->sk_receive_queue, skb); 7275ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 72761da177e4SLinus Torvalds } 72771da177e4SLinus Torvalds } 72781da177e4SLinus Torvalds 72791da177e4SLinus Torvalds /* Clean up any messages pending delivery due to partial 72801da177e4SLinus Torvalds * delivery. Three cases: 72811da177e4SLinus Torvalds * 1) No partial deliver; no work. 72821da177e4SLinus Torvalds * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby. 72831da177e4SLinus Torvalds * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue. 72841da177e4SLinus Torvalds */ 72851da177e4SLinus Torvalds skb_queue_head_init(&newsp->pd_lobby); 7286b6e1331fSVlad Yasevich atomic_set(&sctp_sk(newsk)->pd_mode, assoc->ulpq.pd_mode); 72871da177e4SLinus Torvalds 7288b6e1331fSVlad Yasevich if (atomic_read(&sctp_sk(oldsk)->pd_mode)) { 72891da177e4SLinus Torvalds struct sk_buff_head *queue; 72901da177e4SLinus Torvalds 72911da177e4SLinus Torvalds /* Decide which queue to move pd_lobby skbs to. */ 72921da177e4SLinus Torvalds if (assoc->ulpq.pd_mode) { 72931da177e4SLinus Torvalds queue = &newsp->pd_lobby; 72941da177e4SLinus Torvalds } else 72951da177e4SLinus Torvalds queue = &newsk->sk_receive_queue; 72961da177e4SLinus Torvalds 72971da177e4SLinus Torvalds /* Walk through the pd_lobby, looking for skbs that 72981da177e4SLinus Torvalds * need moved to the new socket. 72991da177e4SLinus Torvalds */ 73001da177e4SLinus Torvalds sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { 73011da177e4SLinus Torvalds event = sctp_skb2event(skb); 73021da177e4SLinus Torvalds if (event->asoc == assoc) { 73038728b834SDavid S. Miller __skb_unlink(skb, &oldsp->pd_lobby); 73041da177e4SLinus Torvalds __skb_queue_tail(queue, skb); 7305ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 73061da177e4SLinus Torvalds } 73071da177e4SLinus Torvalds } 73081da177e4SLinus Torvalds 73091da177e4SLinus Torvalds /* Clear up any skbs waiting for the partial 73101da177e4SLinus Torvalds * delivery to finish. 73111da177e4SLinus Torvalds */ 73121da177e4SLinus Torvalds if (assoc->ulpq.pd_mode) 7313b6e1331fSVlad Yasevich sctp_clear_pd(oldsk, NULL); 73141da177e4SLinus Torvalds 73151da177e4SLinus Torvalds } 73161da177e4SLinus Torvalds 73171bc4ee40SWei Yongjun sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp) 7318ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 7319ea2bc483STsutomu Fujii 73201bc4ee40SWei Yongjun sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp) 7321ea2bc483STsutomu Fujii sctp_skb_set_owner_r_frag(skb, newsk); 7322ea2bc483STsutomu Fujii 73231da177e4SLinus Torvalds /* Set the type of socket to indicate that it is peeled off from the 73241da177e4SLinus Torvalds * original UDP-style socket or created with the accept() call on a 73251da177e4SLinus Torvalds * TCP-style socket.. 73261da177e4SLinus Torvalds */ 73271da177e4SLinus Torvalds newsp->type = type; 73281da177e4SLinus Torvalds 732961c9fed4SVladislav Yasevich /* Mark the new socket "in-use" by the user so that any packets 733061c9fed4SVladislav Yasevich * that may arrive on the association after we've moved it are 733161c9fed4SVladislav Yasevich * queued to the backlog. This prevents a potential race between 733261c9fed4SVladislav Yasevich * backlog processing on the old socket and new-packet processing 733361c9fed4SVladislav Yasevich * on the new socket. 73345131a184SZach Brown * 73355131a184SZach Brown * The caller has just allocated newsk so we can guarantee that other 73365131a184SZach Brown * paths won't try to lock it and then oldsk. 733761c9fed4SVladislav Yasevich */ 73385131a184SZach Brown lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); 73391da177e4SLinus Torvalds sctp_assoc_migrate(assoc, newsk); 73401da177e4SLinus Torvalds 73411da177e4SLinus Torvalds /* If the association on the newsk is already closed before accept() 73421da177e4SLinus Torvalds * is called, set RCV_SHUTDOWN flag. 73431da177e4SLinus Torvalds */ 73441da177e4SLinus Torvalds if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) 73451da177e4SLinus Torvalds newsk->sk_shutdown |= RCV_SHUTDOWN; 73461da177e4SLinus Torvalds 73471da177e4SLinus Torvalds newsk->sk_state = SCTP_SS_ESTABLISHED; 7348048ed4b6Swangweidong release_sock(newsk); 73491da177e4SLinus Torvalds } 73501da177e4SLinus Torvalds 73514d93df0aSNeil Horman 73521da177e4SLinus Torvalds /* This proto struct describes the ULP interface for SCTP. */ 73531da177e4SLinus Torvalds struct proto sctp_prot = { 73541da177e4SLinus Torvalds .name = "SCTP", 73551da177e4SLinus Torvalds .owner = THIS_MODULE, 73561da177e4SLinus Torvalds .close = sctp_close, 73571da177e4SLinus Torvalds .connect = sctp_connect, 73581da177e4SLinus Torvalds .disconnect = sctp_disconnect, 73591da177e4SLinus Torvalds .accept = sctp_accept, 73601da177e4SLinus Torvalds .ioctl = sctp_ioctl, 73611da177e4SLinus Torvalds .init = sctp_init_sock, 73621da177e4SLinus Torvalds .destroy = sctp_destroy_sock, 73631da177e4SLinus Torvalds .shutdown = sctp_shutdown, 73641da177e4SLinus Torvalds .setsockopt = sctp_setsockopt, 73651da177e4SLinus Torvalds .getsockopt = sctp_getsockopt, 73661da177e4SLinus Torvalds .sendmsg = sctp_sendmsg, 73671da177e4SLinus Torvalds .recvmsg = sctp_recvmsg, 73681da177e4SLinus Torvalds .bind = sctp_bind, 73691da177e4SLinus Torvalds .backlog_rcv = sctp_backlog_rcv, 73701da177e4SLinus Torvalds .hash = sctp_hash, 73711da177e4SLinus Torvalds .unhash = sctp_unhash, 73721da177e4SLinus Torvalds .get_port = sctp_get_port, 73731da177e4SLinus Torvalds .obj_size = sizeof(struct sctp_sock), 73744d93df0aSNeil Horman .sysctl_mem = sysctl_sctp_mem, 73754d93df0aSNeil Horman .sysctl_rmem = sysctl_sctp_rmem, 73764d93df0aSNeil Horman .sysctl_wmem = sysctl_sctp_wmem, 73774d93df0aSNeil Horman .memory_pressure = &sctp_memory_pressure, 73784d93df0aSNeil Horman .enter_memory_pressure = sctp_enter_memory_pressure, 73794d93df0aSNeil Horman .memory_allocated = &sctp_memory_allocated, 73805f31886fSPavel Emelyanov .sockets_allocated = &sctp_sockets_allocated, 73811da177e4SLinus Torvalds }; 73821da177e4SLinus Torvalds 7383dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 73848295b6d9SEric Dumazet 7385602dd62dSEric Dumazet #include <net/transp_v6.h> 7386602dd62dSEric Dumazet static void sctp_v6_destroy_sock(struct sock *sk) 7387602dd62dSEric Dumazet { 7388602dd62dSEric Dumazet sctp_destroy_sock(sk); 7389602dd62dSEric Dumazet inet6_destroy_sock(sk); 7390602dd62dSEric Dumazet } 7391602dd62dSEric Dumazet 73921da177e4SLinus Torvalds struct proto sctpv6_prot = { 73931da177e4SLinus Torvalds .name = "SCTPv6", 73941da177e4SLinus Torvalds .owner = THIS_MODULE, 73951da177e4SLinus Torvalds .close = sctp_close, 73961da177e4SLinus Torvalds .connect = sctp_connect, 73971da177e4SLinus Torvalds .disconnect = sctp_disconnect, 73981da177e4SLinus Torvalds .accept = sctp_accept, 73991da177e4SLinus Torvalds .ioctl = sctp_ioctl, 74001da177e4SLinus Torvalds .init = sctp_init_sock, 7401602dd62dSEric Dumazet .destroy = sctp_v6_destroy_sock, 74021da177e4SLinus Torvalds .shutdown = sctp_shutdown, 74031da177e4SLinus Torvalds .setsockopt = sctp_setsockopt, 74041da177e4SLinus Torvalds .getsockopt = sctp_getsockopt, 74051da177e4SLinus Torvalds .sendmsg = sctp_sendmsg, 74061da177e4SLinus Torvalds .recvmsg = sctp_recvmsg, 74071da177e4SLinus Torvalds .bind = sctp_bind, 74081da177e4SLinus Torvalds .backlog_rcv = sctp_backlog_rcv, 74091da177e4SLinus Torvalds .hash = sctp_hash, 74101da177e4SLinus Torvalds .unhash = sctp_unhash, 74111da177e4SLinus Torvalds .get_port = sctp_get_port, 74121da177e4SLinus Torvalds .obj_size = sizeof(struct sctp6_sock), 74134d93df0aSNeil Horman .sysctl_mem = sysctl_sctp_mem, 74144d93df0aSNeil Horman .sysctl_rmem = sysctl_sctp_rmem, 74154d93df0aSNeil Horman .sysctl_wmem = sysctl_sctp_wmem, 74164d93df0aSNeil Horman .memory_pressure = &sctp_memory_pressure, 74174d93df0aSNeil Horman .enter_memory_pressure = sctp_enter_memory_pressure, 74184d93df0aSNeil Horman .memory_allocated = &sctp_memory_allocated, 74195f31886fSPavel Emelyanov .sockets_allocated = &sctp_sockets_allocated, 74201da177e4SLinus Torvalds }; 7421dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */ 7422