xref: /openbmc/linux/net/sctp/socket.c (revision 01ce63c90170283a9855d1db4fe81934dddce648)
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(&param32, 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(&param, 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(&params, 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 *)&params.spp_address)) {
25281da177e4SLinus Torvalds 		trans = sctp_addr_id2transport(sk, &params.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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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 *)&params.spp_address)) {
46151da177e4SLinus Torvalds 		trans = sctp_addr_id2transport(sk, &params.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, &params, 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(&params, 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(&params, 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, &params, 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(&params, 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, &params, 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(&params, 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, &params.assoc_value, len))
54351da177e4SLinus Torvalds 			return -EFAULT;
5436e89c2095SWei Yongjun 	} else {
5437e89c2095SWei Yongjun 		if (copy_to_user(optval, &params, 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(&params, 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, &params.assoc_value, len))
5529219b99a9SNeil Horman 			return -EFAULT;
5530219b99a9SNeil Horman 	} else {
5531219b99a9SNeil Horman 		if (copy_to_user(optval, &params, 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