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