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