xref: /openbmc/linux/net/sctp/socket.c (revision 7b7fd0ac7dc1ffcaf24d9bca0f051b0168e43cd4)
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>
6240e0b090SPeilin Ye #include <trace/events/sock.h>
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds #include <linux/socket.h> /* for sa_family_t */
65bc3b2d7fSPaul Gortmaker #include <linux/export.h>
661da177e4SLinus Torvalds #include <net/sock.h>
671da177e4SLinus Torvalds #include <net/sctp/sctp.h>
681da177e4SLinus Torvalds #include <net/sctp/sm.h>
6913aa8770SMarcelo Ricardo Leitner #include <net/sctp/stream_sched.h>
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds /* Forward declarations for internal helper functions. */
72dc9511ddSEric Dumazet static bool sctp_writeable(const struct sock *sk);
731da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb);
74cea0cc80SXin Long static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
75a0ff6600SXin Long 				size_t msg_len);
761da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p);
771da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
781da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo);
791da177e4SLinus Torvalds static void sctp_wait_for_close(struct sock *sk, long timeo);
800a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk);
811da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
821da177e4SLinus Torvalds 					union sctp_addr *addr, int len);
831da177e4SLinus Torvalds static int sctp_bindx_add(struct sock *, struct sockaddr *, int);
841da177e4SLinus Torvalds static int sctp_bindx_rem(struct sock *, struct sockaddr *, int);
851da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int);
861da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int);
871da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc,
881da177e4SLinus Torvalds 			    struct sctp_chunk *chunk);
891da177e4SLinus Torvalds static int sctp_do_bind(struct sock *, union sctp_addr *, int);
901da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk);
9189664c62SXin Long static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
92b7ef2618SXin Long 			     struct sctp_association *assoc,
93b7ef2618SXin Long 			     enum sctp_socket_type type);
941da177e4SLinus Torvalds 
9506044751SEric Dumazet static unsigned long sctp_memory_pressure;
968d987e5cSEric Dumazet static atomic_long_t sctp_memory_allocated;
970defbb0aSEric Dumazet static DEFINE_PER_CPU(int, sctp_memory_per_cpu_fw_alloc);
981748376bSEric Dumazet struct percpu_counter sctp_sockets_allocated;
994d93df0aSNeil Horman 
sctp_enter_memory_pressure(struct sock * sk)1005c52ba17SPavel Emelyanov static void sctp_enter_memory_pressure(struct sock *sk)
1014d93df0aSNeil Horman {
10276f33296SEric Dumazet 	WRITE_ONCE(sctp_memory_pressure, 1);
1034d93df0aSNeil Horman }
1044d93df0aSNeil Horman 
1054d93df0aSNeil Horman 
1061da177e4SLinus Torvalds /* Get the sndbuf space available at the time on the association.  */
sctp_wspace(struct sctp_association * asoc)1071da177e4SLinus Torvalds static inline int sctp_wspace(struct sctp_association *asoc)
1081da177e4SLinus Torvalds {
109cd305c74SXin Long 	struct sock *sk = asoc->base.sk;
1101da177e4SLinus Torvalds 
111cd305c74SXin Long 	return asoc->ep->sndbuf_policy ? sk->sk_sndbuf - asoc->sndbuf_used
112cd305c74SXin Long 				       : sk_stream_wspace(sk);
1131da177e4SLinus Torvalds }
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds /* Increment the used sndbuf space count of the corresponding association by
1161da177e4SLinus Torvalds  * the size of the outgoing data chunk.
1171da177e4SLinus Torvalds  * Also, set the skb destructor for sndbuf accounting later.
1181da177e4SLinus Torvalds  *
1191da177e4SLinus Torvalds  * Since it is always 1-1 between chunk and skb, and also a new skb is always
1201da177e4SLinus Torvalds  * allocated for chunk bundling in sctp_packet_transmit(), we can use the
1211da177e4SLinus Torvalds  * destructor in the data chunk skb for the purpose of the sndbuf space
1221da177e4SLinus Torvalds  * tracking.
1231da177e4SLinus Torvalds  */
sctp_set_owner_w(struct sctp_chunk * chunk)1241da177e4SLinus Torvalds static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds 	struct sctp_association *asoc = chunk->asoc;
1271da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds 	/* The sndbuf space is tracked per association.  */
1301da177e4SLinus Torvalds 	sctp_association_hold(asoc);
1311da177e4SLinus Torvalds 
1321b1e0bc9SXin Long 	if (chunk->shkey)
1331b1e0bc9SXin Long 		sctp_auth_shkey_hold(chunk->shkey);
1341b1e0bc9SXin Long 
1354eb701dfSNeil Horman 	skb_set_owner_w(chunk->skb, sk);
1364eb701dfSNeil Horman 
1371da177e4SLinus Torvalds 	chunk->skb->destructor = sctp_wfree;
1381da177e4SLinus Torvalds 	/* Save the chunk pointer in skb for sctp_wfree to use later.  */
139f869c912SDaniel Borkmann 	skb_shinfo(chunk->skb)->destructor_arg = chunk;
1401da177e4SLinus Torvalds 
14114afee4bSReshetova, Elena 	refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
142605c0ac1SXin Long 	asoc->sndbuf_used += chunk->skb->truesize + sizeof(struct sctp_chunk);
143dc9511ddSEric Dumazet 	sk_wmem_queued_add(sk, chunk->skb->truesize + sizeof(struct sctp_chunk));
1443ab224beSHideo Aoki 	sk_mem_charge(sk, chunk->skb->truesize);
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds 
sctp_clear_owner_w(struct sctp_chunk * chunk)147d04adf1bSXin Long static void sctp_clear_owner_w(struct sctp_chunk *chunk)
148d04adf1bSXin Long {
149d04adf1bSXin Long 	skb_orphan(chunk->skb);
150d04adf1bSXin Long }
151d04adf1bSXin Long 
1525c3e82feSQiujun Huang #define traverse_and_process()	\
1535c3e82feSQiujun Huang do {				\
1545c3e82feSQiujun Huang 	msg = chunk->msg;	\
1555c3e82feSQiujun Huang 	if (msg == prev_msg)	\
1565c3e82feSQiujun Huang 		continue;	\
1575c3e82feSQiujun Huang 	list_for_each_entry(c, &msg->chunks, frag_list) {	\
1585c3e82feSQiujun Huang 		if ((clear && asoc->base.sk == c->skb->sk) ||	\
1595c3e82feSQiujun Huang 		    (!clear && asoc->base.sk != c->skb->sk))	\
1605c3e82feSQiujun Huang 			cb(c);	\
1615c3e82feSQiujun Huang 	}			\
1625c3e82feSQiujun Huang 	prev_msg = msg;		\
1635c3e82feSQiujun Huang } while (0)
1645c3e82feSQiujun Huang 
sctp_for_each_tx_datachunk(struct sctp_association * asoc,bool clear,void (* cb)(struct sctp_chunk *))165d04adf1bSXin Long static void sctp_for_each_tx_datachunk(struct sctp_association *asoc,
1665c3e82feSQiujun Huang 				       bool clear,
167d04adf1bSXin Long 				       void (*cb)(struct sctp_chunk *))
168d04adf1bSXin Long 
169d04adf1bSXin Long {
1705c3e82feSQiujun Huang 	struct sctp_datamsg *msg, *prev_msg = NULL;
171d04adf1bSXin Long 	struct sctp_outq *q = &asoc->outqueue;
1725c3e82feSQiujun Huang 	struct sctp_chunk *chunk, *c;
173d04adf1bSXin Long 	struct sctp_transport *t;
174d04adf1bSXin Long 
175d04adf1bSXin Long 	list_for_each_entry(t, &asoc->peer.transport_addr_list, transports)
176d04adf1bSXin Long 		list_for_each_entry(chunk, &t->transmitted, transmitted_list)
1775c3e82feSQiujun Huang 			traverse_and_process();
178d04adf1bSXin Long 
179a8dd3979SXin Long 	list_for_each_entry(chunk, &q->retransmit, transmitted_list)
1805c3e82feSQiujun Huang 		traverse_and_process();
181d04adf1bSXin Long 
182a8dd3979SXin Long 	list_for_each_entry(chunk, &q->sacked, transmitted_list)
1835c3e82feSQiujun Huang 		traverse_and_process();
184d04adf1bSXin Long 
185a8dd3979SXin Long 	list_for_each_entry(chunk, &q->abandoned, transmitted_list)
1865c3e82feSQiujun Huang 		traverse_and_process();
187d04adf1bSXin Long 
188d04adf1bSXin Long 	list_for_each_entry(chunk, &q->out_chunk_list, list)
1895c3e82feSQiujun Huang 		traverse_and_process();
190d04adf1bSXin Long }
191d04adf1bSXin Long 
sctp_for_each_rx_skb(struct sctp_association * asoc,struct sock * sk,void (* cb)(struct sk_buff *,struct sock *))19213228238SXin Long static void sctp_for_each_rx_skb(struct sctp_association *asoc, struct sock *sk,
19313228238SXin Long 				 void (*cb)(struct sk_buff *, struct sock *))
19413228238SXin Long 
19513228238SXin Long {
19613228238SXin Long 	struct sk_buff *skb, *tmp;
19713228238SXin Long 
19813228238SXin Long 	sctp_skb_for_each(skb, &asoc->ulpq.lobby, tmp)
19913228238SXin Long 		cb(skb, sk);
20013228238SXin Long 
20113228238SXin Long 	sctp_skb_for_each(skb, &asoc->ulpq.reasm, tmp)
20213228238SXin Long 		cb(skb, sk);
20313228238SXin Long 
20413228238SXin Long 	sctp_skb_for_each(skb, &asoc->ulpq.reasm_uo, tmp)
20513228238SXin Long 		cb(skb, sk);
20613228238SXin Long }
20713228238SXin Long 
2081da177e4SLinus Torvalds /* Verify that this is a valid address. */
sctp_verify_addr(struct sock * sk,union sctp_addr * addr,int len)2091da177e4SLinus Torvalds static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
2101da177e4SLinus Torvalds 				   int len)
2111da177e4SLinus Torvalds {
2121da177e4SLinus Torvalds 	struct sctp_af *af;
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	/* Verify basic sockaddr. */
2151da177e4SLinus Torvalds 	af = sctp_sockaddr_af(sctp_sk(sk), addr, len);
2161da177e4SLinus Torvalds 	if (!af)
2171da177e4SLinus Torvalds 		return -EINVAL;
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	/* Is this a valid SCTP address?  */
2205636bef7SVlad Yasevich 	if (!af->addr_valid(addr, sctp_sk(sk), NULL))
2211da177e4SLinus Torvalds 		return -EINVAL;
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 	if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr)))
2241da177e4SLinus Torvalds 		return -EINVAL;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 	return 0;
2271da177e4SLinus Torvalds }
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds /* Look up the association by its id.  If this is not a UDP-style
2301da177e4SLinus Torvalds  * socket, the ID field is always ignored.
2311da177e4SLinus Torvalds  */
sctp_id2assoc(struct sock * sk,sctp_assoc_t id)2321da177e4SLinus Torvalds struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds 	struct sctp_association *asoc = NULL;
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 	/* If this is not a UDP-style socket, assoc id should be ignored. */
2371da177e4SLinus Torvalds 	if (!sctp_style(sk, UDP)) {
2381da177e4SLinus Torvalds 		/* Return NULL if the socket state is not ESTABLISHED. It
2391da177e4SLinus Torvalds 		 * could be a TCP-style listening socket or a socket which
2401da177e4SLinus Torvalds 		 * hasn't yet called connect() to establish an association.
2411da177e4SLinus Torvalds 		 */
242e5b13f34SMarcelo Ricardo Leitner 		if (!sctp_sstate(sk, ESTABLISHED) && !sctp_sstate(sk, CLOSING))
2431da177e4SLinus Torvalds 			return NULL;
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 		/* Get the first and the only association from the list. */
2461da177e4SLinus Torvalds 		if (!list_empty(&sctp_sk(sk)->ep->asocs))
2471da177e4SLinus Torvalds 			asoc = list_entry(sctp_sk(sk)->ep->asocs.next,
2481da177e4SLinus Torvalds 					  struct sctp_association, asocs);
2491da177e4SLinus Torvalds 		return asoc;
2501da177e4SLinus Torvalds 	}
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	/* Otherwise this is a UDP-style socket. */
25380df2704SXin Long 	if (id <= SCTP_ALL_ASSOC)
2541da177e4SLinus Torvalds 		return NULL;
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	spin_lock_bh(&sctp_assocs_id_lock);
2571da177e4SLinus Torvalds 	asoc = (struct sctp_association *)idr_find(&sctp_assocs_id, (int)id);
258b336decaSMarcelo Ricardo Leitner 	if (asoc && (asoc->base.sk != sk || asoc->base.dead))
259b336decaSMarcelo Ricardo Leitner 		asoc = NULL;
2601da177e4SLinus Torvalds 	spin_unlock_bh(&sctp_assocs_id_lock);
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	return asoc;
2631da177e4SLinus Torvalds }
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds /* Look up the transport from an address and an assoc id. If both address and
2661da177e4SLinus Torvalds  * id are specified, the associations matching the address and the id should be
2671da177e4SLinus Torvalds  * the same.
2681da177e4SLinus Torvalds  */
sctp_addr_id2transport(struct sock * sk,struct sockaddr_storage * addr,sctp_assoc_t id)2691da177e4SLinus Torvalds static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
2701da177e4SLinus Torvalds 					      struct sockaddr_storage *addr,
2711da177e4SLinus Torvalds 					      sctp_assoc_t id)
2721da177e4SLinus Torvalds {
2731da177e4SLinus Torvalds 	struct sctp_association *addr_asoc = NULL, *id_asoc = NULL;
2746f29a130SXin Long 	struct sctp_af *af = sctp_get_af_specific(addr->ss_family);
2751da177e4SLinus Torvalds 	union sctp_addr *laddr = (union sctp_addr *)addr;
2766f29a130SXin Long 	struct sctp_transport *transport;
2776f29a130SXin Long 
278912964eaSXin Long 	if (!af || sctp_verify_addr(sk, laddr, af->sockaddr_len))
2796f29a130SXin Long 		return NULL;
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep,
282cd4ff034SAl Viro 					       laddr,
2831da177e4SLinus Torvalds 					       &transport);
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	if (!addr_asoc)
2861da177e4SLinus Torvalds 		return NULL;
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	id_asoc = sctp_id2assoc(sk, id);
2891da177e4SLinus Torvalds 	if (id_asoc && (id_asoc != addr_asoc))
2901da177e4SLinus Torvalds 		return NULL;
2911da177e4SLinus Torvalds 
292299ee123SJason Gunthorpe 	sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk),
2931da177e4SLinus Torvalds 						(union sctp_addr *)addr);
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	return transport;
2961da177e4SLinus Torvalds }
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds /* API 3.1.2 bind() - UDP Style Syntax
2991da177e4SLinus Torvalds  * The syntax of bind() is,
3001da177e4SLinus Torvalds  *
3011da177e4SLinus Torvalds  *   ret = bind(int sd, struct sockaddr *addr, int addrlen);
3021da177e4SLinus Torvalds  *
3031da177e4SLinus Torvalds  *   sd      - the socket descriptor returned by socket().
3041da177e4SLinus Torvalds  *   addr    - the address structure (struct sockaddr_in or struct
3051da177e4SLinus Torvalds  *             sockaddr_in6 [RFC 2553]),
3061da177e4SLinus Torvalds  *   addr_len - the size of the address structure.
3071da177e4SLinus Torvalds  */
sctp_bind(struct sock * sk,struct sockaddr * addr,int addr_len)308dda91928SDaniel Borkmann static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len)
3091da177e4SLinus Torvalds {
3101da177e4SLinus Torvalds 	int retval = 0;
3111da177e4SLinus Torvalds 
312048ed4b6Swangweidong 	lock_sock(sk);
3131da177e4SLinus Torvalds 
314bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addr:%p, addr_len:%d\n", __func__, sk,
315bb33381dSDaniel Borkmann 		 addr, addr_len);
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds 	/* Disallow binding twice. */
3181da177e4SLinus Torvalds 	if (!sctp_sk(sk)->ep->base.bind_addr.port)
3193f7a87d2SFrank Filz 		retval = sctp_do_bind(sk, (union sctp_addr *)addr,
3201da177e4SLinus Torvalds 				      addr_len);
3211da177e4SLinus Torvalds 	else
3221da177e4SLinus Torvalds 		retval = -EINVAL;
3231da177e4SLinus Torvalds 
324048ed4b6Swangweidong 	release_sock(sk);
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 	return retval;
3271da177e4SLinus Torvalds }
3281da177e4SLinus Torvalds 
3298e2ef6abSMao Wenan static int sctp_get_port_local(struct sock *, union sctp_addr *);
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds /* Verify this is a valid sockaddr. */
sctp_sockaddr_af(struct sctp_sock * opt,union sctp_addr * addr,int len)3321da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
3331da177e4SLinus Torvalds 					union sctp_addr *addr, int len)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds 	struct sctp_af *af;
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	/* Check minimum size.  */
3381da177e4SLinus Torvalds 	if (len < sizeof (struct sockaddr))
3391da177e4SLinus Torvalds 		return NULL;
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	if (!opt->pf->af_supported(addr->sa.sa_family, opt))
3421da177e4SLinus Torvalds 		return NULL;
343c5006b8aSXin Long 
34481e98370SEric Dumazet 	if (addr->sa.sa_family == AF_INET6) {
34581e98370SEric Dumazet 		if (len < SIN6_LEN_RFC2133)
34681e98370SEric Dumazet 			return NULL;
347c5006b8aSXin Long 		/* V4 mapped address are really of AF_INET family */
34881e98370SEric Dumazet 		if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
349c5006b8aSXin Long 		    !opt->pf->af_supported(AF_INET, opt))
350c5006b8aSXin Long 			return NULL;
35181e98370SEric Dumazet 	}
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	/* If we get this far, af is valid. */
3541da177e4SLinus Torvalds 	af = sctp_get_af_specific(addr->sa.sa_family);
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds 	if (len < af->sockaddr_len)
3571da177e4SLinus Torvalds 		return NULL;
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	return af;
3601da177e4SLinus Torvalds }
3611da177e4SLinus Torvalds 
sctp_auto_asconf_init(struct sctp_sock * sp)36234e5b011SXin Long static void sctp_auto_asconf_init(struct sctp_sock *sp)
36334e5b011SXin Long {
36434e5b011SXin Long 	struct net *net = sock_net(&sp->inet.sk);
36534e5b011SXin Long 
36634e5b011SXin Long 	if (net->sctp.default_auto_asconf) {
3676feb37b3SChengfeng Ye 		spin_lock_bh(&net->sctp.addr_wq_lock);
36834e5b011SXin Long 		list_add_tail(&sp->auto_asconf_list, &net->sctp.auto_asconf_splist);
3696feb37b3SChengfeng Ye 		spin_unlock_bh(&net->sctp.addr_wq_lock);
37034e5b011SXin Long 		sp->do_auto_asconf = 1;
37134e5b011SXin Long 	}
37234e5b011SXin Long }
37334e5b011SXin Long 
3741da177e4SLinus Torvalds /* Bind a local address either to an endpoint or to an association.  */
sctp_do_bind(struct sock * sk,union sctp_addr * addr,int len)375dda91928SDaniel Borkmann static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
3761da177e4SLinus Torvalds {
3773594698aSEric W. Biederman 	struct net *net = sock_net(sk);
3781da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
3791da177e4SLinus Torvalds 	struct sctp_endpoint *ep = sp->ep;
3801da177e4SLinus Torvalds 	struct sctp_bind_addr *bp = &ep->base.bind_addr;
3811da177e4SLinus Torvalds 	struct sctp_af *af;
3821da177e4SLinus Torvalds 	unsigned short snum;
3831da177e4SLinus Torvalds 	int ret = 0;
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	/* Common sockaddr verification. */
3861da177e4SLinus Torvalds 	af = sctp_sockaddr_af(sp, addr, len);
3873f7a87d2SFrank Filz 	if (!af) {
388bb33381dSDaniel Borkmann 		pr_debug("%s: sk:%p, newaddr:%p, len:%d EINVAL\n",
389bb33381dSDaniel Borkmann 			 __func__, sk, addr, len);
3901da177e4SLinus Torvalds 		return -EINVAL;
3913f7a87d2SFrank Filz 	}
3923f7a87d2SFrank Filz 
3933f7a87d2SFrank Filz 	snum = ntohs(addr->v4.sin_port);
3943f7a87d2SFrank Filz 
395bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, new addr:%pISc, port:%d, new port:%d, len:%d\n",
396bb33381dSDaniel Borkmann 		 __func__, sk, &addr->sa, bp->port, snum, len);
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 	/* PF specific bind() address verification. */
3991da177e4SLinus Torvalds 	if (!sp->pf->bind_verify(sp, addr))
4001da177e4SLinus Torvalds 		return -EADDRNOTAVAIL;
4011da177e4SLinus Torvalds 
4028b358056SVlad Yasevich 	/* We must either be unbound, or bind to the same port.
4038b358056SVlad Yasevich 	 * It's OK to allow 0 ports if we are already bound.
4048b358056SVlad Yasevich 	 * We'll just inhert an already bound port in this case
4058b358056SVlad Yasevich 	 */
4068b358056SVlad Yasevich 	if (bp->port) {
4078b358056SVlad Yasevich 		if (!snum)
4088b358056SVlad Yasevich 			snum = bp->port;
4098b358056SVlad Yasevich 		else if (snum != bp->port) {
410bb33381dSDaniel Borkmann 			pr_debug("%s: new port %d doesn't match existing port "
411bb33381dSDaniel Borkmann 				 "%d\n", __func__, snum, bp->port);
4121da177e4SLinus Torvalds 			return -EINVAL;
4131da177e4SLinus Torvalds 		}
4148b358056SVlad Yasevich 	}
4151da177e4SLinus Torvalds 
41682f31ebfSMaciej Żenczykowski 	if (snum && inet_port_requires_bind_service(net, snum) &&
4173594698aSEric W. Biederman 	    !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
4181da177e4SLinus Torvalds 		return -EACCES;
4191da177e4SLinus Torvalds 
4204e54064eSVlad Yasevich 	/* See if the address matches any of the addresses we may have
4214e54064eSVlad Yasevich 	 * already bound before checking against other endpoints.
4224e54064eSVlad Yasevich 	 */
4234e54064eSVlad Yasevich 	if (sctp_bind_addr_match(bp, addr, sp))
4244e54064eSVlad Yasevich 		return -EINVAL;
4254e54064eSVlad Yasevich 
4261da177e4SLinus Torvalds 	/* Make sure we are allowed to bind here.
4271da177e4SLinus Torvalds 	 * The function sctp_get_port_local() does duplicate address
4281da177e4SLinus Torvalds 	 * detection.
4291da177e4SLinus Torvalds 	 */
4302772b495SVlad Yasevich 	addr->v4.sin_port = htons(snum);
431e0e4b8deSMao Wenan 	if (sctp_get_port_local(sk, addr))
4321da177e4SLinus Torvalds 		return -EADDRINUSE;
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 	/* Refresh ephemeral port.  */
43534e5b011SXin Long 	if (!bp->port) {
436c720c7e8SEric Dumazet 		bp->port = inet_sk(sk)->inet_num;
43734e5b011SXin Long 		sctp_auto_asconf_init(sp);
43834e5b011SXin Long 	}
4391da177e4SLinus Torvalds 
440559cf710SVlad Yasevich 	/* Add the address to the bind address list.
441559cf710SVlad Yasevich 	 * Use GFP_ATOMIC since BHs will be disabled.
442559cf710SVlad Yasevich 	 */
443133800d1SMarcelo Ricardo Leitner 	ret = sctp_add_bind_addr(bp, addr, af->sockaddr_len,
444133800d1SMarcelo Ricardo Leitner 				 SCTP_ADDR_SRC, GFP_ATOMIC);
4451da177e4SLinus Torvalds 
44629b99f54SMao Wenan 	if (ret) {
44729b99f54SMao Wenan 		sctp_put_port(sk);
44829b99f54SMao Wenan 		return ret;
44929b99f54SMao Wenan 	}
4501da177e4SLinus Torvalds 	/* Copy back into socket for getsockname() use. */
451c720c7e8SEric Dumazet 	inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
452299ee123SJason Gunthorpe 	sp->pf->to_sk_saddr(addr, sk);
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 	return ret;
4551da177e4SLinus Torvalds }
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds  /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks
4581da177e4SLinus Torvalds  *
4591da177e4SLinus Torvalds  * R1) One and only one ASCONF Chunk MAY be in transit and unacknowledged
4601da177e4SLinus Torvalds  * at any one time.  If a sender, after sending an ASCONF chunk, decides
4611da177e4SLinus Torvalds  * it needs to transfer another ASCONF Chunk, it MUST wait until the
4621da177e4SLinus Torvalds  * ASCONF-ACK Chunk returns from the previous ASCONF Chunk before sending a
4631da177e4SLinus Torvalds  * subsequent ASCONF. Note this restriction binds each side, so at any
4641da177e4SLinus Torvalds  * time two ASCONF may be in-transit on any given association (one sent
4651da177e4SLinus Torvalds  * from each endpoint).
4661da177e4SLinus Torvalds  */
sctp_send_asconf(struct sctp_association * asoc,struct sctp_chunk * chunk)4671da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc,
4681da177e4SLinus Torvalds 			    struct sctp_chunk *chunk)
4691da177e4SLinus Torvalds {
4701da177e4SLinus Torvalds 	int retval = 0;
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds 	/* If there is an outstanding ASCONF chunk, queue it for later
4731da177e4SLinus Torvalds 	 * transmission.
4741da177e4SLinus Torvalds 	 */
4751da177e4SLinus Torvalds 	if (asoc->addip_last_asconf) {
47679af02c2SDavid S. Miller 		list_add_tail(&chunk->list, &asoc->addip_chunk_list);
4771da177e4SLinus Torvalds 		goto out;
4781da177e4SLinus Torvalds 	}
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 	/* Hold the chunk until an ASCONF_ACK is received. */
4811da177e4SLinus Torvalds 	sctp_chunk_hold(chunk);
4824e7696d9SXin Long 	retval = sctp_primitive_ASCONF(asoc->base.net, asoc, chunk);
4831da177e4SLinus Torvalds 	if (retval)
4841da177e4SLinus Torvalds 		sctp_chunk_free(chunk);
4851da177e4SLinus Torvalds 	else
4861da177e4SLinus Torvalds 		asoc->addip_last_asconf = chunk;
4871da177e4SLinus Torvalds 
4881da177e4SLinus Torvalds out:
4891da177e4SLinus Torvalds 	return retval;
4901da177e4SLinus Torvalds }
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds /* Add a list of addresses as bind addresses to local endpoint or
4931da177e4SLinus Torvalds  * association.
4941da177e4SLinus Torvalds  *
4951da177e4SLinus Torvalds  * Basically run through each address specified in the addrs/addrcnt
4961da177e4SLinus Torvalds  * array/length pair, determine if it is IPv6 or IPv4 and call
4971da177e4SLinus Torvalds  * sctp_do_bind() on it.
4981da177e4SLinus Torvalds  *
4991da177e4SLinus Torvalds  * If any of them fails, then the operation will be reversed and the
5001da177e4SLinus Torvalds  * ones that were added will be removed.
5011da177e4SLinus Torvalds  *
5021da177e4SLinus Torvalds  * Only sctp_setsockopt_bindx() is supposed to call this function.
5031da177e4SLinus Torvalds  */
sctp_bindx_add(struct sock * sk,struct sockaddr * addrs,int addrcnt)50404675210Ssebastian@breakpoint.cc static int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt)
5051da177e4SLinus Torvalds {
5061da177e4SLinus Torvalds 	int cnt;
5071da177e4SLinus Torvalds 	int retval = 0;
5081da177e4SLinus Torvalds 	void *addr_buf;
5091da177e4SLinus Torvalds 	struct sockaddr *sa_addr;
5101da177e4SLinus Torvalds 	struct sctp_af *af;
5111da177e4SLinus Torvalds 
512bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", __func__, sk,
513bb33381dSDaniel Borkmann 		 addrs, addrcnt);
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds 	addr_buf = addrs;
5161da177e4SLinus Torvalds 	for (cnt = 0; cnt < addrcnt; cnt++) {
5171da177e4SLinus Torvalds 		/* The list may contain either IPv4 or IPv6 address;
5181da177e4SLinus Torvalds 		 * determine the address length for walking thru the list.
5191da177e4SLinus Torvalds 		 */
520ea110733SJoe Perches 		sa_addr = addr_buf;
5211da177e4SLinus Torvalds 		af = sctp_get_af_specific(sa_addr->sa_family);
5221da177e4SLinus Torvalds 		if (!af) {
5231da177e4SLinus Torvalds 			retval = -EINVAL;
5241da177e4SLinus Torvalds 			goto err_bindx_add;
5251da177e4SLinus Torvalds 		}
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds 		retval = sctp_do_bind(sk, (union sctp_addr *)sa_addr,
5281da177e4SLinus Torvalds 				      af->sockaddr_len);
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 		addr_buf += af->sockaddr_len;
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds err_bindx_add:
5331da177e4SLinus Torvalds 		if (retval < 0) {
5341da177e4SLinus Torvalds 			/* Failed. Cleanup the ones that have been added */
5351da177e4SLinus Torvalds 			if (cnt > 0)
5361da177e4SLinus Torvalds 				sctp_bindx_rem(sk, addrs, cnt);
5371da177e4SLinus Torvalds 			return retval;
5381da177e4SLinus Torvalds 		}
5391da177e4SLinus Torvalds 	}
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 	return retval;
5421da177e4SLinus Torvalds }
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds /* Send an ASCONF chunk with Add IP address parameters to all the peers of the
5451da177e4SLinus Torvalds  * associations that are part of the endpoint indicating that a list of local
5461da177e4SLinus Torvalds  * addresses are added to the endpoint.
5471da177e4SLinus Torvalds  *
5481da177e4SLinus Torvalds  * If any of the addresses is already in the bind address list of the
5491da177e4SLinus Torvalds  * association, we do not send the chunk for that association.  But it will not
5501da177e4SLinus Torvalds  * affect other associations.
5511da177e4SLinus Torvalds  *
5521da177e4SLinus Torvalds  * Only sctp_setsockopt_bindx() is supposed to call this function.
5531da177e4SLinus Torvalds  */
sctp_send_asconf_add_ip(struct sock * sk,struct sockaddr * addrs,int addrcnt)5541da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock		*sk,
5551da177e4SLinus Torvalds 				   struct sockaddr	*addrs,
5561da177e4SLinus Torvalds 				   int 			addrcnt)
5571da177e4SLinus Torvalds {
5581da177e4SLinus Torvalds 	struct sctp_sock		*sp;
5591da177e4SLinus Torvalds 	struct sctp_endpoint		*ep;
5601da177e4SLinus Torvalds 	struct sctp_association		*asoc;
5611da177e4SLinus Torvalds 	struct sctp_bind_addr		*bp;
5621da177e4SLinus Torvalds 	struct sctp_chunk		*chunk;
5631da177e4SLinus Torvalds 	struct sctp_sockaddr_entry	*laddr;
5641da177e4SLinus Torvalds 	union sctp_addr			*addr;
565dc022a98SSridhar Samudrala 	union sctp_addr			saveaddr;
5661da177e4SLinus Torvalds 	void				*addr_buf;
5671da177e4SLinus Torvalds 	struct sctp_af			*af;
5681da177e4SLinus Torvalds 	struct list_head		*p;
5691da177e4SLinus Torvalds 	int 				i;
5701da177e4SLinus Torvalds 	int 				retval = 0;
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds 	sp = sctp_sk(sk);
5731da177e4SLinus Torvalds 	ep = sp->ep;
5741da177e4SLinus Torvalds 
5754e27428fSXin Long 	if (!ep->asconf_enable)
5764e27428fSXin Long 		return retval;
5774e27428fSXin Long 
578bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
5790dc47877SHarvey Harrison 		 __func__, sk, addrs, addrcnt);
5801da177e4SLinus Torvalds 
5819dbc15f0SRobert P. J. Day 	list_for_each_entry(asoc, &ep->asocs, asocs) {
5821da177e4SLinus Torvalds 		if (!asoc->peer.asconf_capable)
5831da177e4SLinus Torvalds 			continue;
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 		if (asoc->peer.addip_disabled_mask & SCTP_PARAM_ADD_IP)
5861da177e4SLinus Torvalds 			continue;
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds 		if (!sctp_state(asoc, ESTABLISHED))
5891da177e4SLinus Torvalds 			continue;
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 		/* Check if any address in the packed array of addresses is
5921da177e4SLinus Torvalds 		 * in the bind address list of the association. If so,
5931da177e4SLinus Torvalds 		 * do not send the asconf chunk to its peer, but continue with
5941da177e4SLinus Torvalds 		 * other associations.
5951da177e4SLinus Torvalds 		 */
5961da177e4SLinus Torvalds 		addr_buf = addrs;
5971da177e4SLinus Torvalds 		for (i = 0; i < addrcnt; i++) {
598ea110733SJoe Perches 			addr = addr_buf;
5991da177e4SLinus Torvalds 			af = sctp_get_af_specific(addr->v4.sin_family);
6001da177e4SLinus Torvalds 			if (!af) {
6011da177e4SLinus Torvalds 				retval = -EINVAL;
6021da177e4SLinus Torvalds 				goto out;
6031da177e4SLinus Torvalds 			}
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds 			if (sctp_assoc_lookup_laddr(asoc, addr))
6061da177e4SLinus Torvalds 				break;
6071da177e4SLinus Torvalds 
6081da177e4SLinus Torvalds 			addr_buf += af->sockaddr_len;
6091da177e4SLinus Torvalds 		}
6101da177e4SLinus Torvalds 		if (i < addrcnt)
6111da177e4SLinus Torvalds 			continue;
6121da177e4SLinus Torvalds 
613559cf710SVlad Yasevich 		/* Use the first valid address in bind addr list of
614559cf710SVlad Yasevich 		 * association as Address Parameter of ASCONF CHUNK.
6151da177e4SLinus Torvalds 		 */
6161da177e4SLinus Torvalds 		bp = &asoc->base.bind_addr;
6171da177e4SLinus Torvalds 		p = bp->address_list.next;
6181da177e4SLinus Torvalds 		laddr = list_entry(p, struct sctp_sockaddr_entry, list);
6195ae955cfSAl Viro 		chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs,
6201da177e4SLinus Torvalds 						   addrcnt, SCTP_PARAM_ADD_IP);
6211da177e4SLinus Torvalds 		if (!chunk) {
6221da177e4SLinus Torvalds 			retval = -ENOMEM;
6231da177e4SLinus Torvalds 			goto out;
6241da177e4SLinus Torvalds 		}
6251da177e4SLinus Torvalds 
626dc022a98SSridhar Samudrala 		/* Add the new addresses to the bind address list with
627dc022a98SSridhar Samudrala 		 * use_as_src set to 0.
6281da177e4SLinus Torvalds 		 */
629dc022a98SSridhar Samudrala 		addr_buf = addrs;
630dc022a98SSridhar Samudrala 		for (i = 0; i < addrcnt; i++) {
631ea110733SJoe Perches 			addr = addr_buf;
632dc022a98SSridhar Samudrala 			af = sctp_get_af_specific(addr->v4.sin_family);
633dc022a98SSridhar Samudrala 			memcpy(&saveaddr, addr, af->sockaddr_len);
634f57d96b2SVlad Yasevich 			retval = sctp_add_bind_addr(bp, &saveaddr,
635133800d1SMarcelo Ricardo Leitner 						    sizeof(saveaddr),
636f57d96b2SVlad Yasevich 						    SCTP_ADDR_NEW, GFP_ATOMIC);
637dc022a98SSridhar Samudrala 			addr_buf += af->sockaddr_len;
638dc022a98SSridhar Samudrala 		}
6398a07eb0aSMichio Honda 		if (asoc->src_out_of_asoc_ok) {
6408a07eb0aSMichio Honda 			struct sctp_transport *trans;
6418a07eb0aSMichio Honda 
6428a07eb0aSMichio Honda 			list_for_each_entry(trans,
6438a07eb0aSMichio Honda 			    &asoc->peer.transport_addr_list, transports) {
6448a07eb0aSMichio Honda 				trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
6458a07eb0aSMichio Honda 				    2*asoc->pathmtu, 4380));
6468a07eb0aSMichio Honda 				trans->ssthresh = asoc->peer.i.a_rwnd;
6478a07eb0aSMichio Honda 				trans->rto = asoc->rto_initial;
648196d6759SMichele Baldessari 				sctp_max_rto(asoc, trans);
6498a07eb0aSMichio Honda 				trans->rtt = trans->srtt = trans->rttvar = 0;
6506e91b578SMarcelo Ricardo Leitner 				/* Clear the source and route cache */
6518a07eb0aSMichio Honda 				sctp_transport_route(trans, NULL,
6528a07eb0aSMichio Honda 						     sctp_sk(asoc->base.sk));
6538a07eb0aSMichio Honda 			}
6548a07eb0aSMichio Honda 		}
6558a07eb0aSMichio Honda 		retval = sctp_send_asconf(asoc, chunk);
6561da177e4SLinus Torvalds 	}
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds out:
6591da177e4SLinus Torvalds 	return retval;
6601da177e4SLinus Torvalds }
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds /* Remove a list of addresses from bind addresses list.  Do not remove the
6631da177e4SLinus Torvalds  * last address.
6641da177e4SLinus Torvalds  *
6651da177e4SLinus Torvalds  * Basically run through each address specified in the addrs/addrcnt
6661da177e4SLinus Torvalds  * array/length pair, determine if it is IPv6 or IPv4 and call
6671da177e4SLinus Torvalds  * sctp_del_bind() on it.
6681da177e4SLinus Torvalds  *
6691da177e4SLinus Torvalds  * If any of them fails, then the operation will be reversed and the
6701da177e4SLinus Torvalds  * ones that were removed will be added back.
6711da177e4SLinus Torvalds  *
6721da177e4SLinus Torvalds  * At least one address has to be left; if only one address is
6731da177e4SLinus Torvalds  * available, the operation will return -EBUSY.
6741da177e4SLinus Torvalds  *
6751da177e4SLinus Torvalds  * Only sctp_setsockopt_bindx() is supposed to call this function.
6761da177e4SLinus Torvalds  */
sctp_bindx_rem(struct sock * sk,struct sockaddr * addrs,int addrcnt)67704675210Ssebastian@breakpoint.cc static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
6781da177e4SLinus Torvalds {
6791da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
6801da177e4SLinus Torvalds 	struct sctp_endpoint *ep = sp->ep;
6811da177e4SLinus Torvalds 	int cnt;
6821da177e4SLinus Torvalds 	struct sctp_bind_addr *bp = &ep->base.bind_addr;
6831da177e4SLinus Torvalds 	int retval = 0;
6841da177e4SLinus Torvalds 	void *addr_buf;
685c9a08505SAl Viro 	union sctp_addr *sa_addr;
6861da177e4SLinus Torvalds 	struct sctp_af *af;
6871da177e4SLinus Torvalds 
688bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
689bb33381dSDaniel Borkmann 		 __func__, sk, addrs, addrcnt);
6901da177e4SLinus Torvalds 
6911da177e4SLinus Torvalds 	addr_buf = addrs;
6921da177e4SLinus Torvalds 	for (cnt = 0; cnt < addrcnt; cnt++) {
6931da177e4SLinus Torvalds 		/* If the bind address list is empty or if there is only one
6941da177e4SLinus Torvalds 		 * bind address, there is nothing more to be removed (we need
6951da177e4SLinus Torvalds 		 * at least one address here).
6961da177e4SLinus Torvalds 		 */
6971da177e4SLinus Torvalds 		if (list_empty(&bp->address_list) ||
6981da177e4SLinus Torvalds 		    (sctp_list_single_entry(&bp->address_list))) {
6991da177e4SLinus Torvalds 			retval = -EBUSY;
7001da177e4SLinus Torvalds 			goto err_bindx_rem;
7011da177e4SLinus Torvalds 		}
7021da177e4SLinus Torvalds 
703ea110733SJoe Perches 		sa_addr = addr_buf;
704c9a08505SAl Viro 		af = sctp_get_af_specific(sa_addr->sa.sa_family);
7051da177e4SLinus Torvalds 		if (!af) {
7061da177e4SLinus Torvalds 			retval = -EINVAL;
7071da177e4SLinus Torvalds 			goto err_bindx_rem;
7081da177e4SLinus Torvalds 		}
7090304ff8aSPaolo Galtieri 
7100304ff8aSPaolo Galtieri 		if (!af->addr_valid(sa_addr, sp, NULL)) {
7110304ff8aSPaolo Galtieri 			retval = -EADDRNOTAVAIL;
7120304ff8aSPaolo Galtieri 			goto err_bindx_rem;
7130304ff8aSPaolo Galtieri 		}
7140304ff8aSPaolo Galtieri 
715ee9cbacaSVlad Yasevich 		if (sa_addr->v4.sin_port &&
716ee9cbacaSVlad Yasevich 		    sa_addr->v4.sin_port != htons(bp->port)) {
7171da177e4SLinus Torvalds 			retval = -EINVAL;
7181da177e4SLinus Torvalds 			goto err_bindx_rem;
7191da177e4SLinus Torvalds 		}
7201da177e4SLinus Torvalds 
721ee9cbacaSVlad Yasevich 		if (!sa_addr->v4.sin_port)
722ee9cbacaSVlad Yasevich 			sa_addr->v4.sin_port = htons(bp->port);
723ee9cbacaSVlad Yasevich 
7241da177e4SLinus Torvalds 		/* FIXME - There is probably a need to check if sk->sk_saddr and
7251da177e4SLinus Torvalds 		 * sk->sk_rcv_addr are currently set to one of the addresses to
7261da177e4SLinus Torvalds 		 * be removed. This is something which needs to be looked into
7271da177e4SLinus Torvalds 		 * when we are fixing the outstanding issues with multi-homing
7281da177e4SLinus Torvalds 		 * socket routing and failover schemes. Refer to comments in
7291da177e4SLinus Torvalds 		 * sctp_do_bind(). -daisy
7301da177e4SLinus Torvalds 		 */
7310ed90fb0SVlad Yasevich 		retval = sctp_del_bind_addr(bp, sa_addr);
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 		addr_buf += af->sockaddr_len;
7341da177e4SLinus Torvalds err_bindx_rem:
7351da177e4SLinus Torvalds 		if (retval < 0) {
7361da177e4SLinus Torvalds 			/* Failed. Add the ones that has been removed back */
7371da177e4SLinus Torvalds 			if (cnt > 0)
7381da177e4SLinus Torvalds 				sctp_bindx_add(sk, addrs, cnt);
7391da177e4SLinus Torvalds 			return retval;
7401da177e4SLinus Torvalds 		}
7411da177e4SLinus Torvalds 	}
7421da177e4SLinus Torvalds 
7431da177e4SLinus Torvalds 	return retval;
7441da177e4SLinus Torvalds }
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds /* Send an ASCONF chunk with Delete IP address parameters to all the peers of
7471da177e4SLinus Torvalds  * the associations that are part of the endpoint indicating that a list of
7481da177e4SLinus Torvalds  * local addresses are removed from the endpoint.
7491da177e4SLinus Torvalds  *
7501da177e4SLinus Torvalds  * If any of the addresses is already in the bind address list of the
7511da177e4SLinus Torvalds  * association, we do not send the chunk for that association.  But it will not
7521da177e4SLinus Torvalds  * affect other associations.
7531da177e4SLinus Torvalds  *
7541da177e4SLinus Torvalds  * Only sctp_setsockopt_bindx() is supposed to call this function.
7551da177e4SLinus Torvalds  */
sctp_send_asconf_del_ip(struct sock * sk,struct sockaddr * addrs,int addrcnt)7561da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock		*sk,
7571da177e4SLinus Torvalds 				   struct sockaddr	*addrs,
7581da177e4SLinus Torvalds 				   int			addrcnt)
7591da177e4SLinus Torvalds {
7601da177e4SLinus Torvalds 	struct sctp_sock	*sp;
7611da177e4SLinus Torvalds 	struct sctp_endpoint	*ep;
7621da177e4SLinus Torvalds 	struct sctp_association	*asoc;
763dc022a98SSridhar Samudrala 	struct sctp_transport	*transport;
7641da177e4SLinus Torvalds 	struct sctp_bind_addr	*bp;
7651da177e4SLinus Torvalds 	struct sctp_chunk	*chunk;
7661da177e4SLinus Torvalds 	union sctp_addr		*laddr;
7671da177e4SLinus Torvalds 	void			*addr_buf;
7681da177e4SLinus Torvalds 	struct sctp_af		*af;
769dc022a98SSridhar Samudrala 	struct sctp_sockaddr_entry *saddr;
7701da177e4SLinus Torvalds 	int 			i;
7711da177e4SLinus Torvalds 	int 			retval = 0;
7728a07eb0aSMichio Honda 	int			stored = 0;
7731da177e4SLinus Torvalds 
7748a07eb0aSMichio Honda 	chunk = NULL;
7751da177e4SLinus Torvalds 	sp = sctp_sk(sk);
7761da177e4SLinus Torvalds 	ep = sp->ep;
7771da177e4SLinus Torvalds 
7784e27428fSXin Long 	if (!ep->asconf_enable)
7794e27428fSXin Long 		return retval;
7804e27428fSXin Long 
781bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
7820dc47877SHarvey Harrison 		 __func__, sk, addrs, addrcnt);
7831da177e4SLinus Torvalds 
7849dbc15f0SRobert P. J. Day 	list_for_each_entry(asoc, &ep->asocs, asocs) {
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 		if (!asoc->peer.asconf_capable)
7871da177e4SLinus Torvalds 			continue;
7881da177e4SLinus Torvalds 
7891da177e4SLinus Torvalds 		if (asoc->peer.addip_disabled_mask & SCTP_PARAM_DEL_IP)
7901da177e4SLinus Torvalds 			continue;
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds 		if (!sctp_state(asoc, ESTABLISHED))
7931da177e4SLinus Torvalds 			continue;
7941da177e4SLinus Torvalds 
7951da177e4SLinus Torvalds 		/* Check if any address in the packed array of addresses is
7961da177e4SLinus Torvalds 		 * not present in the bind address list of the association.
7971da177e4SLinus Torvalds 		 * If so, do not send the asconf chunk to its peer, but
7981da177e4SLinus Torvalds 		 * continue with other associations.
7991da177e4SLinus Torvalds 		 */
8001da177e4SLinus Torvalds 		addr_buf = addrs;
8011da177e4SLinus Torvalds 		for (i = 0; i < addrcnt; i++) {
802ea110733SJoe Perches 			laddr = addr_buf;
8031da177e4SLinus Torvalds 			af = sctp_get_af_specific(laddr->v4.sin_family);
8041da177e4SLinus Torvalds 			if (!af) {
8051da177e4SLinus Torvalds 				retval = -EINVAL;
8061da177e4SLinus Torvalds 				goto out;
8071da177e4SLinus Torvalds 			}
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds 			if (!sctp_assoc_lookup_laddr(asoc, laddr))
8101da177e4SLinus Torvalds 				break;
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds 			addr_buf += af->sockaddr_len;
8131da177e4SLinus Torvalds 		}
8141da177e4SLinus Torvalds 		if (i < addrcnt)
8151da177e4SLinus Torvalds 			continue;
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds 		/* Find one address in the association's bind address list
8181da177e4SLinus Torvalds 		 * that is not in the packed array of addresses. This is to
8191da177e4SLinus Torvalds 		 * make sure that we do not delete all the addresses in the
8201da177e4SLinus Torvalds 		 * association.
8211da177e4SLinus Torvalds 		 */
8221da177e4SLinus Torvalds 		bp = &asoc->base.bind_addr;
8231da177e4SLinus Torvalds 		laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
8241da177e4SLinus Torvalds 					       addrcnt, sp);
8258a07eb0aSMichio Honda 		if ((laddr == NULL) && (addrcnt == 1)) {
8268a07eb0aSMichio Honda 			if (asoc->asconf_addr_del_pending)
8271da177e4SLinus Torvalds 				continue;
8288a07eb0aSMichio Honda 			asoc->asconf_addr_del_pending =
8298a07eb0aSMichio Honda 			    kzalloc(sizeof(union sctp_addr), GFP_ATOMIC);
8306d65e5eeSMichio Honda 			if (asoc->asconf_addr_del_pending == NULL) {
8316d65e5eeSMichio Honda 				retval = -ENOMEM;
8326d65e5eeSMichio Honda 				goto out;
8336d65e5eeSMichio Honda 			}
8348a07eb0aSMichio Honda 			asoc->asconf_addr_del_pending->sa.sa_family =
8358a07eb0aSMichio Honda 				    addrs->sa_family;
8368a07eb0aSMichio Honda 			asoc->asconf_addr_del_pending->v4.sin_port =
8378a07eb0aSMichio Honda 				    htons(bp->port);
8388a07eb0aSMichio Honda 			if (addrs->sa_family == AF_INET) {
8398a07eb0aSMichio Honda 				struct sockaddr_in *sin;
8408a07eb0aSMichio Honda 
8418a07eb0aSMichio Honda 				sin = (struct sockaddr_in *)addrs;
8428a07eb0aSMichio Honda 				asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr;
8438a07eb0aSMichio Honda 			} else if (addrs->sa_family == AF_INET6) {
8448a07eb0aSMichio Honda 				struct sockaddr_in6 *sin6;
8458a07eb0aSMichio Honda 
8468a07eb0aSMichio Honda 				sin6 = (struct sockaddr_in6 *)addrs;
8474e3fd7a0SAlexey Dobriyan 				asoc->asconf_addr_del_pending->v6.sin6_addr = sin6->sin6_addr;
8488a07eb0aSMichio Honda 			}
849bb33381dSDaniel Borkmann 
850bb33381dSDaniel Borkmann 			pr_debug("%s: keep the last address asoc:%p %pISc at %p\n",
851bb33381dSDaniel Borkmann 				 __func__, asoc, &asoc->asconf_addr_del_pending->sa,
8528a07eb0aSMichio Honda 				 asoc->asconf_addr_del_pending);
853bb33381dSDaniel Borkmann 
8548a07eb0aSMichio Honda 			asoc->src_out_of_asoc_ok = 1;
8558a07eb0aSMichio Honda 			stored = 1;
8568a07eb0aSMichio Honda 			goto skip_mkasconf;
8578a07eb0aSMichio Honda 		}
8581da177e4SLinus Torvalds 
85988362ad8SDaniel Borkmann 		if (laddr == NULL)
86088362ad8SDaniel Borkmann 			return -EINVAL;
86188362ad8SDaniel Borkmann 
862559cf710SVlad Yasevich 		/* We do not need RCU protection throughout this loop
863559cf710SVlad Yasevich 		 * because this is done under a socket lock from the
864559cf710SVlad Yasevich 		 * setsockopt call.
865559cf710SVlad Yasevich 		 */
8661da177e4SLinus Torvalds 		chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt,
8671da177e4SLinus Torvalds 						   SCTP_PARAM_DEL_IP);
8681da177e4SLinus Torvalds 		if (!chunk) {
8691da177e4SLinus Torvalds 			retval = -ENOMEM;
8701da177e4SLinus Torvalds 			goto out;
8711da177e4SLinus Torvalds 		}
8721da177e4SLinus Torvalds 
8738a07eb0aSMichio Honda skip_mkasconf:
874dc022a98SSridhar Samudrala 		/* Reset use_as_src flag for the addresses in the bind address
875dc022a98SSridhar Samudrala 		 * list that are to be deleted.
8761da177e4SLinus Torvalds 		 */
877dc022a98SSridhar Samudrala 		addr_buf = addrs;
878dc022a98SSridhar Samudrala 		for (i = 0; i < addrcnt; i++) {
879ea110733SJoe Perches 			laddr = addr_buf;
880dc022a98SSridhar Samudrala 			af = sctp_get_af_specific(laddr->v4.sin_family);
881559cf710SVlad Yasevich 			list_for_each_entry(saddr, &bp->address_list, list) {
8825f242a13SAl Viro 				if (sctp_cmp_addr_exact(&saddr->a, laddr))
883f57d96b2SVlad Yasevich 					saddr->state = SCTP_ADDR_DEL;
884dc022a98SSridhar Samudrala 			}
885dc022a98SSridhar Samudrala 			addr_buf += af->sockaddr_len;
886dc022a98SSridhar Samudrala 		}
887dc022a98SSridhar Samudrala 
888dc022a98SSridhar Samudrala 		/* Update the route and saddr entries for all the transports
889dc022a98SSridhar Samudrala 		 * as some of the addresses in the bind address list are
890dc022a98SSridhar Samudrala 		 * about to be deleted and cannot be used as source addresses.
891dc022a98SSridhar Samudrala 		 */
8929dbc15f0SRobert P. J. Day 		list_for_each_entry(transport, &asoc->peer.transport_addr_list,
8939dbc15f0SRobert P. J. Day 					transports) {
894dc022a98SSridhar Samudrala 			sctp_transport_route(transport, NULL,
895dc022a98SSridhar Samudrala 					     sctp_sk(asoc->base.sk));
896dc022a98SSridhar Samudrala 		}
897dc022a98SSridhar Samudrala 
8988a07eb0aSMichio Honda 		if (stored)
8998a07eb0aSMichio Honda 			/* We don't need to transmit ASCONF */
9008a07eb0aSMichio Honda 			continue;
901dc022a98SSridhar Samudrala 		retval = sctp_send_asconf(asoc, chunk);
9021da177e4SLinus Torvalds 	}
9031da177e4SLinus Torvalds out:
9041da177e4SLinus Torvalds 	return retval;
9051da177e4SLinus Torvalds }
9061da177e4SLinus Torvalds 
9079f7d653bSMichio Honda /* set addr events to assocs in the endpoint.  ep and addr_wq must be locked */
sctp_asconf_mgmt(struct sctp_sock * sp,struct sctp_sockaddr_entry * addrw)9089f7d653bSMichio Honda int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw)
9099f7d653bSMichio Honda {
9109f7d653bSMichio Honda 	struct sock *sk = sctp_opt2sk(sp);
9119f7d653bSMichio Honda 	union sctp_addr *addr;
9129f7d653bSMichio Honda 	struct sctp_af *af;
9139f7d653bSMichio Honda 
9149f7d653bSMichio Honda 	/* It is safe to write port space in caller. */
9159f7d653bSMichio Honda 	addr = &addrw->a;
9169f7d653bSMichio Honda 	addr->v4.sin_port = htons(sp->ep->base.bind_addr.port);
9179f7d653bSMichio Honda 	af = sctp_get_af_specific(addr->sa.sa_family);
9189f7d653bSMichio Honda 	if (!af)
9199f7d653bSMichio Honda 		return -EINVAL;
9209f7d653bSMichio Honda 	if (sctp_verify_addr(sk, addr, af->sockaddr_len))
9219f7d653bSMichio Honda 		return -EINVAL;
9229f7d653bSMichio Honda 
9239f7d653bSMichio Honda 	if (addrw->state == SCTP_ADDR_NEW)
9249f7d653bSMichio Honda 		return sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1);
9259f7d653bSMichio Honda 	else
9269f7d653bSMichio Honda 		return sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1);
9279f7d653bSMichio Honda }
9289f7d653bSMichio Honda 
9291da177e4SLinus Torvalds /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt()
9301da177e4SLinus Torvalds  *
9311da177e4SLinus Torvalds  * API 8.1
9321da177e4SLinus Torvalds  * int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt,
9331da177e4SLinus Torvalds  *                int flags);
9341da177e4SLinus Torvalds  *
9351da177e4SLinus Torvalds  * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
9361da177e4SLinus Torvalds  * If the sd is an IPv6 socket, the addresses passed can either be IPv4
9371da177e4SLinus Torvalds  * or IPv6 addresses.
9381da177e4SLinus Torvalds  *
9391da177e4SLinus Torvalds  * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see
9401da177e4SLinus Torvalds  * Section 3.1.2 for this usage.
9411da177e4SLinus Torvalds  *
9421da177e4SLinus Torvalds  * addrs is a pointer to an array of one or more socket addresses. Each
9431da177e4SLinus Torvalds  * address is contained in its appropriate structure (i.e. struct
9441da177e4SLinus Torvalds  * sockaddr_in or struct sockaddr_in6) the family of the address type
94523c435f7SVille Nuorvala  * must be used to distinguish the address length (note that this
9461da177e4SLinus Torvalds  * representation is termed a "packed array" of addresses). The caller
9471da177e4SLinus Torvalds  * specifies the number of addresses in the array with addrcnt.
9481da177e4SLinus Torvalds  *
9491da177e4SLinus Torvalds  * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns
9501da177e4SLinus Torvalds  * -1, and sets errno to the appropriate error code.
9511da177e4SLinus Torvalds  *
9521da177e4SLinus Torvalds  * For SCTP, the port given in each socket address must be the same, or
9531da177e4SLinus Torvalds  * sctp_bindx() will fail, setting errno to EINVAL.
9541da177e4SLinus Torvalds  *
9551da177e4SLinus Torvalds  * The flags parameter is formed from the bitwise OR of zero or more of
9561da177e4SLinus Torvalds  * the following currently defined flags:
9571da177e4SLinus Torvalds  *
9581da177e4SLinus Torvalds  * SCTP_BINDX_ADD_ADDR
9591da177e4SLinus Torvalds  *
9601da177e4SLinus Torvalds  * SCTP_BINDX_REM_ADDR
9611da177e4SLinus Torvalds  *
9621da177e4SLinus Torvalds  * SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the
9631da177e4SLinus Torvalds  * association, and SCTP_BINDX_REM_ADDR directs SCTP to remove the given
9641da177e4SLinus Torvalds  * addresses from the association. The two flags are mutually exclusive;
9651da177e4SLinus Torvalds  * if both are given, sctp_bindx() will fail with EINVAL. A caller may
9661da177e4SLinus Torvalds  * not remove all addresses from an association; sctp_bindx() will
9671da177e4SLinus Torvalds  * reject such an attempt with EINVAL.
9681da177e4SLinus Torvalds  *
9691da177e4SLinus Torvalds  * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate
9701da177e4SLinus Torvalds  * additional addresses with an endpoint after calling bind().  Or use
9711da177e4SLinus Torvalds  * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening
9721da177e4SLinus Torvalds  * socket is associated with so that no new association accepted will be
9731da177e4SLinus Torvalds  * associated with those addresses. If the endpoint supports dynamic
9741da177e4SLinus Torvalds  * address a SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR may cause a
9751da177e4SLinus Torvalds  * endpoint to send the appropriate message to the peer to change the
9761da177e4SLinus Torvalds  * peers address lists.
9771da177e4SLinus Torvalds  *
9781da177e4SLinus Torvalds  * Adding and removing addresses from a connected association is
9791da177e4SLinus Torvalds  * optional functionality. Implementations that do not support this
9801da177e4SLinus Torvalds  * functionality should return EOPNOTSUPP.
9811da177e4SLinus Torvalds  *
9821da177e4SLinus Torvalds  * Basically do nothing but copying the addresses from user to kernel
9831da177e4SLinus Torvalds  * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk.
9843f7a87d2SFrank Filz  * This is used for tunneling the sctp_bindx() request through sctp_setsockopt()
9853f7a87d2SFrank Filz  * from userspace.
9861da177e4SLinus Torvalds  *
9871da177e4SLinus Torvalds  * On exit there is no need to do sockfd_put(), sys_setsockopt() does
9881da177e4SLinus Torvalds  * it.
9891da177e4SLinus Torvalds  *
9901da177e4SLinus Torvalds  * sk        The sk of the socket
99105bfd366SChristoph Hellwig  * addrs     The pointer to the addresses
9921da177e4SLinus Torvalds  * addrssize Size of the addrs buffer
9931da177e4SLinus Torvalds  * op        Operation to perform (add or remove, see the flags of
9941da177e4SLinus Torvalds  *           sctp_bindx)
9951da177e4SLinus Torvalds  *
9961da177e4SLinus Torvalds  * Returns 0 if ok, <0 errno code on error.
9971da177e4SLinus Torvalds  */
sctp_setsockopt_bindx(struct sock * sk,struct sockaddr * addrs,int addrs_size,int op)9988c7517f5SChristoph Hellwig static int sctp_setsockopt_bindx(struct sock *sk, struct sockaddr *addrs,
9998c7517f5SChristoph Hellwig 				 int addrs_size, int op)
10001da177e4SLinus Torvalds {
10011da177e4SLinus Torvalds 	int err;
10021da177e4SLinus Torvalds 	int addrcnt = 0;
10031da177e4SLinus Torvalds 	int walk_size = 0;
10041da177e4SLinus Torvalds 	struct sockaddr *sa_addr;
100505bfd366SChristoph Hellwig 	void *addr_buf = addrs;
10061da177e4SLinus Torvalds 	struct sctp_af *af;
10071da177e4SLinus Torvalds 
1008bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p addrs:%p addrs_size:%d opt:%d\n",
10098c7517f5SChristoph Hellwig 		 __func__, sk, addr_buf, addrs_size, op);
10101da177e4SLinus Torvalds 
10111da177e4SLinus Torvalds 	if (unlikely(addrs_size <= 0))
10121da177e4SLinus Torvalds 		return -EINVAL;
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 	/* Walk through the addrs buffer and count the number of addresses. */
10151da177e4SLinus Torvalds 	while (walk_size < addrs_size) {
101605bfd366SChristoph Hellwig 		if (walk_size + sizeof(sa_family_t) > addrs_size)
1017d7e0d19aSDan Rosenberg 			return -EINVAL;
1018d7e0d19aSDan Rosenberg 
1019ea110733SJoe Perches 		sa_addr = addr_buf;
10201da177e4SLinus Torvalds 		af = sctp_get_af_specific(sa_addr->sa_family);
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds 		/* If the address family is not supported or if this address
10231da177e4SLinus Torvalds 		 * causes the address buffer to overflow return EINVAL.
10241da177e4SLinus Torvalds 		 */
102505bfd366SChristoph Hellwig 		if (!af || (walk_size + af->sockaddr_len) > addrs_size)
10261da177e4SLinus Torvalds 			return -EINVAL;
10271da177e4SLinus Torvalds 		addrcnt++;
10281da177e4SLinus Torvalds 		addr_buf += af->sockaddr_len;
10291da177e4SLinus Torvalds 		walk_size += af->sockaddr_len;
10301da177e4SLinus Torvalds 	}
10311da177e4SLinus Torvalds 
10321da177e4SLinus Torvalds 	/* Do the work. */
10331da177e4SLinus Torvalds 	switch (op) {
10341da177e4SLinus Torvalds 	case SCTP_BINDX_ADD_ADDR:
10352277c7cdSRichard Haines 		/* Allow security module to validate bindx addresses. */
10362277c7cdSRichard Haines 		err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_BINDX_ADD,
103705bfd366SChristoph Hellwig 						 addrs, addrs_size);
10382277c7cdSRichard Haines 		if (err)
103905bfd366SChristoph Hellwig 			return err;
104005bfd366SChristoph Hellwig 		err = sctp_bindx_add(sk, addrs, addrcnt);
10411da177e4SLinus Torvalds 		if (err)
104205bfd366SChristoph Hellwig 			return err;
104305bfd366SChristoph Hellwig 		return sctp_send_asconf_add_ip(sk, addrs, addrcnt);
10441da177e4SLinus Torvalds 	case SCTP_BINDX_REM_ADDR:
104505bfd366SChristoph Hellwig 		err = sctp_bindx_rem(sk, addrs, addrcnt);
10461da177e4SLinus Torvalds 		if (err)
104705bfd366SChristoph Hellwig 			return err;
104805bfd366SChristoph Hellwig 		return sctp_send_asconf_del_ip(sk, addrs, addrcnt);
10491da177e4SLinus Torvalds 
10501da177e4SLinus Torvalds 	default:
105105bfd366SChristoph Hellwig 		return -EINVAL;
105205bfd366SChristoph Hellwig 	}
10533ff50b79SStephen Hemminger }
10541da177e4SLinus Torvalds 
sctp_bind_add(struct sock * sk,struct sockaddr * addrs,int addrlen)1055c0425a42SChristoph Hellwig static int sctp_bind_add(struct sock *sk, struct sockaddr *addrs,
1056c0425a42SChristoph Hellwig 		int addrlen)
1057c0425a42SChristoph Hellwig {
1058c0425a42SChristoph Hellwig 	int err;
1059c0425a42SChristoph Hellwig 
1060c0425a42SChristoph Hellwig 	lock_sock(sk);
10618c7517f5SChristoph Hellwig 	err = sctp_setsockopt_bindx(sk, addrs, addrlen, SCTP_BINDX_ADD_ADDR);
1062c0425a42SChristoph Hellwig 	release_sock(sk);
1063c0425a42SChristoph Hellwig 	return err;
1064c0425a42SChristoph Hellwig }
1065c0425a42SChristoph Hellwig 
sctp_connect_new_asoc(struct sctp_endpoint * ep,const union sctp_addr * daddr,const struct sctp_initmsg * init,struct sctp_transport ** tp)1066f26f9951SXin Long static int sctp_connect_new_asoc(struct sctp_endpoint *ep,
1067f26f9951SXin Long 				 const union sctp_addr *daddr,
1068f26f9951SXin Long 				 const struct sctp_initmsg *init,
1069f26f9951SXin Long 				 struct sctp_transport **tp)
1070f26f9951SXin Long {
1071f26f9951SXin Long 	struct sctp_association *asoc;
1072f26f9951SXin Long 	struct sock *sk = ep->base.sk;
1073f26f9951SXin Long 	struct net *net = sock_net(sk);
1074f26f9951SXin Long 	enum sctp_scope scope;
1075f26f9951SXin Long 	int err;
1076f26f9951SXin Long 
1077f26f9951SXin Long 	if (sctp_endpoint_is_peeled_off(ep, daddr))
1078f26f9951SXin Long 		return -EADDRNOTAVAIL;
1079f26f9951SXin Long 
1080f26f9951SXin Long 	if (!ep->base.bind_addr.port) {
1081f26f9951SXin Long 		if (sctp_autobind(sk))
1082f26f9951SXin Long 			return -EAGAIN;
1083f26f9951SXin Long 	} else {
108482f31ebfSMaciej Żenczykowski 		if (inet_port_requires_bind_service(net, ep->base.bind_addr.port) &&
1085f26f9951SXin Long 		    !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
1086f26f9951SXin Long 			return -EACCES;
1087f26f9951SXin Long 	}
1088f26f9951SXin Long 
1089f26f9951SXin Long 	scope = sctp_scope(daddr);
1090f26f9951SXin Long 	asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
1091f26f9951SXin Long 	if (!asoc)
1092f26f9951SXin Long 		return -ENOMEM;
1093f26f9951SXin Long 
1094f26f9951SXin Long 	err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL);
1095f26f9951SXin Long 	if (err < 0)
1096f26f9951SXin Long 		goto free;
1097f26f9951SXin Long 
1098f26f9951SXin Long 	*tp = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN);
1099f26f9951SXin Long 	if (!*tp) {
1100f26f9951SXin Long 		err = -ENOMEM;
1101f26f9951SXin Long 		goto free;
1102f26f9951SXin Long 	}
1103f26f9951SXin Long 
1104f26f9951SXin Long 	if (!init)
1105f26f9951SXin Long 		return 0;
1106f26f9951SXin Long 
1107f26f9951SXin Long 	if (init->sinit_num_ostreams) {
1108f26f9951SXin Long 		__u16 outcnt = init->sinit_num_ostreams;
1109f26f9951SXin Long 
1110f26f9951SXin Long 		asoc->c.sinit_num_ostreams = outcnt;
1111f26f9951SXin Long 		/* outcnt has been changed, need to re-init stream */
1112f26f9951SXin Long 		err = sctp_stream_init(&asoc->stream, outcnt, 0, GFP_KERNEL);
1113f26f9951SXin Long 		if (err)
1114f26f9951SXin Long 			goto free;
1115f26f9951SXin Long 	}
1116f26f9951SXin Long 
1117f26f9951SXin Long 	if (init->sinit_max_instreams)
1118f26f9951SXin Long 		asoc->c.sinit_max_instreams = init->sinit_max_instreams;
1119f26f9951SXin Long 
1120f26f9951SXin Long 	if (init->sinit_max_attempts)
1121f26f9951SXin Long 		asoc->max_init_attempts = init->sinit_max_attempts;
1122f26f9951SXin Long 
1123f26f9951SXin Long 	if (init->sinit_max_init_timeo)
1124f26f9951SXin Long 		asoc->max_init_timeo =
1125f26f9951SXin Long 			msecs_to_jiffies(init->sinit_max_init_timeo);
1126f26f9951SXin Long 
1127f26f9951SXin Long 	return 0;
1128f26f9951SXin Long free:
1129f26f9951SXin Long 	sctp_association_free(asoc);
1130f26f9951SXin Long 	return err;
1131f26f9951SXin Long }
1132f26f9951SXin Long 
sctp_connect_add_peer(struct sctp_association * asoc,union sctp_addr * daddr,int addr_len)1133a64e59c7SXin Long static int sctp_connect_add_peer(struct sctp_association *asoc,
1134a64e59c7SXin Long 				 union sctp_addr *daddr, int addr_len)
1135a64e59c7SXin Long {
1136a64e59c7SXin Long 	struct sctp_endpoint *ep = asoc->ep;
1137a64e59c7SXin Long 	struct sctp_association *old;
1138a64e59c7SXin Long 	struct sctp_transport *t;
1139a64e59c7SXin Long 	int err;
1140a64e59c7SXin Long 
1141a64e59c7SXin Long 	err = sctp_verify_addr(ep->base.sk, daddr, addr_len);
1142a64e59c7SXin Long 	if (err)
1143a64e59c7SXin Long 		return err;
1144a64e59c7SXin Long 
1145a64e59c7SXin Long 	old = sctp_endpoint_lookup_assoc(ep, daddr, &t);
1146a64e59c7SXin Long 	if (old && old != asoc)
1147a64e59c7SXin Long 		return old->state >= SCTP_STATE_ESTABLISHED ? -EISCONN
1148a64e59c7SXin Long 							    : -EALREADY;
1149a64e59c7SXin Long 
1150a64e59c7SXin Long 	if (sctp_endpoint_is_peeled_off(ep, daddr))
1151a64e59c7SXin Long 		return -EADDRNOTAVAIL;
1152a64e59c7SXin Long 
1153a64e59c7SXin Long 	t = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN);
1154a64e59c7SXin Long 	if (!t)
1155a64e59c7SXin Long 		return -ENOMEM;
1156a64e59c7SXin Long 
1157a64e59c7SXin Long 	return 0;
1158a64e59c7SXin Long }
1159a64e59c7SXin Long 
11603f7a87d2SFrank Filz /* __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, int addrs_size)
11613f7a87d2SFrank Filz  *
11623f7a87d2SFrank Filz  * Common routine for handling connect() and sctp_connectx().
11633f7a87d2SFrank Filz  * Connect will come in with just a single address.
11643f7a87d2SFrank Filz  */
__sctp_connect(struct sock * sk,struct sockaddr * kaddrs,int addrs_size,int flags,sctp_assoc_t * assoc_id)1165dd8378b3SXin Long static int __sctp_connect(struct sock *sk, struct sockaddr *kaddrs,
1166dd8378b3SXin Long 			  int addrs_size, int flags, sctp_assoc_t *assoc_id)
11673f7a87d2SFrank Filz {
1168dd8378b3SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
1169dd8378b3SXin Long 	struct sctp_endpoint *ep = sp->ep;
11703f7a87d2SFrank Filz 	struct sctp_transport *transport;
1171a64e59c7SXin Long 	struct sctp_association *asoc;
1172dd8378b3SXin Long 	void *addr_buf = kaddrs;
1173dd8378b3SXin Long 	union sctp_addr *daddr;
1174299ee123SJason Gunthorpe 	struct sctp_af *af;
1175dd8378b3SXin Long 	int walk_size, err;
1176dd8378b3SXin Long 	long timeo;
1177299ee123SJason Gunthorpe 
1178dd8378b3SXin Long 	if (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING) ||
1179dd8378b3SXin Long 	    (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)))
1180dd8378b3SXin Long 		return -EISCONN;
1181d7e0d19aSDan Rosenberg 
1182dd8378b3SXin Long 	daddr = addr_buf;
1183dd8378b3SXin Long 	af = sctp_get_af_specific(daddr->sa.sa_family);
1184dd8378b3SXin Long 	if (!af || af->sockaddr_len > addrs_size)
1185dd8378b3SXin Long 		return -EINVAL;
11863f7a87d2SFrank Filz 
1187dd8378b3SXin Long 	err = sctp_verify_addr(sk, daddr, af->sockaddr_len);
11883f7a87d2SFrank Filz 	if (err)
1189dd8378b3SXin Long 		return err;
11903f7a87d2SFrank Filz 
1191dd8378b3SXin Long 	asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
1192dd8378b3SXin Long 	if (asoc)
1193dd8378b3SXin Long 		return asoc->state >= SCTP_STATE_ESTABLISHED ? -EISCONN
1194dd8378b3SXin Long 							     : -EALREADY;
11953f7a87d2SFrank Filz 
1196f26f9951SXin Long 	err = sctp_connect_new_asoc(ep, daddr, NULL, &transport);
1197f26f9951SXin Long 	if (err)
1198f26f9951SXin Long 		return err;
1199f26f9951SXin Long 	asoc = transport->asoc;
1200409b95afSVlad Yasevich 
1201dd8378b3SXin Long 	addr_buf += af->sockaddr_len;
1202dd8378b3SXin Long 	walk_size = af->sockaddr_len;
1203dd8378b3SXin Long 	while (walk_size < addrs_size) {
1204dd8378b3SXin Long 		err = -EINVAL;
1205dd8378b3SXin Long 		if (walk_size + sizeof(sa_family_t) > addrs_size)
1206dd8378b3SXin Long 			goto out_free;
1207dd8378b3SXin Long 
1208dd8378b3SXin Long 		daddr = addr_buf;
1209dd8378b3SXin Long 		af = sctp_get_af_specific(daddr->sa.sa_family);
1210dd8378b3SXin Long 		if (!af || af->sockaddr_len + walk_size > addrs_size)
1211dd8378b3SXin Long 			goto out_free;
1212dd8378b3SXin Long 
1213dd8378b3SXin Long 		if (asoc->peer.port != ntohs(daddr->v4.sin_port))
1214dd8378b3SXin Long 			goto out_free;
1215dd8378b3SXin Long 
1216a64e59c7SXin Long 		err = sctp_connect_add_peer(asoc, daddr, af->sockaddr_len);
1217dd8378b3SXin Long 		if (err)
1218dd8378b3SXin Long 			goto out_free;
1219dd8378b3SXin Long 
12203f7a87d2SFrank Filz 		addr_buf  += af->sockaddr_len;
12213f7a87d2SFrank Filz 		walk_size += af->sockaddr_len;
12223f7a87d2SFrank Filz 	}
12233f7a87d2SFrank Filz 
1224c6ba68a2SVlad Yasevich 	/* In case the user of sctp_connectx() wants an association
1225c6ba68a2SVlad Yasevich 	 * id back, assign one now.
1226c6ba68a2SVlad Yasevich 	 */
1227c6ba68a2SVlad Yasevich 	if (assoc_id) {
1228c6ba68a2SVlad Yasevich 		err = sctp_assoc_set_id(asoc, GFP_KERNEL);
1229c6ba68a2SVlad Yasevich 		if (err < 0)
1230c6ba68a2SVlad Yasevich 			goto out_free;
1231c6ba68a2SVlad Yasevich 	}
1232c6ba68a2SVlad Yasevich 
1233f26f9951SXin Long 	err = sctp_primitive_ASSOCIATE(sock_net(sk), asoc, NULL);
1234dd8378b3SXin Long 	if (err < 0)
12353f7a87d2SFrank Filz 		goto out_free;
12363f7a87d2SFrank Filz 
12373f7a87d2SFrank Filz 	/* Initialize sk's dport and daddr for getpeername() */
1238c720c7e8SEric Dumazet 	inet_sk(sk)->inet_dport = htons(asoc->peer.port);
1239dd8378b3SXin Long 	sp->pf->to_sk_daddr(daddr, sk);
12408de8c873SSridhar Samudrala 	sk->sk_err = 0;
12413f7a87d2SFrank Filz 
12427233bc84SMarcelo Ricardo Leitner 	if (assoc_id)
124388a0a948SVlad Yasevich 		*assoc_id = asoc->assoc_id;
12442277c7cdSRichard Haines 
1245dd8378b3SXin Long 	timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
1246dd8378b3SXin Long 	return sctp_wait_for_connect(asoc, &timeo);
12473f7a87d2SFrank Filz 
12483f7a87d2SFrank Filz out_free:
1249bb33381dSDaniel Borkmann 	pr_debug("%s: took out_free path with asoc:%p kaddrs:%p err:%d\n",
1250bb33381dSDaniel Borkmann 		 __func__, asoc, kaddrs, err);
12513f7a87d2SFrank Filz 	sctp_association_free(asoc);
12523f7a87d2SFrank Filz 	return err;
12533f7a87d2SFrank Filz }
12543f7a87d2SFrank Filz 
12553f7a87d2SFrank Filz /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt()
12563f7a87d2SFrank Filz  *
12573f7a87d2SFrank Filz  * API 8.9
125888a0a948SVlad Yasevich  * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
125988a0a948SVlad Yasevich  * 			sctp_assoc_t *asoc);
12603f7a87d2SFrank Filz  *
12613f7a87d2SFrank Filz  * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
12623f7a87d2SFrank Filz  * If the sd is an IPv6 socket, the addresses passed can either be IPv4
12633f7a87d2SFrank Filz  * or IPv6 addresses.
12643f7a87d2SFrank Filz  *
12653f7a87d2SFrank Filz  * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see
12663f7a87d2SFrank Filz  * Section 3.1.2 for this usage.
12673f7a87d2SFrank Filz  *
12683f7a87d2SFrank Filz  * addrs is a pointer to an array of one or more socket addresses. Each
12693f7a87d2SFrank Filz  * address is contained in its appropriate structure (i.e. struct
12703f7a87d2SFrank Filz  * sockaddr_in or struct sockaddr_in6) the family of the address type
12713f7a87d2SFrank Filz  * must be used to distengish the address length (note that this
12723f7a87d2SFrank Filz  * representation is termed a "packed array" of addresses). The caller
12733f7a87d2SFrank Filz  * specifies the number of addresses in the array with addrcnt.
12743f7a87d2SFrank Filz  *
127588a0a948SVlad Yasevich  * On success, sctp_connectx() returns 0. It also sets the assoc_id to
127688a0a948SVlad Yasevich  * the association id of the new association.  On failure, sctp_connectx()
127788a0a948SVlad Yasevich  * returns -1, and sets errno to the appropriate error code.  The assoc_id
127888a0a948SVlad Yasevich  * is not touched by the kernel.
12793f7a87d2SFrank Filz  *
12803f7a87d2SFrank Filz  * For SCTP, the port given in each socket address must be the same, or
12813f7a87d2SFrank Filz  * sctp_connectx() will fail, setting errno to EINVAL.
12823f7a87d2SFrank Filz  *
12833f7a87d2SFrank Filz  * An application can use sctp_connectx to initiate an association with
12843f7a87d2SFrank Filz  * an endpoint that is multi-homed.  Much like sctp_bindx() this call
12853f7a87d2SFrank Filz  * allows a caller to specify multiple addresses at which a peer can be
12863f7a87d2SFrank Filz  * reached.  The way the SCTP stack uses the list of addresses to set up
128725985edcSLucas De Marchi  * the association is implementation dependent.  This function only
12883f7a87d2SFrank Filz  * specifies that the stack will try to make use of all the addresses in
12893f7a87d2SFrank Filz  * the list when needed.
12903f7a87d2SFrank Filz  *
12913f7a87d2SFrank Filz  * Note that the list of addresses passed in is only used for setting up
12923f7a87d2SFrank Filz  * the association.  It does not necessarily equal the set of addresses
12933f7a87d2SFrank Filz  * the peer uses for the resulting association.  If the caller wants to
12943f7a87d2SFrank Filz  * find out the set of peer addresses, it must use sctp_getpaddrs() to
12953f7a87d2SFrank Filz  * retrieve them after the association has been set up.
12963f7a87d2SFrank Filz  *
12973f7a87d2SFrank Filz  * Basically do nothing but copying the addresses from user to kernel
12983f7a87d2SFrank Filz  * land and invoking either sctp_connectx(). This is used for tunneling
12993f7a87d2SFrank Filz  * the sctp_connectx() request through sctp_setsockopt() from userspace.
13003f7a87d2SFrank Filz  *
13013f7a87d2SFrank Filz  * On exit there is no need to do sockfd_put(), sys_setsockopt() does
13023f7a87d2SFrank Filz  * it.
13033f7a87d2SFrank Filz  *
13043f7a87d2SFrank Filz  * sk        The sk of the socket
1305ce5b2f89SChristoph Hellwig  * addrs     The pointer to the addresses
13063f7a87d2SFrank Filz  * addrssize Size of the addrs buffer
13073f7a87d2SFrank Filz  *
130888a0a948SVlad Yasevich  * Returns >=0 if ok, <0 errno code on error.
13093f7a87d2SFrank Filz  */
__sctp_setsockopt_connectx(struct sock * sk,struct sockaddr * kaddrs,int addrs_size,sctp_assoc_t * assoc_id)1310ce5b2f89SChristoph Hellwig static int __sctp_setsockopt_connectx(struct sock *sk, struct sockaddr *kaddrs,
1311ce5b2f89SChristoph Hellwig 				      int addrs_size, sctp_assoc_t *assoc_id)
13123f7a87d2SFrank Filz {
1313644fbdeaSXin Long 	int err = 0, flags = 0;
13143f7a87d2SFrank Filz 
1315bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
1316ce5b2f89SChristoph Hellwig 		 __func__, sk, kaddrs, addrs_size);
13173f7a87d2SFrank Filz 
1318f40f1177SXin Long 	/* make sure the 1st addr's sa_family is accessible later */
1319f40f1177SXin Long 	if (unlikely(addrs_size < sizeof(sa_family_t)))
13203f7a87d2SFrank Filz 		return -EINVAL;
13213f7a87d2SFrank Filz 
13222277c7cdSRichard Haines 	/* Allow security module to validate connectx addresses. */
13232277c7cdSRichard Haines 	err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX,
13242277c7cdSRichard Haines 					 (struct sockaddr *)kaddrs,
13252277c7cdSRichard Haines 					  addrs_size);
13262277c7cdSRichard Haines 	if (err)
1327ce5b2f89SChristoph Hellwig 		return err;
13282277c7cdSRichard Haines 
1329644fbdeaSXin Long 	/* in-kernel sockets don't generally have a file allocated to them
1330644fbdeaSXin Long 	 * if all they do is call sock_create_kern().
1331644fbdeaSXin Long 	 */
1332644fbdeaSXin Long 	if (sk->sk_socket->file)
1333644fbdeaSXin Long 		flags = sk->sk_socket->file->f_flags;
1334644fbdeaSXin Long 
1335ce5b2f89SChristoph Hellwig 	return __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
13363f7a87d2SFrank Filz }
13373f7a87d2SFrank Filz 
133888a0a948SVlad Yasevich /*
133988a0a948SVlad Yasevich  * This is an older interface.  It's kept for backward compatibility
134088a0a948SVlad Yasevich  * to the option that doesn't provide association id.
134188a0a948SVlad Yasevich  */
sctp_setsockopt_connectx_old(struct sock * sk,struct sockaddr * kaddrs,int addrs_size)1342dda91928SDaniel Borkmann static int sctp_setsockopt_connectx_old(struct sock *sk,
1343ce5b2f89SChristoph Hellwig 					struct sockaddr *kaddrs,
134488a0a948SVlad Yasevich 					int addrs_size)
134588a0a948SVlad Yasevich {
1346ce5b2f89SChristoph Hellwig 	return __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, NULL);
134788a0a948SVlad Yasevich }
134888a0a948SVlad Yasevich 
134988a0a948SVlad Yasevich /*
135088a0a948SVlad Yasevich  * New interface for the API.  The since the API is done with a socket
135188a0a948SVlad Yasevich  * option, to make it simple we feed back the association id is as a return
135288a0a948SVlad Yasevich  * indication to the call.  Error is always negative and association id is
135388a0a948SVlad Yasevich  * always positive.
135488a0a948SVlad Yasevich  */
sctp_setsockopt_connectx(struct sock * sk,struct sockaddr * kaddrs,int addrs_size)1355dda91928SDaniel Borkmann static int sctp_setsockopt_connectx(struct sock *sk,
1356ce5b2f89SChristoph Hellwig 				    struct sockaddr *kaddrs,
135788a0a948SVlad Yasevich 				    int addrs_size)
135888a0a948SVlad Yasevich {
135988a0a948SVlad Yasevich 	sctp_assoc_t assoc_id = 0;
136088a0a948SVlad Yasevich 	int err = 0;
136188a0a948SVlad Yasevich 
1362ce5b2f89SChristoph Hellwig 	err = __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, &assoc_id);
136388a0a948SVlad Yasevich 
136488a0a948SVlad Yasevich 	if (err)
136588a0a948SVlad Yasevich 		return err;
136688a0a948SVlad Yasevich 	else
136788a0a948SVlad Yasevich 		return assoc_id;
136888a0a948SVlad Yasevich }
136988a0a948SVlad Yasevich 
1370c6ba68a2SVlad Yasevich /*
1371f9c67811SVlad Yasevich  * New (hopefully final) interface for the API.
1372f9c67811SVlad Yasevich  * We use the sctp_getaddrs_old structure so that use-space library
1373ffd59393SDaniel Borkmann  * can avoid any unnecessary allocations. The only different part
1374f9c67811SVlad Yasevich  * is that we store the actual length of the address buffer into the
1375f9c67811SVlad Yasevich  * addrs_num structure member. That way we can re-use the existing
1376f9c67811SVlad Yasevich  * code.
1377c6ba68a2SVlad Yasevich  */
1378ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT
1379ffd59393SDaniel Borkmann struct compat_sctp_getaddrs_old {
1380ffd59393SDaniel Borkmann 	sctp_assoc_t	assoc_id;
1381ffd59393SDaniel Borkmann 	s32		addr_num;
1382ffd59393SDaniel Borkmann 	compat_uptr_t	addrs;		/* struct sockaddr * */
1383ffd59393SDaniel Borkmann };
1384ffd59393SDaniel Borkmann #endif
1385ffd59393SDaniel Borkmann 
sctp_getsockopt_connectx3(struct sock * sk,int len,char __user * optval,int __user * optlen)1386dda91928SDaniel Borkmann static int sctp_getsockopt_connectx3(struct sock *sk, int len,
1387c6ba68a2SVlad Yasevich 				     char __user *optval,
1388c6ba68a2SVlad Yasevich 				     int __user *optlen)
1389c6ba68a2SVlad Yasevich {
1390f9c67811SVlad Yasevich 	struct sctp_getaddrs_old param;
1391c6ba68a2SVlad Yasevich 	sctp_assoc_t assoc_id = 0;
1392ce5b2f89SChristoph Hellwig 	struct sockaddr *kaddrs;
1393c6ba68a2SVlad Yasevich 	int err = 0;
1394c6ba68a2SVlad Yasevich 
1395ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT
139696c0e0a9SAndy Lutomirski 	if (in_compat_syscall()) {
1397ffd59393SDaniel Borkmann 		struct compat_sctp_getaddrs_old param32;
1398c6ba68a2SVlad Yasevich 
1399ffd59393SDaniel Borkmann 		if (len < sizeof(param32))
1400ffd59393SDaniel Borkmann 			return -EINVAL;
1401ffd59393SDaniel Borkmann 		if (copy_from_user(&param32, optval, sizeof(param32)))
1402f9c67811SVlad Yasevich 			return -EFAULT;
1403f9c67811SVlad Yasevich 
1404ffd59393SDaniel Borkmann 		param.assoc_id = param32.assoc_id;
1405ffd59393SDaniel Borkmann 		param.addr_num = param32.addr_num;
1406ffd59393SDaniel Borkmann 		param.addrs = compat_ptr(param32.addrs);
1407ffd59393SDaniel Borkmann 	} else
1408ffd59393SDaniel Borkmann #endif
1409ffd59393SDaniel Borkmann 	{
1410ffd59393SDaniel Borkmann 		if (len < sizeof(param))
1411ffd59393SDaniel Borkmann 			return -EINVAL;
1412ffd59393SDaniel Borkmann 		if (copy_from_user(&param, optval, sizeof(param)))
1413ffd59393SDaniel Borkmann 			return -EFAULT;
1414ffd59393SDaniel Borkmann 	}
1415c6ba68a2SVlad Yasevich 
1416ce5b2f89SChristoph Hellwig 	kaddrs = memdup_user(param.addrs, param.addr_num);
1417ce5b2f89SChristoph Hellwig 	if (IS_ERR(kaddrs))
1418ce5b2f89SChristoph Hellwig 		return PTR_ERR(kaddrs);
1419ce5b2f89SChristoph Hellwig 
1420ce5b2f89SChristoph Hellwig 	err = __sctp_setsockopt_connectx(sk, kaddrs, param.addr_num, &assoc_id);
1421ce5b2f89SChristoph Hellwig 	kfree(kaddrs);
1422c6ba68a2SVlad Yasevich 	if (err == 0 || err == -EINPROGRESS) {
1423c6ba68a2SVlad Yasevich 		if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
1424c6ba68a2SVlad Yasevich 			return -EFAULT;
1425c6ba68a2SVlad Yasevich 		if (put_user(sizeof(assoc_id), optlen))
1426c6ba68a2SVlad Yasevich 			return -EFAULT;
1427c6ba68a2SVlad Yasevich 	}
1428c6ba68a2SVlad Yasevich 
1429c6ba68a2SVlad Yasevich 	return err;
1430c6ba68a2SVlad Yasevich }
1431c6ba68a2SVlad Yasevich 
14321da177e4SLinus Torvalds /* API 3.1.4 close() - UDP Style Syntax
14331da177e4SLinus Torvalds  * Applications use close() to perform graceful shutdown (as described in
14341da177e4SLinus Torvalds  * Section 10.1 of [SCTP]) on ALL the associations currently represented
14351da177e4SLinus Torvalds  * by a UDP-style socket.
14361da177e4SLinus Torvalds  *
14371da177e4SLinus Torvalds  * The syntax is
14381da177e4SLinus Torvalds  *
14391da177e4SLinus Torvalds  *   ret = close(int sd);
14401da177e4SLinus Torvalds  *
14411da177e4SLinus Torvalds  *   sd      - the socket descriptor of the associations to be closed.
14421da177e4SLinus Torvalds  *
14431da177e4SLinus Torvalds  * To gracefully shutdown a specific association represented by the
14441da177e4SLinus Torvalds  * UDP-style socket, an application should use the sendmsg() call,
14451da177e4SLinus Torvalds  * passing no user data, but including the appropriate flag in the
14461da177e4SLinus Torvalds  * ancillary data (see Section xxxx).
14471da177e4SLinus Torvalds  *
14481da177e4SLinus Torvalds  * If sd in the close() call is a branched-off socket representing only
14491da177e4SLinus Torvalds  * one association, the shutdown is performed on that association only.
14501da177e4SLinus Torvalds  *
14511da177e4SLinus Torvalds  * 4.1.6 close() - TCP Style Syntax
14521da177e4SLinus Torvalds  *
14531da177e4SLinus Torvalds  * Applications use close() to gracefully close down an association.
14541da177e4SLinus Torvalds  *
14551da177e4SLinus Torvalds  * The syntax is:
14561da177e4SLinus Torvalds  *
14571da177e4SLinus Torvalds  *    int close(int sd);
14581da177e4SLinus Torvalds  *
14591da177e4SLinus Torvalds  *      sd      - the socket descriptor of the association to be closed.
14601da177e4SLinus Torvalds  *
14611da177e4SLinus Torvalds  * After an application calls close() on a socket descriptor, no further
14621da177e4SLinus Torvalds  * socket operations will succeed on that descriptor.
14631da177e4SLinus Torvalds  *
14641da177e4SLinus Torvalds  * API 7.1.4 SO_LINGER
14651da177e4SLinus Torvalds  *
14661da177e4SLinus Torvalds  * An application using the TCP-style socket can use this option to
14671da177e4SLinus Torvalds  * perform the SCTP ABORT primitive.  The linger option structure is:
14681da177e4SLinus Torvalds  *
14691da177e4SLinus Torvalds  *  struct  linger {
14701da177e4SLinus Torvalds  *     int     l_onoff;                // option on/off
14711da177e4SLinus Torvalds  *     int     l_linger;               // linger time
14721da177e4SLinus Torvalds  * };
14731da177e4SLinus Torvalds  *
14741da177e4SLinus Torvalds  * To enable the option, set l_onoff to 1.  If the l_linger value is set
14751da177e4SLinus Torvalds  * to 0, calling close() is the same as the ABORT primitive.  If the
14761da177e4SLinus Torvalds  * value is set to a negative value, the setsockopt() call will return
14771da177e4SLinus Torvalds  * an error.  If the value is set to a positive value linger_time, the
14781da177e4SLinus Torvalds  * close() can be blocked for at most linger_time ms.  If the graceful
14791da177e4SLinus Torvalds  * shutdown phase does not finish during this period, close() will
14801da177e4SLinus Torvalds  * return but the graceful shutdown phase continues in the system.
14811da177e4SLinus Torvalds  */
sctp_close(struct sock * sk,long timeout)1482dda91928SDaniel Borkmann static void sctp_close(struct sock *sk, long timeout)
14831da177e4SLinus Torvalds {
148455e26eb9SEric W. Biederman 	struct net *net = sock_net(sk);
14851da177e4SLinus Torvalds 	struct sctp_endpoint *ep;
14861da177e4SLinus Torvalds 	struct sctp_association *asoc;
14871da177e4SLinus Torvalds 	struct list_head *pos, *temp;
1488cd4fcc70SThomas Graf 	unsigned int data_was_unread;
14891da177e4SLinus Torvalds 
1490bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout);
14911da177e4SLinus Torvalds 
14926dfe4b97SXin Long 	lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
14931da177e4SLinus Torvalds 	sk->sk_shutdown = SHUTDOWN_MASK;
1494cbabf463SYafang Shao 	inet_sk_set_state(sk, SCTP_SS_CLOSING);
14951da177e4SLinus Torvalds 
14961da177e4SLinus Torvalds 	ep = sctp_sk(sk)->ep;
14971da177e4SLinus Torvalds 
1498cd4fcc70SThomas Graf 	/* Clean up any skbs sitting on the receive queue.  */
1499cd4fcc70SThomas Graf 	data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue);
1500cd4fcc70SThomas Graf 	data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);
1501cd4fcc70SThomas Graf 
150261c9fed4SVladislav Yasevich 	/* Walk all associations on an endpoint.  */
15031da177e4SLinus Torvalds 	list_for_each_safe(pos, temp, &ep->asocs) {
15041da177e4SLinus Torvalds 		asoc = list_entry(pos, struct sctp_association, asocs);
15051da177e4SLinus Torvalds 
15061da177e4SLinus Torvalds 		if (sctp_style(sk, TCP)) {
15071da177e4SLinus Torvalds 			/* A closed association can still be in the list if
15081da177e4SLinus Torvalds 			 * it belongs to a TCP-style listening socket that is
15091da177e4SLinus Torvalds 			 * not yet accepted. If so, free it. If not, send an
15101da177e4SLinus Torvalds 			 * ABORT or SHUTDOWN based on the linger options.
15111da177e4SLinus Torvalds 			 */
15121da177e4SLinus Torvalds 			if (sctp_state(asoc, CLOSED)) {
15131da177e4SLinus Torvalds 				sctp_association_free(asoc);
1514b89498a1SVladislav Yasevich 				continue;
1515b89498a1SVladislav Yasevich 			}
1516b89498a1SVladislav Yasevich 		}
15171da177e4SLinus Torvalds 
1518cd4fcc70SThomas Graf 		if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) ||
1519cd4fcc70SThomas Graf 		    !skb_queue_empty(&asoc->ulpq.reasm) ||
152013228238SXin Long 		    !skb_queue_empty(&asoc->ulpq.reasm_uo) ||
1521cd4fcc70SThomas Graf 		    (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) {
1522b9ac8672SSridhar Samudrala 			struct sctp_chunk *chunk;
1523b9ac8672SSridhar Samudrala 
1524b9ac8672SSridhar Samudrala 			chunk = sctp_make_abort_user(asoc, NULL, 0);
152555e26eb9SEric W. Biederman 			sctp_primitive_ABORT(net, asoc, chunk);
1526b9ac8672SSridhar Samudrala 		} else
152755e26eb9SEric W. Biederman 			sctp_primitive_SHUTDOWN(net, asoc, NULL);
15281da177e4SLinus Torvalds 	}
15291da177e4SLinus Torvalds 
15301da177e4SLinus Torvalds 	/* On a TCP-style socket, block for at most linger_time if set. */
15311da177e4SLinus Torvalds 	if (sctp_style(sk, TCP) && timeout)
15321da177e4SLinus Torvalds 		sctp_wait_for_close(sk, timeout);
15331da177e4SLinus Torvalds 
15341da177e4SLinus Torvalds 	/* This will run the backlog queue.  */
1535048ed4b6Swangweidong 	release_sock(sk);
15361da177e4SLinus Torvalds 
15371da177e4SLinus Torvalds 	/* Supposedly, no process has access to the socket, but
15381da177e4SLinus Torvalds 	 * the net layers still may.
153901bfe5e8SXin Long 	 * Also, sctp_destroy_sock() needs to be called with addr_wq_lock
154001bfe5e8SXin Long 	 * held and that should be grabbed before socket lock.
15411da177e4SLinus Torvalds 	 */
154201bfe5e8SXin Long 	spin_lock_bh(&net->sctp.addr_wq_lock);
154301bfe5e8SXin Long 	bh_lock_sock_nested(sk);
15441da177e4SLinus Torvalds 
15451da177e4SLinus Torvalds 	/* Hold the sock, since sk_common_release() will put sock_put()
15461da177e4SLinus Torvalds 	 * and we have just a little more cleanup.
15471da177e4SLinus Torvalds 	 */
15481da177e4SLinus Torvalds 	sock_hold(sk);
15491da177e4SLinus Torvalds 	sk_common_release(sk);
15501da177e4SLinus Torvalds 
15515bc1d1b4Swangweidong 	bh_unlock_sock(sk);
155201bfe5e8SXin Long 	spin_unlock_bh(&net->sctp.addr_wq_lock);
15531da177e4SLinus Torvalds 
15541da177e4SLinus Torvalds 	sock_put(sk);
15551da177e4SLinus Torvalds 
15561da177e4SLinus Torvalds 	SCTP_DBG_OBJCNT_DEC(sock);
15571da177e4SLinus Torvalds }
15581da177e4SLinus Torvalds 
15591da177e4SLinus Torvalds /* Handle EPIPE error. */
sctp_error(struct sock * sk,int flags,int err)15601da177e4SLinus Torvalds static int sctp_error(struct sock *sk, int flags, int err)
15611da177e4SLinus Torvalds {
15621da177e4SLinus Torvalds 	if (err == -EPIPE)
15631da177e4SLinus Torvalds 		err = sock_error(sk) ? : -EPIPE;
15641da177e4SLinus Torvalds 	if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
15651da177e4SLinus Torvalds 		send_sig(SIGPIPE, current, 0);
15661da177e4SLinus Torvalds 	return err;
15671da177e4SLinus Torvalds }
15681da177e4SLinus Torvalds 
15691da177e4SLinus Torvalds /* API 3.1.3 sendmsg() - UDP Style Syntax
15701da177e4SLinus Torvalds  *
15711da177e4SLinus Torvalds  * An application uses sendmsg() and recvmsg() calls to transmit data to
15721da177e4SLinus Torvalds  * and receive data from its peer.
15731da177e4SLinus Torvalds  *
15741da177e4SLinus Torvalds  *  ssize_t sendmsg(int socket, const struct msghdr *message,
15751da177e4SLinus Torvalds  *                  int flags);
15761da177e4SLinus Torvalds  *
15771da177e4SLinus Torvalds  *  socket  - the socket descriptor of the endpoint.
15781da177e4SLinus Torvalds  *  message - pointer to the msghdr structure which contains a single
15791da177e4SLinus Torvalds  *            user message and possibly some ancillary data.
15801da177e4SLinus Torvalds  *
15811da177e4SLinus Torvalds  *            See Section 5 for complete description of the data
15821da177e4SLinus Torvalds  *            structures.
15831da177e4SLinus Torvalds  *
15841da177e4SLinus Torvalds  *  flags   - flags sent or received with the user message, see Section
15851da177e4SLinus Torvalds  *            5 for complete description of the flags.
15861da177e4SLinus Torvalds  *
15871da177e4SLinus Torvalds  * Note:  This function could use a rewrite especially when explicit
15881da177e4SLinus Torvalds  * connect support comes in.
15891da177e4SLinus Torvalds  */
15901da177e4SLinus Torvalds /* BUG:  We do not implement the equivalent of sk_stream_wait_memory(). */
15911da177e4SLinus Torvalds 
1592a05437acSXin Long static int sctp_msghdr_parse(const struct msghdr *msg,
1593a05437acSXin Long 			     struct sctp_cmsgs *cmsgs);
15941da177e4SLinus Torvalds 
sctp_sendmsg_parse(struct sock * sk,struct sctp_cmsgs * cmsgs,struct sctp_sndrcvinfo * srinfo,const struct msghdr * msg,size_t msg_len)1595204f817fSXin Long static int sctp_sendmsg_parse(struct sock *sk, struct sctp_cmsgs *cmsgs,
1596204f817fSXin Long 			      struct sctp_sndrcvinfo *srinfo,
1597204f817fSXin Long 			      const struct msghdr *msg, size_t msg_len)
1598204f817fSXin Long {
1599204f817fSXin Long 	__u16 sflags;
1600204f817fSXin Long 	int err;
1601204f817fSXin Long 
1602204f817fSXin Long 	if (sctp_sstate(sk, LISTENING) && sctp_style(sk, TCP))
1603204f817fSXin Long 		return -EPIPE;
1604204f817fSXin Long 
1605204f817fSXin Long 	if (msg_len > sk->sk_sndbuf)
1606204f817fSXin Long 		return -EMSGSIZE;
1607204f817fSXin Long 
1608204f817fSXin Long 	memset(cmsgs, 0, sizeof(*cmsgs));
1609204f817fSXin Long 	err = sctp_msghdr_parse(msg, cmsgs);
1610204f817fSXin Long 	if (err) {
1611204f817fSXin Long 		pr_debug("%s: msghdr parse err:%x\n", __func__, err);
1612204f817fSXin Long 		return err;
1613204f817fSXin Long 	}
1614204f817fSXin Long 
1615204f817fSXin Long 	memset(srinfo, 0, sizeof(*srinfo));
1616204f817fSXin Long 	if (cmsgs->srinfo) {
1617204f817fSXin Long 		srinfo->sinfo_stream = cmsgs->srinfo->sinfo_stream;
1618204f817fSXin Long 		srinfo->sinfo_flags = cmsgs->srinfo->sinfo_flags;
1619204f817fSXin Long 		srinfo->sinfo_ppid = cmsgs->srinfo->sinfo_ppid;
1620204f817fSXin Long 		srinfo->sinfo_context = cmsgs->srinfo->sinfo_context;
1621204f817fSXin Long 		srinfo->sinfo_assoc_id = cmsgs->srinfo->sinfo_assoc_id;
1622204f817fSXin Long 		srinfo->sinfo_timetolive = cmsgs->srinfo->sinfo_timetolive;
1623204f817fSXin Long 	}
1624204f817fSXin Long 
1625204f817fSXin Long 	if (cmsgs->sinfo) {
1626204f817fSXin Long 		srinfo->sinfo_stream = cmsgs->sinfo->snd_sid;
1627204f817fSXin Long 		srinfo->sinfo_flags = cmsgs->sinfo->snd_flags;
1628204f817fSXin Long 		srinfo->sinfo_ppid = cmsgs->sinfo->snd_ppid;
1629204f817fSXin Long 		srinfo->sinfo_context = cmsgs->sinfo->snd_context;
1630204f817fSXin Long 		srinfo->sinfo_assoc_id = cmsgs->sinfo->snd_assoc_id;
1631204f817fSXin Long 	}
1632204f817fSXin Long 
1633ed63afb8SXin Long 	if (cmsgs->prinfo) {
1634ed63afb8SXin Long 		srinfo->sinfo_timetolive = cmsgs->prinfo->pr_value;
1635ed63afb8SXin Long 		SCTP_PR_SET_POLICY(srinfo->sinfo_flags,
1636ed63afb8SXin Long 				   cmsgs->prinfo->pr_policy);
1637ed63afb8SXin Long 	}
1638ed63afb8SXin Long 
1639204f817fSXin Long 	sflags = srinfo->sinfo_flags;
1640204f817fSXin Long 	if (!sflags && msg_len)
1641204f817fSXin Long 		return 0;
1642204f817fSXin Long 
1643204f817fSXin Long 	if (sctp_style(sk, TCP) && (sflags & (SCTP_EOF | SCTP_ABORT)))
1644204f817fSXin Long 		return -EINVAL;
1645204f817fSXin Long 
1646204f817fSXin Long 	if (((sflags & SCTP_EOF) && msg_len > 0) ||
1647204f817fSXin Long 	    (!(sflags & (SCTP_EOF | SCTP_ABORT)) && msg_len == 0))
1648204f817fSXin Long 		return -EINVAL;
1649204f817fSXin Long 
1650204f817fSXin Long 	if ((sflags & SCTP_ADDR_OVER) && !msg->msg_name)
1651204f817fSXin Long 		return -EINVAL;
1652204f817fSXin Long 
1653204f817fSXin Long 	return 0;
1654204f817fSXin Long }
1655204f817fSXin Long 
sctp_sendmsg_new_asoc(struct sock * sk,__u16 sflags,struct sctp_cmsgs * cmsgs,union sctp_addr * daddr,struct sctp_transport ** tp)16562bfd80f9SXin Long static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
16572bfd80f9SXin Long 				 struct sctp_cmsgs *cmsgs,
16582bfd80f9SXin Long 				 union sctp_addr *daddr,
16592bfd80f9SXin Long 				 struct sctp_transport **tp)
16602bfd80f9SXin Long {
16612bfd80f9SXin Long 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
16622bfd80f9SXin Long 	struct sctp_association *asoc;
16632c0dbaa0SXin Long 	struct cmsghdr *cmsg;
16644be4139fSXin Long 	__be32 flowinfo = 0;
16659eda2d2dSLinus Torvalds 	struct sctp_af *af;
1666d98985ddSWei Yongjun 	int err;
16672bfd80f9SXin Long 
16682bfd80f9SXin Long 	*tp = NULL;
16692bfd80f9SXin Long 
16702bfd80f9SXin Long 	if (sflags & (SCTP_EOF | SCTP_ABORT))
16712bfd80f9SXin Long 		return -EINVAL;
16722bfd80f9SXin Long 
16732bfd80f9SXin Long 	if (sctp_style(sk, TCP) && (sctp_sstate(sk, ESTABLISHED) ||
16742bfd80f9SXin Long 				    sctp_sstate(sk, CLOSING)))
16752bfd80f9SXin Long 		return -EADDRNOTAVAIL;
16762bfd80f9SXin Long 
16772277c7cdSRichard Haines 	/* Label connection socket for first association 1-to-many
16782277c7cdSRichard Haines 	 * style for client sequence socket()->sendmsg(). This
16792277c7cdSRichard Haines 	 * needs to be done before sctp_assoc_add_peer() as that will
16802277c7cdSRichard Haines 	 * set up the initial packet that needs to account for any
16812277c7cdSRichard Haines 	 * security ip options (CIPSO/CALIPSO) added to the packet.
16822277c7cdSRichard Haines 	 */
16839eda2d2dSLinus Torvalds 	af = sctp_get_af_specific(daddr->sa.sa_family);
16849eda2d2dSLinus Torvalds 	if (!af)
16859eda2d2dSLinus Torvalds 		return -EINVAL;
16862277c7cdSRichard Haines 	err = security_sctp_bind_connect(sk, SCTP_SENDMSG_CONNECT,
16879eda2d2dSLinus Torvalds 					 (struct sockaddr *)daddr,
16882277c7cdSRichard Haines 					 af->sockaddr_len);
16892277c7cdSRichard Haines 	if (err < 0)
16909eda2d2dSLinus Torvalds 		return err;
16912277c7cdSRichard Haines 
1692f26f9951SXin Long 	err = sctp_connect_new_asoc(ep, daddr, cmsgs->init, tp);
16932bfd80f9SXin Long 	if (err)
1694f26f9951SXin Long 		return err;
1695f26f9951SXin Long 	asoc = (*tp)->asoc;
16962bfd80f9SXin Long 
16972c0dbaa0SXin Long 	if (!cmsgs->addrs_msg)
16982c0dbaa0SXin Long 		return 0;
16992c0dbaa0SXin Long 
17004be4139fSXin Long 	if (daddr->sa.sa_family == AF_INET6)
17014be4139fSXin Long 		flowinfo = daddr->v6.sin6_flowinfo;
17024be4139fSXin Long 
17032c0dbaa0SXin Long 	/* sendv addr list parse */
17042c0dbaa0SXin Long 	for_each_cmsghdr(cmsg, cmsgs->addrs_msg) {
17052c0dbaa0SXin Long 		union sctp_addr _daddr;
17062c0dbaa0SXin Long 		int dlen;
17072c0dbaa0SXin Long 
17082c0dbaa0SXin Long 		if (cmsg->cmsg_level != IPPROTO_SCTP ||
17092c0dbaa0SXin Long 		    (cmsg->cmsg_type != SCTP_DSTADDRV4 &&
17102c0dbaa0SXin Long 		     cmsg->cmsg_type != SCTP_DSTADDRV6))
17112c0dbaa0SXin Long 			continue;
17122c0dbaa0SXin Long 
17132c0dbaa0SXin Long 		daddr = &_daddr;
17142c0dbaa0SXin Long 		memset(daddr, 0, sizeof(*daddr));
17152c0dbaa0SXin Long 		dlen = cmsg->cmsg_len - sizeof(struct cmsghdr);
17162c0dbaa0SXin Long 		if (cmsg->cmsg_type == SCTP_DSTADDRV4) {
1717d98985ddSWei Yongjun 			if (dlen < sizeof(struct in_addr)) {
1718d98985ddSWei Yongjun 				err = -EINVAL;
17192c0dbaa0SXin Long 				goto free;
1720d98985ddSWei Yongjun 			}
17212c0dbaa0SXin Long 
17222c0dbaa0SXin Long 			dlen = sizeof(struct in_addr);
17232c0dbaa0SXin Long 			daddr->v4.sin_family = AF_INET;
17242c0dbaa0SXin Long 			daddr->v4.sin_port = htons(asoc->peer.port);
17252c0dbaa0SXin Long 			memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen);
17262c0dbaa0SXin Long 		} else {
1727d98985ddSWei Yongjun 			if (dlen < sizeof(struct in6_addr)) {
1728d98985ddSWei Yongjun 				err = -EINVAL;
17292c0dbaa0SXin Long 				goto free;
1730d98985ddSWei Yongjun 			}
17312c0dbaa0SXin Long 
17322c0dbaa0SXin Long 			dlen = sizeof(struct in6_addr);
17334be4139fSXin Long 			daddr->v6.sin6_flowinfo = flowinfo;
17342c0dbaa0SXin Long 			daddr->v6.sin6_family = AF_INET6;
17352c0dbaa0SXin Long 			daddr->v6.sin6_port = htons(asoc->peer.port);
17362c0dbaa0SXin Long 			memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen);
17372c0dbaa0SXin Long 		}
1738a64e59c7SXin Long 
1739a64e59c7SXin Long 		err = sctp_connect_add_peer(asoc, daddr, sizeof(*daddr));
17402c0dbaa0SXin Long 		if (err)
17412c0dbaa0SXin Long 			goto free;
17422c0dbaa0SXin Long 	}
17432c0dbaa0SXin Long 
17442bfd80f9SXin Long 	return 0;
17452bfd80f9SXin Long 
17462bfd80f9SXin Long free:
17472bfd80f9SXin Long 	sctp_association_free(asoc);
17482bfd80f9SXin Long 	return err;
17492bfd80f9SXin Long }
17502bfd80f9SXin Long 
sctp_sendmsg_check_sflags(struct sctp_association * asoc,__u16 sflags,struct msghdr * msg,size_t msg_len)1751c2666de1SXin Long static int sctp_sendmsg_check_sflags(struct sctp_association *asoc,
1752c2666de1SXin Long 				     __u16 sflags, struct msghdr *msg,
1753c2666de1SXin Long 				     size_t msg_len)
1754c2666de1SXin Long {
1755c2666de1SXin Long 	struct sock *sk = asoc->base.sk;
1756c2666de1SXin Long 	struct net *net = sock_net(sk);
1757c2666de1SXin Long 
1758c2666de1SXin Long 	if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP))
1759c2666de1SXin Long 		return -EPIPE;
1760c2666de1SXin Long 
176149102805SXin Long 	if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP) &&
176249102805SXin Long 	    !sctp_state(asoc, ESTABLISHED))
176349102805SXin Long 		return 0;
176449102805SXin Long 
1765c2666de1SXin Long 	if (sflags & SCTP_EOF) {
1766c2666de1SXin Long 		pr_debug("%s: shutting down association:%p\n", __func__, asoc);
1767c2666de1SXin Long 		sctp_primitive_SHUTDOWN(net, asoc, NULL);
1768c2666de1SXin Long 
1769c2666de1SXin Long 		return 0;
1770c2666de1SXin Long 	}
1771c2666de1SXin Long 
1772c2666de1SXin Long 	if (sflags & SCTP_ABORT) {
1773c2666de1SXin Long 		struct sctp_chunk *chunk;
1774c2666de1SXin Long 
1775c2666de1SXin Long 		chunk = sctp_make_abort_user(asoc, msg, msg_len);
1776c2666de1SXin Long 		if (!chunk)
1777c2666de1SXin Long 			return -ENOMEM;
1778c2666de1SXin Long 
1779c2666de1SXin Long 		pr_debug("%s: aborting association:%p\n", __func__, asoc);
1780c2666de1SXin Long 		sctp_primitive_ABORT(net, asoc, chunk);
1781901efe12SXin Long 		iov_iter_revert(&msg->msg_iter, msg_len);
1782c2666de1SXin Long 
1783c2666de1SXin Long 		return 0;
1784c2666de1SXin Long 	}
1785c2666de1SXin Long 
1786c2666de1SXin Long 	return 1;
1787c2666de1SXin Long }
1788c2666de1SXin Long 
sctp_sendmsg_to_asoc(struct sctp_association * asoc,struct msghdr * msg,size_t msg_len,struct sctp_transport * transport,struct sctp_sndrcvinfo * sinfo)1789f84af331SXin Long static int sctp_sendmsg_to_asoc(struct sctp_association *asoc,
1790f84af331SXin Long 				struct msghdr *msg, size_t msg_len,
1791f84af331SXin Long 				struct sctp_transport *transport,
1792f84af331SXin Long 				struct sctp_sndrcvinfo *sinfo)
1793f84af331SXin Long {
1794f84af331SXin Long 	struct sock *sk = asoc->base.sk;
179563d01330SMarcelo Ricardo Leitner 	struct sctp_sock *sp = sctp_sk(sk);
1796f84af331SXin Long 	struct net *net = sock_net(sk);
1797f84af331SXin Long 	struct sctp_datamsg *datamsg;
1798f84af331SXin Long 	bool wait_connect = false;
1799f84af331SXin Long 	struct sctp_chunk *chunk;
1800f84af331SXin Long 	long timeo;
1801f84af331SXin Long 	int err;
1802f84af331SXin Long 
1803f84af331SXin Long 	if (sinfo->sinfo_stream >= asoc->stream.outcnt) {
1804f84af331SXin Long 		err = -EINVAL;
1805f84af331SXin Long 		goto err;
1806f84af331SXin Long 	}
1807f84af331SXin Long 
180805364ca0SKonstantin Khorenko 	if (unlikely(!SCTP_SO(&asoc->stream, sinfo->sinfo_stream)->ext)) {
1809f84af331SXin Long 		err = sctp_stream_init_ext(&asoc->stream, sinfo->sinfo_stream);
1810f84af331SXin Long 		if (err)
1811f84af331SXin Long 			goto err;
1812f84af331SXin Long 	}
1813f84af331SXin Long 
181463d01330SMarcelo Ricardo Leitner 	if (sp->disable_fragments && msg_len > asoc->frag_point) {
1815f84af331SXin Long 		err = -EMSGSIZE;
1816f84af331SXin Long 		goto err;
1817f84af331SXin Long 	}
1818f84af331SXin Long 
18192521680eSMarcelo Ricardo Leitner 	if (asoc->pmtu_pending) {
182063d01330SMarcelo Ricardo Leitner 		if (sp->param_flags & SPP_PMTUD_ENABLE)
18212521680eSMarcelo Ricardo Leitner 			sctp_assoc_sync_pmtu(asoc);
18222521680eSMarcelo Ricardo Leitner 		asoc->pmtu_pending = 0;
18232521680eSMarcelo Ricardo Leitner 	}
18240aee4c25SNeil Horman 
1825cd305c74SXin Long 	if (sctp_wspace(asoc) < (int)msg_len)
18260aee4c25SNeil Horman 		sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc));
18270aee4c25SNeil Horman 
18281033990aSXin Long 	if (sctp_wspace(asoc) <= 0 || !sk_wmem_schedule(sk, msg_len)) {
18290aee4c25SNeil Horman 		timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
18300aee4c25SNeil Horman 		err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len);
18310aee4c25SNeil Horman 		if (err)
18320aee4c25SNeil Horman 			goto err;
18332584024bSXin Long 		if (unlikely(sinfo->sinfo_stream >= asoc->stream.outcnt)) {
18342584024bSXin Long 			err = -EINVAL;
18352584024bSXin Long 			goto err;
18362584024bSXin Long 		}
18370aee4c25SNeil Horman 	}
18380aee4c25SNeil Horman 
1839f84af331SXin Long 	if (sctp_state(asoc, CLOSED)) {
1840f84af331SXin Long 		err = sctp_primitive_ASSOCIATE(net, asoc, NULL);
1841f84af331SXin Long 		if (err)
1842f84af331SXin Long 			goto err;
1843f84af331SXin Long 
1844e55f4b8bSXin Long 		if (asoc->ep->intl_enable) {
1845f84af331SXin Long 			timeo = sock_sndtimeo(sk, 0);
1846f84af331SXin Long 			err = sctp_wait_for_connect(asoc, &timeo);
1847c863850cSXin Long 			if (err) {
1848c863850cSXin Long 				err = -ESRCH;
1849f84af331SXin Long 				goto err;
1850c863850cSXin Long 			}
1851f84af331SXin Long 		} else {
1852f84af331SXin Long 			wait_connect = true;
1853f84af331SXin Long 		}
1854f84af331SXin Long 
1855f84af331SXin Long 		pr_debug("%s: we associated primitively\n", __func__);
1856f84af331SXin Long 	}
1857f84af331SXin Long 
1858f84af331SXin Long 	datamsg = sctp_datamsg_from_user(asoc, sinfo, &msg->msg_iter);
1859f84af331SXin Long 	if (IS_ERR(datamsg)) {
1860f84af331SXin Long 		err = PTR_ERR(datamsg);
1861f84af331SXin Long 		goto err;
1862f84af331SXin Long 	}
1863f84af331SXin Long 
1864f84af331SXin Long 	asoc->force_delay = !!(msg->msg_flags & MSG_MORE);
1865f84af331SXin Long 
1866f84af331SXin Long 	list_for_each_entry(chunk, &datamsg->chunks, frag_list) {
1867f84af331SXin Long 		sctp_chunk_hold(chunk);
1868f84af331SXin Long 		sctp_set_owner_w(chunk);
1869f84af331SXin Long 		chunk->transport = transport;
1870f84af331SXin Long 	}
1871f84af331SXin Long 
1872f84af331SXin Long 	err = sctp_primitive_SEND(net, asoc, datamsg);
1873f84af331SXin Long 	if (err) {
1874f84af331SXin Long 		sctp_datamsg_free(datamsg);
1875f84af331SXin Long 		goto err;
1876f84af331SXin Long 	}
1877f84af331SXin Long 
1878f84af331SXin Long 	pr_debug("%s: we sent primitively\n", __func__);
1879f84af331SXin Long 
1880f84af331SXin Long 	sctp_datamsg_put(datamsg);
1881f84af331SXin Long 
1882f84af331SXin Long 	if (unlikely(wait_connect)) {
1883f84af331SXin Long 		timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
1884f84af331SXin Long 		sctp_wait_for_connect(asoc, &timeo);
1885f84af331SXin Long 	}
1886f84af331SXin Long 
1887f84af331SXin Long 	err = msg_len;
1888f84af331SXin Long 
1889f84af331SXin Long err:
1890f84af331SXin Long 	return err;
1891f84af331SXin Long }
1892f84af331SXin Long 
sctp_sendmsg_get_daddr(struct sock * sk,const struct msghdr * msg,struct sctp_cmsgs * cmsgs)1893becef9b1SXin Long static union sctp_addr *sctp_sendmsg_get_daddr(struct sock *sk,
1894becef9b1SXin Long 					       const struct msghdr *msg,
1895becef9b1SXin Long 					       struct sctp_cmsgs *cmsgs)
1896becef9b1SXin Long {
1897becef9b1SXin Long 	union sctp_addr *daddr = NULL;
1898becef9b1SXin Long 	int err;
1899becef9b1SXin Long 
1900becef9b1SXin Long 	if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) {
1901becef9b1SXin Long 		int len = msg->msg_namelen;
1902becef9b1SXin Long 
1903becef9b1SXin Long 		if (len > sizeof(*daddr))
1904becef9b1SXin Long 			len = sizeof(*daddr);
1905becef9b1SXin Long 
1906becef9b1SXin Long 		daddr = (union sctp_addr *)msg->msg_name;
1907becef9b1SXin Long 
1908becef9b1SXin Long 		err = sctp_verify_addr(sk, daddr, len);
1909becef9b1SXin Long 		if (err)
1910becef9b1SXin Long 			return ERR_PTR(err);
1911becef9b1SXin Long 	}
1912becef9b1SXin Long 
1913becef9b1SXin Long 	return daddr;
1914becef9b1SXin Long }
1915becef9b1SXin Long 
sctp_sendmsg_update_sinfo(struct sctp_association * asoc,struct sctp_sndrcvinfo * sinfo,struct sctp_cmsgs * cmsgs)1916d42cb06eSXin Long static void sctp_sendmsg_update_sinfo(struct sctp_association *asoc,
1917d42cb06eSXin Long 				      struct sctp_sndrcvinfo *sinfo,
1918d42cb06eSXin Long 				      struct sctp_cmsgs *cmsgs)
1919d42cb06eSXin Long {
1920d42cb06eSXin Long 	if (!cmsgs->srinfo && !cmsgs->sinfo) {
1921d42cb06eSXin Long 		sinfo->sinfo_stream = asoc->default_stream;
1922d42cb06eSXin Long 		sinfo->sinfo_ppid = asoc->default_ppid;
1923d42cb06eSXin Long 		sinfo->sinfo_context = asoc->default_context;
1924d42cb06eSXin Long 		sinfo->sinfo_assoc_id = sctp_assoc2id(asoc);
1925ed63afb8SXin Long 
1926ed63afb8SXin Long 		if (!cmsgs->prinfo)
1927ed63afb8SXin Long 			sinfo->sinfo_flags = asoc->default_flags;
1928d42cb06eSXin Long 	}
1929d42cb06eSXin Long 
1930ed63afb8SXin Long 	if (!cmsgs->srinfo && !cmsgs->prinfo)
1931d42cb06eSXin Long 		sinfo->sinfo_timetolive = asoc->default_timetolive;
19323ff547c0SXin Long 
19333ff547c0SXin Long 	if (cmsgs->authinfo) {
19343ff547c0SXin Long 		/* Reuse sinfo_tsn to indicate that authinfo was set and
19353ff547c0SXin Long 		 * sinfo_ssn to save the keyid on tx path.
19363ff547c0SXin Long 		 */
19373ff547c0SXin Long 		sinfo->sinfo_tsn = 1;
19383ff547c0SXin Long 		sinfo->sinfo_ssn = cmsgs->authinfo->auth_keynumber;
19393ff547c0SXin Long 	}
1940d42cb06eSXin Long }
1941d42cb06eSXin Long 
sctp_sendmsg(struct sock * sk,struct msghdr * msg,size_t msg_len)19421b784140SYing Xue static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
19431da177e4SLinus Torvalds {
1944204f817fSXin Long 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
19458e87c6ebSXin Long 	struct sctp_transport *transport = NULL;
1946204f817fSXin Long 	struct sctp_sndrcvinfo _sinfo, *sinfo;
1947ba59fb02SGreg Kroah-Hartman 	struct sctp_association *asoc, *tmp;
1948007b7e18SXin Long 	struct sctp_cmsgs cmsgs;
1949becef9b1SXin Long 	union sctp_addr *daddr;
1950007b7e18SXin Long 	bool new = false;
1951007b7e18SXin Long 	__u16 sflags;
195263b94938SGeir Ola Vaagland 	int err;
19531da177e4SLinus Torvalds 
1954204f817fSXin Long 	/* Parse and get snd_info */
1955204f817fSXin Long 	err = sctp_sendmsg_parse(sk, &cmsgs, &_sinfo, msg, msg_len);
1956204f817fSXin Long 	if (err)
1957007b7e18SXin Long 		goto out;
19581da177e4SLinus Torvalds 
1959204f817fSXin Long 	sinfo  = &_sinfo;
1960007b7e18SXin Long 	sflags = sinfo->sinfo_flags;
19611da177e4SLinus Torvalds 
1962becef9b1SXin Long 	/* Get daddr from msg */
1963becef9b1SXin Long 	daddr = sctp_sendmsg_get_daddr(sk, msg, &cmsgs);
1964becef9b1SXin Long 	if (IS_ERR(daddr)) {
1965becef9b1SXin Long 		err = PTR_ERR(daddr);
1966007b7e18SXin Long 		goto out;
19671da177e4SLinus Torvalds 	}
19681da177e4SLinus Torvalds 
1969048ed4b6Swangweidong 	lock_sock(sk);
19701da177e4SLinus Torvalds 
197149102805SXin Long 	/* SCTP_SENDALL process */
197249102805SXin Long 	if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) {
1973ba59fb02SGreg Kroah-Hartman 		list_for_each_entry_safe(asoc, tmp, &ep->asocs, asocs) {
197449102805SXin Long 			err = sctp_sendmsg_check_sflags(asoc, sflags, msg,
197549102805SXin Long 							msg_len);
197649102805SXin Long 			if (err == 0)
197749102805SXin Long 				continue;
197849102805SXin Long 			if (err < 0)
197949102805SXin Long 				goto out_unlock;
198049102805SXin Long 
198149102805SXin Long 			sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs);
198249102805SXin Long 
198349102805SXin Long 			err = sctp_sendmsg_to_asoc(asoc, msg, msg_len,
198449102805SXin Long 						   NULL, sinfo);
198549102805SXin Long 			if (err < 0)
198649102805SXin Long 				goto out_unlock;
198749102805SXin Long 
198849102805SXin Long 			iov_iter_revert(&msg->msg_iter, err);
198949102805SXin Long 		}
199049102805SXin Long 
199149102805SXin Long 		goto out_unlock;
199249102805SXin Long 	}
199349102805SXin Long 
19940a3920d2SXin Long 	/* Get and check or create asoc */
1995becef9b1SXin Long 	if (daddr) {
1996becef9b1SXin Long 		asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
19971da177e4SLinus Torvalds 		if (asoc) {
19980a3920d2SXin Long 			err = sctp_sendmsg_check_sflags(asoc, sflags, msg,
19990a3920d2SXin Long 							msg_len);
2000c2666de1SXin Long 			if (err <= 0)
20011da177e4SLinus Torvalds 				goto out_unlock;
20020a3920d2SXin Long 		} else {
2003007b7e18SXin Long 			err = sctp_sendmsg_new_asoc(sk, sflags, &cmsgs, daddr,
20042bfd80f9SXin Long 						    &transport);
2005625637bfSXin Long 			if (err)
20062bfd80f9SXin Long 				goto out_unlock;
20071da177e4SLinus Torvalds 
20082bfd80f9SXin Long 			asoc = transport->asoc;
2009007b7e18SXin Long 			new = true;
20101da177e4SLinus Torvalds 		}
20111da177e4SLinus Torvalds 
2012007b7e18SXin Long 		if (!sctp_style(sk, TCP) && !(sflags & SCTP_ADDR_OVER))
20138e87c6ebSXin Long 			transport = NULL;
20140a3920d2SXin Long 	} else {
20150a3920d2SXin Long 		asoc = sctp_id2assoc(sk, sinfo->sinfo_assoc_id);
20160a3920d2SXin Long 		if (!asoc) {
20170a3920d2SXin Long 			err = -EPIPE;
20180a3920d2SXin Long 			goto out_unlock;
20190a3920d2SXin Long 		}
20200a3920d2SXin Long 
20210a3920d2SXin Long 		err = sctp_sendmsg_check_sflags(asoc, sflags, msg, msg_len);
20220a3920d2SXin Long 		if (err <= 0)
20230a3920d2SXin Long 			goto out_unlock;
20240a3920d2SXin Long 	}
20258e87c6ebSXin Long 
2026d42cb06eSXin Long 	/* Update snd_info with the asoc */
2027d42cb06eSXin Long 	sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs);
20281da177e4SLinus Torvalds 
2029f84af331SXin Long 	/* Send msg to the asoc */
20308e87c6ebSXin Long 	err = sctp_sendmsg_to_asoc(asoc, msg, msg_len, transport, sinfo);
2031007b7e18SXin Long 	if (err < 0 && err != -ESRCH && new)
20321da177e4SLinus Torvalds 		sctp_association_free(asoc);
20338e87c6ebSXin Long 
20341da177e4SLinus Torvalds out_unlock:
2035048ed4b6Swangweidong 	release_sock(sk);
2036007b7e18SXin Long out:
2037f84af331SXin Long 	return sctp_error(sk, msg->msg_flags, err);
20381da177e4SLinus Torvalds }
20391da177e4SLinus Torvalds 
20401da177e4SLinus Torvalds /* This is an extended version of skb_pull() that removes the data from the
20411da177e4SLinus Torvalds  * start of a skb even when data is spread across the list of skb's in the
20421da177e4SLinus Torvalds  * frag_list. len specifies the total amount of data that needs to be removed.
20431da177e4SLinus Torvalds  * when 'len' bytes could be removed from the skb, it returns 0.
20441da177e4SLinus Torvalds  * If 'len' exceeds the total skb length,  it returns the no. of bytes that
20451da177e4SLinus Torvalds  * could not be removed.
20461da177e4SLinus Torvalds  */
sctp_skb_pull(struct sk_buff * skb,int len)20471da177e4SLinus Torvalds static int sctp_skb_pull(struct sk_buff *skb, int len)
20481da177e4SLinus Torvalds {
20491da177e4SLinus Torvalds 	struct sk_buff *list;
20501da177e4SLinus Torvalds 	int skb_len = skb_headlen(skb);
20511da177e4SLinus Torvalds 	int rlen;
20521da177e4SLinus Torvalds 
20531da177e4SLinus Torvalds 	if (len <= skb_len) {
20541da177e4SLinus Torvalds 		__skb_pull(skb, len);
20551da177e4SLinus Torvalds 		return 0;
20561da177e4SLinus Torvalds 	}
20571da177e4SLinus Torvalds 	len -= skb_len;
20581da177e4SLinus Torvalds 	__skb_pull(skb, skb_len);
20591da177e4SLinus Torvalds 
20601b003be3SDavid S. Miller 	skb_walk_frags(skb, list) {
20611da177e4SLinus Torvalds 		rlen = sctp_skb_pull(list, len);
20621da177e4SLinus Torvalds 		skb->len -= (len-rlen);
20631da177e4SLinus Torvalds 		skb->data_len -= (len-rlen);
20641da177e4SLinus Torvalds 
20651da177e4SLinus Torvalds 		if (!rlen)
20661da177e4SLinus Torvalds 			return 0;
20671da177e4SLinus Torvalds 
20681da177e4SLinus Torvalds 		len = rlen;
20691da177e4SLinus Torvalds 	}
20701da177e4SLinus Torvalds 
20711da177e4SLinus Torvalds 	return len;
20721da177e4SLinus Torvalds }
20731da177e4SLinus Torvalds 
20741da177e4SLinus Torvalds /* API 3.1.3  recvmsg() - UDP Style Syntax
20751da177e4SLinus Torvalds  *
20761da177e4SLinus Torvalds  *  ssize_t recvmsg(int socket, struct msghdr *message,
20771da177e4SLinus Torvalds  *                    int flags);
20781da177e4SLinus Torvalds  *
20791da177e4SLinus Torvalds  *  socket  - the socket descriptor of the endpoint.
20801da177e4SLinus Torvalds  *  message - pointer to the msghdr structure which contains a single
20811da177e4SLinus Torvalds  *            user message and possibly some ancillary data.
20821da177e4SLinus Torvalds  *
20831da177e4SLinus Torvalds  *            See Section 5 for complete description of the data
20841da177e4SLinus Torvalds  *            structures.
20851da177e4SLinus Torvalds  *
20861da177e4SLinus Torvalds  *  flags   - flags sent or received with the user message, see Section
20871da177e4SLinus Torvalds  *            5 for complete description of the flags.
20881da177e4SLinus Torvalds  */
sctp_recvmsg(struct sock * sk,struct msghdr * msg,size_t len,int flags,int * addr_len)20891b784140SYing Xue static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
2090ec095263SOliver Hartkopp 			int flags, int *addr_len)
20911da177e4SLinus Torvalds {
20921da177e4SLinus Torvalds 	struct sctp_ulpevent *event = NULL;
20931da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
20941f45f78fSMarcelo Ricardo Leitner 	struct sk_buff *skb, *head_skb;
20951da177e4SLinus Torvalds 	int copied;
20961da177e4SLinus Torvalds 	int err = 0;
20971da177e4SLinus Torvalds 	int skb_len;
20981da177e4SLinus Torvalds 
2099ec095263SOliver Hartkopp 	pr_debug("%s: sk:%p, msghdr:%p, len:%zd, flags:0x%x, addr_len:%p)\n",
2100ec095263SOliver Hartkopp 		 __func__, sk, msg, len, flags, addr_len);
21011da177e4SLinus Torvalds 
21029702e7fbSEric Dumazet 	if (unlikely(flags & MSG_ERRQUEUE))
21039702e7fbSEric Dumazet 		return inet_recv_error(sk, msg, len, addr_len);
21049702e7fbSEric Dumazet 
210563c3c44fSEric Dumazet 	if (sk_can_busy_loop(sk) &&
210663c3c44fSEric Dumazet 	    skb_queue_empty_lockless(&sk->sk_receive_queue))
210763c3c44fSEric Dumazet 		sk_busy_loop(sk, flags & MSG_DONTWAIT);
210863c3c44fSEric Dumazet 
2109048ed4b6Swangweidong 	lock_sock(sk);
21101da177e4SLinus Torvalds 
2111e5b13f34SMarcelo Ricardo Leitner 	if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED) &&
2112e0878694SXin Long 	    !sctp_sstate(sk, CLOSING) && !sctp_sstate(sk, CLOSED)) {
21131da177e4SLinus Torvalds 		err = -ENOTCONN;
21141da177e4SLinus Torvalds 		goto out;
21151da177e4SLinus Torvalds 	}
21161da177e4SLinus Torvalds 
2117ec095263SOliver Hartkopp 	skb = sctp_skb_recv_datagram(sk, flags, &err);
21181da177e4SLinus Torvalds 	if (!skb)
21191da177e4SLinus Torvalds 		goto out;
21201da177e4SLinus Torvalds 
21211da177e4SLinus Torvalds 	/* Get the total length of the skb including any skb's in the
21221da177e4SLinus Torvalds 	 * frag_list.
21231da177e4SLinus Torvalds 	 */
21241da177e4SLinus Torvalds 	skb_len = skb->len;
21251da177e4SLinus Torvalds 
21261da177e4SLinus Torvalds 	copied = skb_len;
21271da177e4SLinus Torvalds 	if (copied > len)
21281da177e4SLinus Torvalds 		copied = len;
21291da177e4SLinus Torvalds 
213051f3d02bSDavid S. Miller 	err = skb_copy_datagram_msg(skb, 0, msg, copied);
21311da177e4SLinus Torvalds 
21321da177e4SLinus Torvalds 	event = sctp_skb2event(skb);
21331da177e4SLinus Torvalds 
21341da177e4SLinus Torvalds 	if (err)
21351da177e4SLinus Torvalds 		goto out_free;
21361da177e4SLinus Torvalds 
21371f45f78fSMarcelo Ricardo Leitner 	if (event->chunk && event->chunk->head_skb)
21381f45f78fSMarcelo Ricardo Leitner 		head_skb = event->chunk->head_skb;
21391f45f78fSMarcelo Ricardo Leitner 	else
21401f45f78fSMarcelo Ricardo Leitner 		head_skb = skb;
21416fd1d51cSErin MacNeil 	sock_recv_cmsgs(msg, sk, head_skb);
21421da177e4SLinus Torvalds 	if (sctp_ulpevent_is_notification(event)) {
21431da177e4SLinus Torvalds 		msg->msg_flags |= MSG_NOTIFICATION;
21441da177e4SLinus Torvalds 		sp->pf->event_msgname(event, msg->msg_name, addr_len);
21451da177e4SLinus Torvalds 	} else {
21461f45f78fSMarcelo Ricardo Leitner 		sp->pf->skb_msgname(head_skb, msg->msg_name, addr_len);
21471da177e4SLinus Torvalds 	}
21481da177e4SLinus Torvalds 
21492347c80fSGeir Ola Vaagland 	/* Check if we allow SCTP_NXTINFO. */
21502347c80fSGeir Ola Vaagland 	if (sp->recvnxtinfo)
21512347c80fSGeir Ola Vaagland 		sctp_ulpevent_read_nxtinfo(event, msg, sk);
21520d3a421dSGeir Ola Vaagland 	/* Check if we allow SCTP_RCVINFO. */
21530d3a421dSGeir Ola Vaagland 	if (sp->recvrcvinfo)
21540d3a421dSGeir Ola Vaagland 		sctp_ulpevent_read_rcvinfo(event, msg);
21551da177e4SLinus Torvalds 	/* Check if we allow SCTP_SNDRCVINFO. */
21562cc0eeb6SXin Long 	if (sctp_ulpevent_type_enabled(sp->subscribe, SCTP_DATA_IO_EVENT))
21571da177e4SLinus Torvalds 		sctp_ulpevent_read_sndrcvinfo(event, msg);
21580d3a421dSGeir Ola Vaagland 
21591da177e4SLinus Torvalds 	err = copied;
21601da177e4SLinus Torvalds 
21611da177e4SLinus Torvalds 	/* If skb's length exceeds the user's buffer, update the skb and
21621da177e4SLinus Torvalds 	 * push it back to the receive_queue so that the next call to
21631da177e4SLinus Torvalds 	 * recvmsg() will return the remaining data. Don't set MSG_EOR.
21641da177e4SLinus Torvalds 	 */
21651da177e4SLinus Torvalds 	if (skb_len > copied) {
21661da177e4SLinus Torvalds 		msg->msg_flags &= ~MSG_EOR;
21671da177e4SLinus Torvalds 		if (flags & MSG_PEEK)
21681da177e4SLinus Torvalds 			goto out_free;
21691da177e4SLinus Torvalds 		sctp_skb_pull(skb, copied);
21701da177e4SLinus Torvalds 		skb_queue_head(&sk->sk_receive_queue, skb);
21711da177e4SLinus Torvalds 
2172362d5204SDaniel Borkmann 		/* When only partial message is copied to the user, increase
2173362d5204SDaniel Borkmann 		 * rwnd by that amount. If all the data in the skb is read,
2174362d5204SDaniel Borkmann 		 * rwnd is updated when the event is freed.
2175362d5204SDaniel Borkmann 		 */
2176362d5204SDaniel Borkmann 		if (!sctp_ulpevent_is_notification(event))
2177362d5204SDaniel Borkmann 			sctp_assoc_rwnd_increase(event->asoc, copied);
21781da177e4SLinus Torvalds 		goto out;
21791da177e4SLinus Torvalds 	} else if ((event->msg_flags & MSG_NOTIFICATION) ||
21801da177e4SLinus Torvalds 		   (event->msg_flags & MSG_EOR))
21811da177e4SLinus Torvalds 		msg->msg_flags |= MSG_EOR;
21821da177e4SLinus Torvalds 	else
21831da177e4SLinus Torvalds 		msg->msg_flags &= ~MSG_EOR;
21841da177e4SLinus Torvalds 
21851da177e4SLinus Torvalds out_free:
21861da177e4SLinus Torvalds 	if (flags & MSG_PEEK) {
21871da177e4SLinus Torvalds 		/* Release the skb reference acquired after peeking the skb in
21881da177e4SLinus Torvalds 		 * sctp_skb_recv_datagram().
21891da177e4SLinus Torvalds 		 */
21901da177e4SLinus Torvalds 		kfree_skb(skb);
21911da177e4SLinus Torvalds 	} else {
21921da177e4SLinus Torvalds 		/* Free the event which includes releasing the reference to
21931da177e4SLinus Torvalds 		 * the owner of the skb, freeing the skb and updating the
21941da177e4SLinus Torvalds 		 * rwnd.
21951da177e4SLinus Torvalds 		 */
21961da177e4SLinus Torvalds 		sctp_ulpevent_free(event);
21971da177e4SLinus Torvalds 	}
21981da177e4SLinus Torvalds out:
2199048ed4b6Swangweidong 	release_sock(sk);
22001da177e4SLinus Torvalds 	return err;
22011da177e4SLinus Torvalds }
22021da177e4SLinus Torvalds 
22031da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
22041da177e4SLinus Torvalds  *
22051da177e4SLinus Torvalds  * This option is a on/off flag.  If enabled no SCTP message
22061da177e4SLinus Torvalds  * fragmentation will be performed.  Instead if a message being sent
22071da177e4SLinus Torvalds  * exceeds the current PMTU size, the message will NOT be sent and
22081da177e4SLinus Torvalds  * instead a error will be indicated to the user.
22091da177e4SLinus Torvalds  */
sctp_setsockopt_disable_fragments(struct sock * sk,int * val,unsigned int optlen)221010835825SChristoph Hellwig static int sctp_setsockopt_disable_fragments(struct sock *sk, int *val,
2211b7058842SDavid S. Miller 					     unsigned int optlen)
22121da177e4SLinus Torvalds {
22131da177e4SLinus Torvalds 	if (optlen < sizeof(int))
22141da177e4SLinus Torvalds 		return -EINVAL;
221510835825SChristoph Hellwig 	sctp_sk(sk)->disable_fragments = (*val == 0) ? 0 : 1;
22161da177e4SLinus Torvalds 	return 0;
22171da177e4SLinus Torvalds }
22181da177e4SLinus Torvalds 
sctp_setsockopt_events(struct sock * sk,__u8 * sn_type,unsigned int optlen)2219a98d21a1SChristoph Hellwig static int sctp_setsockopt_events(struct sock *sk, __u8 *sn_type,
2220b7058842SDavid S. Miller 				  unsigned int optlen)
22211da177e4SLinus Torvalds {
22222cc0eeb6SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
2223a1e3a059SXin Long 	struct sctp_association *asoc;
22242cc0eeb6SXin Long 	int i;
222594912301SWei Yongjun 
22267e8616d8SVlad Yasevich 	if (optlen > sizeof(struct sctp_event_subscribe))
22271da177e4SLinus Torvalds 		return -EINVAL;
22282cc0eeb6SXin Long 
22292cc0eeb6SXin Long 	for (i = 0; i < optlen; i++)
22302cc0eeb6SXin Long 		sctp_ulpevent_type_set(&sp->subscribe, SCTP_SN_TYPE_BASE + i,
22312cc0eeb6SXin Long 				       sn_type[i]);
22322cc0eeb6SXin Long 
2233a1e3a059SXin Long 	list_for_each_entry(asoc, &sp->ep->asocs, asocs)
2234a1e3a059SXin Long 		asoc->subscribe = sctp_sk(sk)->subscribe;
2235a1e3a059SXin Long 
2236bbbea41dSDaniel Borkmann 	/* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT,
223794912301SWei Yongjun 	 * if there is no data to be sent or retransmit, the stack will
223894912301SWei Yongjun 	 * immediately send up this notification.
223994912301SWei Yongjun 	 */
22402cc0eeb6SXin Long 	if (sctp_ulpevent_type_enabled(sp->subscribe, SCTP_SENDER_DRY_EVENT)) {
22412cc0eeb6SXin Long 		struct sctp_ulpevent *event;
224294912301SWei Yongjun 
2243a1e3a059SXin Long 		asoc = sctp_id2assoc(sk, 0);
224494912301SWei Yongjun 		if (asoc && sctp_outq_is_empty(&asoc->outqueue)) {
224594912301SWei Yongjun 			event = sctp_ulpevent_make_sender_dry_event(asoc,
22462e83acb9SMarcelo Ricardo Leitner 					GFP_USER | __GFP_NOWARN);
224794912301SWei Yongjun 			if (!event)
224894912301SWei Yongjun 				return -ENOMEM;
224994912301SWei Yongjun 
22509162e0edSXin Long 			asoc->stream.si->enqueue_event(&asoc->ulpq, event);
225194912301SWei Yongjun 		}
225294912301SWei Yongjun 	}
225394912301SWei Yongjun 
22541da177e4SLinus Torvalds 	return 0;
22551da177e4SLinus Torvalds }
22561da177e4SLinus Torvalds 
22571da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE)
22581da177e4SLinus Torvalds  *
22591da177e4SLinus Torvalds  * This socket option is applicable to the UDP-style socket only.  When
22601da177e4SLinus Torvalds  * set it will cause associations that are idle for more than the
22611da177e4SLinus Torvalds  * specified number of seconds to automatically close.  An association
22621da177e4SLinus Torvalds  * being idle is defined an association that has NOT sent or received
22631da177e4SLinus Torvalds  * user data.  The special value of '0' indicates that no automatic
22641da177e4SLinus Torvalds  * close of any associations should be performed.  The option expects an
22651da177e4SLinus Torvalds  * integer defining the number of seconds of idle time before an
22661da177e4SLinus Torvalds  * association is closed.
22671da177e4SLinus Torvalds  */
sctp_setsockopt_autoclose(struct sock * sk,u32 * optval,unsigned int optlen)22680b49a65cSChristoph Hellwig static int sctp_setsockopt_autoclose(struct sock *sk, u32 *optval,
2269b7058842SDavid S. Miller 				     unsigned int optlen)
22701da177e4SLinus Torvalds {
22711da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
22729f70f46bSNeil Horman 	struct net *net = sock_net(sk);
22731da177e4SLinus Torvalds 
22741da177e4SLinus Torvalds 	/* Applicable to UDP-style socket only */
22751da177e4SLinus Torvalds 	if (sctp_style(sk, TCP))
22761da177e4SLinus Torvalds 		return -EOPNOTSUPP;
22771da177e4SLinus Torvalds 	if (optlen != sizeof(int))
22781da177e4SLinus Torvalds 		return -EINVAL;
22791da177e4SLinus Torvalds 
22800b49a65cSChristoph Hellwig 	sp->autoclose = *optval;
22819f70f46bSNeil Horman 	if (sp->autoclose > net->sctp.max_autoclose)
22829f70f46bSNeil Horman 		sp->autoclose = net->sctp.max_autoclose;
22839f70f46bSNeil Horman 
22841da177e4SLinus Torvalds 	return 0;
22851da177e4SLinus Torvalds }
22861da177e4SLinus Torvalds 
22871da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS)
22881da177e4SLinus Torvalds  *
22891da177e4SLinus Torvalds  * Applications can enable or disable heartbeats for any peer address of
22901da177e4SLinus Torvalds  * an association, modify an address's heartbeat interval, force a
22911da177e4SLinus Torvalds  * heartbeat to be sent immediately, and adjust the address's maximum
22921da177e4SLinus Torvalds  * number of retransmissions sent before an address is considered
22931da177e4SLinus Torvalds  * unreachable.  The following structure is used to access and modify an
22941da177e4SLinus Torvalds  * address's parameters:
22951da177e4SLinus Torvalds  *
22961da177e4SLinus Torvalds  *  struct sctp_paddrparams {
22971da177e4SLinus Torvalds  *     sctp_assoc_t            spp_assoc_id;
22981da177e4SLinus Torvalds  *     struct sockaddr_storage spp_address;
22991da177e4SLinus Torvalds  *     uint32_t                spp_hbinterval;
23001da177e4SLinus Torvalds  *     uint16_t                spp_pathmaxrxt;
230152ccb8e9SFrank Filz  *     uint32_t                spp_pathmtu;
230252ccb8e9SFrank Filz  *     uint32_t                spp_sackdelay;
230352ccb8e9SFrank Filz  *     uint32_t                spp_flags;
23040b0dce7aSXin Long  *     uint32_t                spp_ipv6_flowlabel;
23050b0dce7aSXin Long  *     uint8_t                 spp_dscp;
23061da177e4SLinus Torvalds  * };
23071da177e4SLinus Torvalds  *
230852ccb8e9SFrank Filz  *   spp_assoc_id    - (one-to-many style socket) This is filled in the
230952ccb8e9SFrank Filz  *                     application, and identifies the association for
231052ccb8e9SFrank Filz  *                     this query.
23111da177e4SLinus Torvalds  *   spp_address     - This specifies which address is of interest.
23121da177e4SLinus Torvalds  *   spp_hbinterval  - This contains the value of the heartbeat interval,
231352ccb8e9SFrank Filz  *                     in milliseconds.  If a  value of zero
231452ccb8e9SFrank Filz  *                     is present in this field then no changes are to
231552ccb8e9SFrank Filz  *                     be made to this parameter.
23161da177e4SLinus Torvalds  *   spp_pathmaxrxt  - This contains the maximum number of
23171da177e4SLinus Torvalds  *                     retransmissions before this address shall be
231852ccb8e9SFrank Filz  *                     considered unreachable. If a  value of zero
231952ccb8e9SFrank Filz  *                     is present in this field then no changes are to
232052ccb8e9SFrank Filz  *                     be made to this parameter.
232152ccb8e9SFrank Filz  *   spp_pathmtu     - When Path MTU discovery is disabled the value
232252ccb8e9SFrank Filz  *                     specified here will be the "fixed" path mtu.
232352ccb8e9SFrank Filz  *                     Note that if the spp_address field is empty
232452ccb8e9SFrank Filz  *                     then all associations on this address will
232552ccb8e9SFrank Filz  *                     have this fixed path mtu set upon them.
232652ccb8e9SFrank Filz  *
232752ccb8e9SFrank Filz  *   spp_sackdelay   - When delayed sack is enabled, this value specifies
232852ccb8e9SFrank Filz  *                     the number of milliseconds that sacks will be delayed
232952ccb8e9SFrank Filz  *                     for. This value will apply to all addresses of an
233052ccb8e9SFrank Filz  *                     association if the spp_address field is empty. Note
233152ccb8e9SFrank Filz  *                     also, that if delayed sack is enabled and this
233252ccb8e9SFrank Filz  *                     value is set to 0, no change is made to the last
233352ccb8e9SFrank Filz  *                     recorded delayed sack timer value.
233452ccb8e9SFrank Filz  *
233552ccb8e9SFrank Filz  *   spp_flags       - These flags are used to control various features
233652ccb8e9SFrank Filz  *                     on an association. The flag field may contain
233752ccb8e9SFrank Filz  *                     zero or more of the following options.
233852ccb8e9SFrank Filz  *
233952ccb8e9SFrank Filz  *                     SPP_HB_ENABLE  - Enable heartbeats on the
234052ccb8e9SFrank Filz  *                     specified address. Note that if the address
234152ccb8e9SFrank Filz  *                     field is empty all addresses for the association
234252ccb8e9SFrank Filz  *                     have heartbeats enabled upon them.
234352ccb8e9SFrank Filz  *
234452ccb8e9SFrank Filz  *                     SPP_HB_DISABLE - Disable heartbeats on the
234552ccb8e9SFrank Filz  *                     speicifed address. Note that if the address
234652ccb8e9SFrank Filz  *                     field is empty all addresses for the association
234752ccb8e9SFrank Filz  *                     will have their heartbeats disabled. Note also
234852ccb8e9SFrank Filz  *                     that SPP_HB_ENABLE and SPP_HB_DISABLE are
234952ccb8e9SFrank Filz  *                     mutually exclusive, only one of these two should
235052ccb8e9SFrank Filz  *                     be specified. Enabling both fields will have
235152ccb8e9SFrank Filz  *                     undetermined results.
235252ccb8e9SFrank Filz  *
235352ccb8e9SFrank Filz  *                     SPP_HB_DEMAND - Request a user initiated heartbeat
235452ccb8e9SFrank Filz  *                     to be made immediately.
235552ccb8e9SFrank Filz  *
2356bdf3092aSVlad Yasevich  *                     SPP_HB_TIME_IS_ZERO - Specify's that the time for
2357bdf3092aSVlad Yasevich  *                     heartbeat delayis to be set to the value of 0
2358bdf3092aSVlad Yasevich  *                     milliseconds.
2359bdf3092aSVlad Yasevich  *
236052ccb8e9SFrank Filz  *                     SPP_PMTUD_ENABLE - This field will enable PMTU
236152ccb8e9SFrank Filz  *                     discovery upon the specified address. Note that
236252ccb8e9SFrank Filz  *                     if the address feild is empty then all addresses
236352ccb8e9SFrank Filz  *                     on the association are effected.
236452ccb8e9SFrank Filz  *
236552ccb8e9SFrank Filz  *                     SPP_PMTUD_DISABLE - This field will disable PMTU
236652ccb8e9SFrank Filz  *                     discovery upon the specified address. Note that
236752ccb8e9SFrank Filz  *                     if the address feild is empty then all addresses
236852ccb8e9SFrank Filz  *                     on the association are effected. Not also that
236952ccb8e9SFrank Filz  *                     SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually
237052ccb8e9SFrank Filz  *                     exclusive. Enabling both will have undetermined
237152ccb8e9SFrank Filz  *                     results.
237252ccb8e9SFrank Filz  *
237352ccb8e9SFrank Filz  *                     SPP_SACKDELAY_ENABLE - Setting this flag turns
237452ccb8e9SFrank Filz  *                     on delayed sack. The time specified in spp_sackdelay
237552ccb8e9SFrank Filz  *                     is used to specify the sack delay for this address. Note
237652ccb8e9SFrank Filz  *                     that if spp_address is empty then all addresses will
237752ccb8e9SFrank Filz  *                     enable delayed sack and take on the sack delay
237852ccb8e9SFrank Filz  *                     value specified in spp_sackdelay.
237952ccb8e9SFrank Filz  *                     SPP_SACKDELAY_DISABLE - Setting this flag turns
238052ccb8e9SFrank Filz  *                     off delayed sack. If the spp_address field is blank then
238152ccb8e9SFrank Filz  *                     delayed sack is disabled for the entire association. Note
238252ccb8e9SFrank Filz  *                     also that this field is mutually exclusive to
238352ccb8e9SFrank Filz  *                     SPP_SACKDELAY_ENABLE, setting both will have undefined
238452ccb8e9SFrank Filz  *                     results.
23850b0dce7aSXin Long  *
23860b0dce7aSXin Long  *                     SPP_IPV6_FLOWLABEL:  Setting this flag enables the
23870b0dce7aSXin Long  *                     setting of the IPV6 flow label value.  The value is
23880b0dce7aSXin Long  *                     contained in the spp_ipv6_flowlabel field.
23890b0dce7aSXin Long  *                     Upon retrieval, this flag will be set to indicate that
23900b0dce7aSXin Long  *                     the spp_ipv6_flowlabel field has a valid value returned.
23910b0dce7aSXin Long  *                     If a specific destination address is set (in the
23920b0dce7aSXin Long  *                     spp_address field), then the value returned is that of
23930b0dce7aSXin Long  *                     the address.  If just an association is specified (and
23940b0dce7aSXin Long  *                     no address), then the association's default flow label
23950b0dce7aSXin Long  *                     is returned.  If neither an association nor a destination
23960b0dce7aSXin Long  *                     is specified, then the socket's default flow label is
23970b0dce7aSXin Long  *                     returned.  For non-IPv6 sockets, this flag will be left
23980b0dce7aSXin Long  *                     cleared.
23990b0dce7aSXin Long  *
24000b0dce7aSXin Long  *                     SPP_DSCP:  Setting this flag enables the setting of the
24010b0dce7aSXin Long  *                     Differentiated Services Code Point (DSCP) value
24020b0dce7aSXin Long  *                     associated with either the association or a specific
24030b0dce7aSXin Long  *                     address.  The value is obtained in the spp_dscp field.
24040b0dce7aSXin Long  *                     Upon retrieval, this flag will be set to indicate that
24050b0dce7aSXin Long  *                     the spp_dscp field has a valid value returned.  If a
24060b0dce7aSXin Long  *                     specific destination address is set when called (in the
24070b0dce7aSXin Long  *                     spp_address field), then that specific destination
24080b0dce7aSXin Long  *                     address's DSCP value is returned.  If just an association
24090b0dce7aSXin Long  *                     is specified, then the association's default DSCP is
24100b0dce7aSXin Long  *                     returned.  If neither an association nor a destination is
24110b0dce7aSXin Long  *                     specified, then the socket's default DSCP is returned.
24120b0dce7aSXin Long  *
24130b0dce7aSXin Long  *   spp_ipv6_flowlabel
24140b0dce7aSXin Long  *                   - This field is used in conjunction with the
24150b0dce7aSXin Long  *                     SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label.
24160b0dce7aSXin Long  *                     The 20 least significant bits are used for the flow
24170b0dce7aSXin Long  *                     label.  This setting has precedence over any IPv6-layer
24180b0dce7aSXin Long  *                     setting.
24190b0dce7aSXin Long  *
24200b0dce7aSXin Long  *   spp_dscp        - This field is used in conjunction with the SPP_DSCP flag
24210b0dce7aSXin Long  *                     and contains the DSCP.  The 6 most significant bits are
24220b0dce7aSXin Long  *                     used for the DSCP.  This setting has precedence over any
24230b0dce7aSXin Long  *                     IPv4- or IPv6- layer setting.
24241da177e4SLinus Torvalds  */
sctp_apply_peer_addr_params(struct sctp_paddrparams * params,struct sctp_transport * trans,struct sctp_association * asoc,struct sctp_sock * sp,int hb_change,int pmtud_change,int sackdelay_change)242516164366SAdrian Bunk static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
242652ccb8e9SFrank Filz 				       struct sctp_transport   *trans,
242752ccb8e9SFrank Filz 				       struct sctp_association *asoc,
242852ccb8e9SFrank Filz 				       struct sctp_sock        *sp,
242952ccb8e9SFrank Filz 				       int                      hb_change,
243052ccb8e9SFrank Filz 				       int                      pmtud_change,
243152ccb8e9SFrank Filz 				       int                      sackdelay_change)
243252ccb8e9SFrank Filz {
243352ccb8e9SFrank Filz 	int error;
243452ccb8e9SFrank Filz 
243552ccb8e9SFrank Filz 	if (params->spp_flags & SPP_HB_DEMAND && trans) {
24364e7696d9SXin Long 		error = sctp_primitive_REQUESTHEARTBEAT(trans->asoc->base.net,
24374e7696d9SXin Long 							trans->asoc, trans);
243852ccb8e9SFrank Filz 		if (error)
243952ccb8e9SFrank Filz 			return error;
244052ccb8e9SFrank Filz 	}
244152ccb8e9SFrank Filz 
2442bdf3092aSVlad Yasevich 	/* Note that unless the spp_flag is set to SPP_HB_ENABLE the value of
2443bdf3092aSVlad Yasevich 	 * this field is ignored.  Note also that a value of zero indicates
2444bdf3092aSVlad Yasevich 	 * the current setting should be left unchanged.
2445bdf3092aSVlad Yasevich 	 */
2446bdf3092aSVlad Yasevich 	if (params->spp_flags & SPP_HB_ENABLE) {
2447bdf3092aSVlad Yasevich 
2448bdf3092aSVlad Yasevich 		/* Re-zero the interval if the SPP_HB_TIME_IS_ZERO is
2449bdf3092aSVlad Yasevich 		 * set.  This lets us use 0 value when this flag
2450bdf3092aSVlad Yasevich 		 * is set.
2451bdf3092aSVlad Yasevich 		 */
2452bdf3092aSVlad Yasevich 		if (params->spp_flags & SPP_HB_TIME_IS_ZERO)
2453bdf3092aSVlad Yasevich 			params->spp_hbinterval = 0;
2454bdf3092aSVlad Yasevich 
2455bdf3092aSVlad Yasevich 		if (params->spp_hbinterval ||
2456bdf3092aSVlad Yasevich 		    (params->spp_flags & SPP_HB_TIME_IS_ZERO)) {
245752ccb8e9SFrank Filz 			if (trans) {
2458bdf3092aSVlad Yasevich 				trans->hbinterval =
2459bdf3092aSVlad Yasevich 				    msecs_to_jiffies(params->spp_hbinterval);
24601f4e803cSXin Long 				sctp_transport_reset_hb_timer(trans);
246152ccb8e9SFrank Filz 			} else if (asoc) {
2462bdf3092aSVlad Yasevich 				asoc->hbinterval =
2463bdf3092aSVlad Yasevich 				    msecs_to_jiffies(params->spp_hbinterval);
246452ccb8e9SFrank Filz 			} else {
246552ccb8e9SFrank Filz 				sp->hbinterval = params->spp_hbinterval;
246652ccb8e9SFrank Filz 			}
246752ccb8e9SFrank Filz 		}
2468bdf3092aSVlad Yasevich 	}
246952ccb8e9SFrank Filz 
247052ccb8e9SFrank Filz 	if (hb_change) {
247152ccb8e9SFrank Filz 		if (trans) {
247252ccb8e9SFrank Filz 			trans->param_flags =
247352ccb8e9SFrank Filz 				(trans->param_flags & ~SPP_HB) | hb_change;
247452ccb8e9SFrank Filz 		} else if (asoc) {
247552ccb8e9SFrank Filz 			asoc->param_flags =
247652ccb8e9SFrank Filz 				(asoc->param_flags & ~SPP_HB) | hb_change;
247752ccb8e9SFrank Filz 		} else {
247852ccb8e9SFrank Filz 			sp->param_flags =
247952ccb8e9SFrank Filz 				(sp->param_flags & ~SPP_HB) | hb_change;
248052ccb8e9SFrank Filz 		}
248152ccb8e9SFrank Filz 	}
248252ccb8e9SFrank Filz 
2483bdf3092aSVlad Yasevich 	/* When Path MTU discovery is disabled the value specified here will
2484bdf3092aSVlad Yasevich 	 * be the "fixed" path mtu (i.e. the value of the spp_flags field must
2485bdf3092aSVlad Yasevich 	 * include the flag SPP_PMTUD_DISABLE for this field to have any
2486bdf3092aSVlad Yasevich 	 * effect).
2487bdf3092aSVlad Yasevich 	 */
2488bdf3092aSVlad Yasevich 	if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) {
248952ccb8e9SFrank Filz 		if (trans) {
249052ccb8e9SFrank Filz 			trans->pathmtu = params->spp_pathmtu;
24913ebfdf08SXin Long 			sctp_assoc_sync_pmtu(asoc);
249252ccb8e9SFrank Filz 		} else if (asoc) {
2493c4b2893dSMarcelo Ricardo Leitner 			sctp_assoc_set_pmtu(asoc, params->spp_pathmtu);
249452ccb8e9SFrank Filz 		} else {
249552ccb8e9SFrank Filz 			sp->pathmtu = params->spp_pathmtu;
249652ccb8e9SFrank Filz 		}
249752ccb8e9SFrank Filz 	}
249852ccb8e9SFrank Filz 
249952ccb8e9SFrank Filz 	if (pmtud_change) {
250052ccb8e9SFrank Filz 		if (trans) {
250152ccb8e9SFrank Filz 			int update = (trans->param_flags & SPP_PMTUD_DISABLE) &&
250252ccb8e9SFrank Filz 				(params->spp_flags & SPP_PMTUD_ENABLE);
250352ccb8e9SFrank Filz 			trans->param_flags =
250452ccb8e9SFrank Filz 				(trans->param_flags & ~SPP_PMTUD) | pmtud_change;
250552ccb8e9SFrank Filz 			if (update) {
25069914ae3cSVlad Yasevich 				sctp_transport_pmtu(trans, sctp_opt2sk(sp));
25073ebfdf08SXin Long 				sctp_assoc_sync_pmtu(asoc);
250852ccb8e9SFrank Filz 			}
25097307e4faSXin Long 			sctp_transport_pl_reset(trans);
251052ccb8e9SFrank Filz 		} else if (asoc) {
251152ccb8e9SFrank Filz 			asoc->param_flags =
251252ccb8e9SFrank Filz 				(asoc->param_flags & ~SPP_PMTUD) | pmtud_change;
251352ccb8e9SFrank Filz 		} else {
251452ccb8e9SFrank Filz 			sp->param_flags =
251552ccb8e9SFrank Filz 				(sp->param_flags & ~SPP_PMTUD) | pmtud_change;
251652ccb8e9SFrank Filz 		}
251752ccb8e9SFrank Filz 	}
251852ccb8e9SFrank Filz 
2519bdf3092aSVlad Yasevich 	/* Note that unless the spp_flag is set to SPP_SACKDELAY_ENABLE the
2520bdf3092aSVlad Yasevich 	 * value of this field is ignored.  Note also that a value of zero
2521bdf3092aSVlad Yasevich 	 * indicates the current setting should be left unchanged.
2522bdf3092aSVlad Yasevich 	 */
2523bdf3092aSVlad Yasevich 	if ((params->spp_flags & SPP_SACKDELAY_ENABLE) && params->spp_sackdelay) {
252452ccb8e9SFrank Filz 		if (trans) {
252552ccb8e9SFrank Filz 			trans->sackdelay =
252652ccb8e9SFrank Filz 				msecs_to_jiffies(params->spp_sackdelay);
252752ccb8e9SFrank Filz 		} else if (asoc) {
252852ccb8e9SFrank Filz 			asoc->sackdelay =
252952ccb8e9SFrank Filz 				msecs_to_jiffies(params->spp_sackdelay);
253052ccb8e9SFrank Filz 		} else {
253152ccb8e9SFrank Filz 			sp->sackdelay = params->spp_sackdelay;
253252ccb8e9SFrank Filz 		}
253352ccb8e9SFrank Filz 	}
253452ccb8e9SFrank Filz 
253552ccb8e9SFrank Filz 	if (sackdelay_change) {
253652ccb8e9SFrank Filz 		if (trans) {
253752ccb8e9SFrank Filz 			trans->param_flags =
253852ccb8e9SFrank Filz 				(trans->param_flags & ~SPP_SACKDELAY) |
253952ccb8e9SFrank Filz 				sackdelay_change;
254052ccb8e9SFrank Filz 		} else if (asoc) {
254152ccb8e9SFrank Filz 			asoc->param_flags =
254252ccb8e9SFrank Filz 				(asoc->param_flags & ~SPP_SACKDELAY) |
254352ccb8e9SFrank Filz 				sackdelay_change;
254452ccb8e9SFrank Filz 		} else {
254552ccb8e9SFrank Filz 			sp->param_flags =
254652ccb8e9SFrank Filz 				(sp->param_flags & ~SPP_SACKDELAY) |
254752ccb8e9SFrank Filz 				sackdelay_change;
254852ccb8e9SFrank Filz 		}
254952ccb8e9SFrank Filz 	}
255052ccb8e9SFrank Filz 
255137051f73SAndrei Pelinescu-Onciul 	/* Note that a value of zero indicates the current setting should be
255237051f73SAndrei Pelinescu-Onciul 	   left unchanged.
2553bdf3092aSVlad Yasevich 	 */
255437051f73SAndrei Pelinescu-Onciul 	if (params->spp_pathmaxrxt) {
255552ccb8e9SFrank Filz 		if (trans) {
255652ccb8e9SFrank Filz 			trans->pathmaxrxt = params->spp_pathmaxrxt;
255752ccb8e9SFrank Filz 		} else if (asoc) {
255852ccb8e9SFrank Filz 			asoc->pathmaxrxt = params->spp_pathmaxrxt;
255952ccb8e9SFrank Filz 		} else {
256052ccb8e9SFrank Filz 			sp->pathmaxrxt = params->spp_pathmaxrxt;
256152ccb8e9SFrank Filz 		}
256252ccb8e9SFrank Filz 	}
256352ccb8e9SFrank Filz 
25640b0dce7aSXin Long 	if (params->spp_flags & SPP_IPV6_FLOWLABEL) {
2565741880e1SXin Long 		if (trans) {
2566741880e1SXin Long 			if (trans->ipaddr.sa.sa_family == AF_INET6) {
25670b0dce7aSXin Long 				trans->flowlabel = params->spp_ipv6_flowlabel &
25680b0dce7aSXin Long 						   SCTP_FLOWLABEL_VAL_MASK;
25690b0dce7aSXin Long 				trans->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
2570741880e1SXin Long 			}
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 				if (t->ipaddr.sa.sa_family != AF_INET6)
25770b0dce7aSXin Long 					continue;
2578af8a2b8bSXin Long 				t->flowlabel = params->spp_ipv6_flowlabel &
25790b0dce7aSXin Long 					       SCTP_FLOWLABEL_VAL_MASK;
2580af8a2b8bSXin Long 				t->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
25810b0dce7aSXin Long 			}
25820b0dce7aSXin Long 			asoc->flowlabel = params->spp_ipv6_flowlabel &
25830b0dce7aSXin Long 					  SCTP_FLOWLABEL_VAL_MASK;
25840b0dce7aSXin Long 			asoc->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
25850b0dce7aSXin Long 		} else if (sctp_opt2sk(sp)->sk_family == AF_INET6) {
25860b0dce7aSXin Long 			sp->flowlabel = params->spp_ipv6_flowlabel &
25870b0dce7aSXin Long 					SCTP_FLOWLABEL_VAL_MASK;
25880b0dce7aSXin Long 			sp->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
25890b0dce7aSXin Long 		}
25900b0dce7aSXin Long 	}
25910b0dce7aSXin Long 
25920b0dce7aSXin Long 	if (params->spp_flags & SPP_DSCP) {
25930b0dce7aSXin Long 		if (trans) {
25940b0dce7aSXin Long 			trans->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK;
25950b0dce7aSXin Long 			trans->dscp |= SCTP_DSCP_SET_MASK;
25960b0dce7aSXin Long 		} else if (asoc) {
2597af8a2b8bSXin Long 			struct sctp_transport *t;
2598af8a2b8bSXin Long 
2599af8a2b8bSXin Long 			list_for_each_entry(t, &asoc->peer.transport_addr_list,
26000b0dce7aSXin Long 					    transports) {
2601af8a2b8bSXin Long 				t->dscp = params->spp_dscp &
26020b0dce7aSXin Long 					  SCTP_DSCP_VAL_MASK;
2603af8a2b8bSXin Long 				t->dscp |= SCTP_DSCP_SET_MASK;
26040b0dce7aSXin Long 			}
26050b0dce7aSXin Long 			asoc->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK;
26060b0dce7aSXin Long 			asoc->dscp |= SCTP_DSCP_SET_MASK;
26070b0dce7aSXin Long 		} else {
26080b0dce7aSXin Long 			sp->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK;
26090b0dce7aSXin Long 			sp->dscp |= SCTP_DSCP_SET_MASK;
26100b0dce7aSXin Long 		}
26110b0dce7aSXin Long 	}
26120b0dce7aSXin Long 
261352ccb8e9SFrank Filz 	return 0;
261452ccb8e9SFrank Filz }
261552ccb8e9SFrank Filz 
sctp_setsockopt_peer_addr_params(struct sock * sk,struct sctp_paddrparams * params,unsigned int optlen)26161da177e4SLinus Torvalds static int sctp_setsockopt_peer_addr_params(struct sock *sk,
26179b7b0d1aSChristoph Hellwig 					    struct sctp_paddrparams *params,
2618b7058842SDavid S. Miller 					    unsigned int optlen)
26191da177e4SLinus Torvalds {
262052ccb8e9SFrank Filz 	struct sctp_transport   *trans = NULL;
262152ccb8e9SFrank Filz 	struct sctp_association *asoc = NULL;
262252ccb8e9SFrank Filz 	struct sctp_sock        *sp = sctp_sk(sk);
26231da177e4SLinus Torvalds 	int error;
262452ccb8e9SFrank Filz 	int hb_change, pmtud_change, sackdelay_change;
26251da177e4SLinus Torvalds 
26269b7b0d1aSChristoph Hellwig 	if (optlen == ALIGN(offsetof(struct sctp_paddrparams,
26270b0dce7aSXin Long 					    spp_ipv6_flowlabel), 4)) {
26289b7b0d1aSChristoph Hellwig 		if (params->spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL))
26290b0dce7aSXin Long 			return -EINVAL;
26309b7b0d1aSChristoph Hellwig 	} else if (optlen != sizeof(*params)) {
26310b0dce7aSXin Long 		return -EINVAL;
26320b0dce7aSXin Long 	}
26331da177e4SLinus Torvalds 
263452ccb8e9SFrank Filz 	/* Validate flags and value parameters. */
26359b7b0d1aSChristoph Hellwig 	hb_change        = params->spp_flags & SPP_HB;
26369b7b0d1aSChristoph Hellwig 	pmtud_change     = params->spp_flags & SPP_PMTUD;
26379b7b0d1aSChristoph Hellwig 	sackdelay_change = params->spp_flags & SPP_SACKDELAY;
26381da177e4SLinus Torvalds 
263952ccb8e9SFrank Filz 	if (hb_change        == SPP_HB ||
264052ccb8e9SFrank Filz 	    pmtud_change     == SPP_PMTUD ||
264152ccb8e9SFrank Filz 	    sackdelay_change == SPP_SACKDELAY ||
26429b7b0d1aSChristoph Hellwig 	    params->spp_sackdelay > 500 ||
26439b7b0d1aSChristoph Hellwig 	    (params->spp_pathmtu &&
26449b7b0d1aSChristoph Hellwig 	     params->spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
26451da177e4SLinus Torvalds 		return -EINVAL;
26461da177e4SLinus Torvalds 
264752ccb8e9SFrank Filz 	/* If an address other than INADDR_ANY is specified, and
264852ccb8e9SFrank Filz 	 * no transport is found, then the request is invalid.
264952ccb8e9SFrank Filz 	 */
26509b7b0d1aSChristoph Hellwig 	if (!sctp_is_any(sk, (union sctp_addr *)&params->spp_address)) {
26519b7b0d1aSChristoph Hellwig 		trans = sctp_addr_id2transport(sk, &params->spp_address,
26529b7b0d1aSChristoph Hellwig 					       params->spp_assoc_id);
26531da177e4SLinus Torvalds 		if (!trans)
26541da177e4SLinus Torvalds 			return -EINVAL;
26551da177e4SLinus Torvalds 	}
26561da177e4SLinus Torvalds 
2657b99e5e02SXin Long 	/* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the
2658b99e5e02SXin Long 	 * socket is a one to many style socket, and an association
2659b99e5e02SXin Long 	 * was not found, then the id was invalid.
26601da177e4SLinus Torvalds 	 */
26619b7b0d1aSChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->spp_assoc_id);
26629b7b0d1aSChristoph Hellwig 	if (!asoc && params->spp_assoc_id != SCTP_FUTURE_ASSOC &&
2663b99e5e02SXin Long 	    sctp_style(sk, UDP))
266452ccb8e9SFrank Filz 		return -EINVAL;
266552ccb8e9SFrank Filz 
266652ccb8e9SFrank Filz 	/* Heartbeat demand can only be sent on a transport or
266752ccb8e9SFrank Filz 	 * association, but not a socket.
266852ccb8e9SFrank Filz 	 */
26699b7b0d1aSChristoph Hellwig 	if (params->spp_flags & SPP_HB_DEMAND && !trans && !asoc)
267052ccb8e9SFrank Filz 		return -EINVAL;
267152ccb8e9SFrank Filz 
267252ccb8e9SFrank Filz 	/* Process parameters. */
26739b7b0d1aSChristoph Hellwig 	error = sctp_apply_peer_addr_params(params, trans, asoc, sp,
267452ccb8e9SFrank Filz 					    hb_change, pmtud_change,
267552ccb8e9SFrank Filz 					    sackdelay_change);
267652ccb8e9SFrank Filz 
267752ccb8e9SFrank Filz 	if (error)
267852ccb8e9SFrank Filz 		return error;
267952ccb8e9SFrank Filz 
268052ccb8e9SFrank Filz 	/* If changes are for association, also apply parameters to each
268152ccb8e9SFrank Filz 	 * transport.
268252ccb8e9SFrank Filz 	 */
268352ccb8e9SFrank Filz 	if (!trans && asoc) {
26849dbc15f0SRobert P. J. Day 		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
26859dbc15f0SRobert P. J. Day 				transports) {
26869b7b0d1aSChristoph Hellwig 			sctp_apply_peer_addr_params(params, trans, asoc, sp,
268752ccb8e9SFrank Filz 						    hb_change, pmtud_change,
268852ccb8e9SFrank Filz 						    sackdelay_change);
268952ccb8e9SFrank Filz 		}
269052ccb8e9SFrank Filz 	}
26911da177e4SLinus Torvalds 
26921da177e4SLinus Torvalds 	return 0;
26931da177e4SLinus Torvalds }
26941da177e4SLinus Torvalds 
sctp_spp_sackdelay_enable(__u32 param_flags)26950ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags)
26960ea5e4dfSwangweidong {
26970ea5e4dfSwangweidong 	return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE;
26980ea5e4dfSwangweidong }
26990ea5e4dfSwangweidong 
sctp_spp_sackdelay_disable(__u32 param_flags)27000ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags)
27010ea5e4dfSwangweidong {
27020ea5e4dfSwangweidong 	return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE;
27030ea5e4dfSwangweidong }
27040ea5e4dfSwangweidong 
sctp_apply_asoc_delayed_ack(struct sctp_sack_info * params,struct sctp_association * asoc)27059c5829e1SXin Long static void sctp_apply_asoc_delayed_ack(struct sctp_sack_info *params,
27069c5829e1SXin Long 					struct sctp_association *asoc)
27079c5829e1SXin Long {
27089c5829e1SXin Long 	struct sctp_transport *trans;
27099c5829e1SXin Long 
27109c5829e1SXin Long 	if (params->sack_delay) {
27119c5829e1SXin Long 		asoc->sackdelay = msecs_to_jiffies(params->sack_delay);
27129c5829e1SXin Long 		asoc->param_flags =
27139c5829e1SXin Long 			sctp_spp_sackdelay_enable(asoc->param_flags);
27149c5829e1SXin Long 	}
27159c5829e1SXin Long 	if (params->sack_freq == 1) {
27169c5829e1SXin Long 		asoc->param_flags =
27179c5829e1SXin Long 			sctp_spp_sackdelay_disable(asoc->param_flags);
27189c5829e1SXin Long 	} else if (params->sack_freq > 1) {
27199c5829e1SXin Long 		asoc->sackfreq = params->sack_freq;
27209c5829e1SXin Long 		asoc->param_flags =
27219c5829e1SXin Long 			sctp_spp_sackdelay_enable(asoc->param_flags);
27229c5829e1SXin Long 	}
27239c5829e1SXin Long 
27249c5829e1SXin Long 	list_for_each_entry(trans, &asoc->peer.transport_addr_list,
27259c5829e1SXin Long 			    transports) {
27269c5829e1SXin Long 		if (params->sack_delay) {
27279c5829e1SXin Long 			trans->sackdelay = msecs_to_jiffies(params->sack_delay);
27289c5829e1SXin Long 			trans->param_flags =
27299c5829e1SXin Long 				sctp_spp_sackdelay_enable(trans->param_flags);
27309c5829e1SXin Long 		}
27319c5829e1SXin Long 		if (params->sack_freq == 1) {
27329c5829e1SXin Long 			trans->param_flags =
27339c5829e1SXin Long 				sctp_spp_sackdelay_disable(trans->param_flags);
27349c5829e1SXin Long 		} else if (params->sack_freq > 1) {
27359c5829e1SXin Long 			trans->sackfreq = params->sack_freq;
27369c5829e1SXin Long 			trans->param_flags =
27379c5829e1SXin Long 				sctp_spp_sackdelay_enable(trans->param_flags);
27389c5829e1SXin Long 		}
27399c5829e1SXin Long 	}
27409c5829e1SXin Long }
27419c5829e1SXin Long 
2742d364d927SWei Yongjun /*
2743d364d927SWei Yongjun  * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
27447708610bSFrank Filz  *
2745d364d927SWei Yongjun  * This option will effect the way delayed acks are performed.  This
2746d364d927SWei Yongjun  * option allows you to get or set the delayed ack time, in
2747d364d927SWei Yongjun  * milliseconds.  It also allows changing the delayed ack frequency.
2748d364d927SWei Yongjun  * Changing the frequency to 1 disables the delayed sack algorithm.  If
2749d364d927SWei Yongjun  * the assoc_id is 0, then this sets or gets the endpoints default
2750d364d927SWei Yongjun  * values.  If the assoc_id field is non-zero, then the set or get
2751d364d927SWei Yongjun  * effects the specified association for the one to many model (the
2752d364d927SWei Yongjun  * assoc_id field is ignored by the one to one model).  Note that if
2753d364d927SWei Yongjun  * sack_delay or sack_freq are 0 when setting this option, then the
2754d364d927SWei Yongjun  * current values will remain unchanged.
27557708610bSFrank Filz  *
2756d364d927SWei Yongjun  * struct sctp_sack_info {
2757d364d927SWei Yongjun  *     sctp_assoc_t            sack_assoc_id;
2758d364d927SWei Yongjun  *     uint32_t                sack_delay;
2759d364d927SWei Yongjun  *     uint32_t                sack_freq;
27607708610bSFrank Filz  * };
27617708610bSFrank Filz  *
2762d364d927SWei Yongjun  * sack_assoc_id -  This parameter, indicates which association the user
2763d364d927SWei Yongjun  *    is performing an action upon.  Note that if this field's value is
2764d364d927SWei Yongjun  *    zero then the endpoints default value is changed (effecting future
27657708610bSFrank Filz  *    associations only).
27667708610bSFrank Filz  *
2767d364d927SWei Yongjun  * sack_delay -  This parameter contains the number of milliseconds that
2768d364d927SWei Yongjun  *    the user is requesting the delayed ACK timer be set to.  Note that
2769d364d927SWei Yongjun  *    this value is defined in the standard to be between 200 and 500
2770d364d927SWei Yongjun  *    milliseconds.
27717708610bSFrank Filz  *
2772d364d927SWei Yongjun  * sack_freq -  This parameter contains the number of packets that must
2773d364d927SWei Yongjun  *    be received before a sack is sent without waiting for the delay
2774d364d927SWei Yongjun  *    timer to expire.  The default value for this is 2, setting this
2775d364d927SWei Yongjun  *    value to 1 will disable the delayed sack algorithm.
27767708610bSFrank Filz  */
__sctp_setsockopt_delayed_ack(struct sock * sk,struct sctp_sack_info * params)2777dfd3d526SChristoph Hellwig static int __sctp_setsockopt_delayed_ack(struct sock *sk,
2778dfd3d526SChristoph Hellwig 					 struct sctp_sack_info *params)
27797708610bSFrank Filz {
27807708610bSFrank Filz 	struct sctp_sock *sp = sctp_sk(sk);
27819c5829e1SXin Long 	struct sctp_association *asoc;
27827708610bSFrank Filz 
2783d364d927SWei Yongjun 	/* Validate value parameter. */
2784ebb25defSChristoph Hellwig 	if (params->sack_delay > 500)
2785d364d927SWei Yongjun 		return -EINVAL;
2786d364d927SWei Yongjun 
27879c5829e1SXin Long 	/* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the
27889c5829e1SXin Long 	 * socket is a one to many style socket, and an association
27899c5829e1SXin Long 	 * was not found, then the id was invalid.
27907708610bSFrank Filz 	 */
2791ebb25defSChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->sack_assoc_id);
2792ebb25defSChristoph Hellwig 	if (!asoc && params->sack_assoc_id > SCTP_ALL_ASSOC &&
27939c5829e1SXin Long 	    sctp_style(sk, UDP))
27947708610bSFrank Filz 		return -EINVAL;
27957708610bSFrank Filz 
27967708610bSFrank Filz 	if (asoc) {
2797ebb25defSChristoph Hellwig 		sctp_apply_asoc_delayed_ack(params, asoc);
27989c5829e1SXin Long 
27999c5829e1SXin Long 		return 0;
28009c5829e1SXin Long 	}
28019c5829e1SXin Long 
28028e2614fcSXin Long 	if (sctp_style(sk, TCP))
2803ebb25defSChristoph Hellwig 		params->sack_assoc_id = SCTP_FUTURE_ASSOC;
28048e2614fcSXin Long 
2805ebb25defSChristoph Hellwig 	if (params->sack_assoc_id == SCTP_FUTURE_ASSOC ||
2806ebb25defSChristoph Hellwig 	    params->sack_assoc_id == SCTP_ALL_ASSOC) {
2807ebb25defSChristoph Hellwig 		if (params->sack_delay) {
2808ebb25defSChristoph Hellwig 			sp->sackdelay = params->sack_delay;
28097708610bSFrank Filz 			sp->param_flags =
28100ea5e4dfSwangweidong 				sctp_spp_sackdelay_enable(sp->param_flags);
28117708610bSFrank Filz 		}
2812ebb25defSChristoph Hellwig 		if (params->sack_freq == 1) {
28137708610bSFrank Filz 			sp->param_flags =
28140ea5e4dfSwangweidong 				sctp_spp_sackdelay_disable(sp->param_flags);
2815ebb25defSChristoph Hellwig 		} else if (params->sack_freq > 1) {
2816ebb25defSChristoph Hellwig 			sp->sackfreq = params->sack_freq;
2817d364d927SWei Yongjun 			sp->param_flags =
28180ea5e4dfSwangweidong 				sctp_spp_sackdelay_enable(sp->param_flags);
2819d364d927SWei Yongjun 		}
28207708610bSFrank Filz 	}
28217708610bSFrank Filz 
2822ebb25defSChristoph Hellwig 	if (params->sack_assoc_id == SCTP_CURRENT_ASSOC ||
2823ebb25defSChristoph Hellwig 	    params->sack_assoc_id == SCTP_ALL_ASSOC)
28249c5829e1SXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs)
2825ebb25defSChristoph Hellwig 			sctp_apply_asoc_delayed_ack(params, asoc);
28267708610bSFrank Filz 
28277708610bSFrank Filz 	return 0;
28287708610bSFrank Filz }
28297708610bSFrank Filz 
sctp_setsockopt_delayed_ack(struct sock * sk,struct sctp_sack_info * params,unsigned int optlen)2830dfd3d526SChristoph Hellwig static int sctp_setsockopt_delayed_ack(struct sock *sk,
2831dfd3d526SChristoph Hellwig 				       struct sctp_sack_info *params,
2832dfd3d526SChristoph Hellwig 				       unsigned int optlen)
2833dfd3d526SChristoph Hellwig {
2834dfd3d526SChristoph Hellwig 	if (optlen == sizeof(struct sctp_assoc_value)) {
2835dfd3d526SChristoph Hellwig 		struct sctp_assoc_value *v = (struct sctp_assoc_value *)params;
2836dfd3d526SChristoph Hellwig 		struct sctp_sack_info p;
2837dfd3d526SChristoph Hellwig 
2838dfd3d526SChristoph Hellwig 		pr_warn_ratelimited(DEPRECATED
2839dfd3d526SChristoph Hellwig 				    "%s (pid %d) "
2840dfd3d526SChristoph Hellwig 				    "Use of struct sctp_assoc_value in delayed_ack socket option.\n"
2841dfd3d526SChristoph Hellwig 				    "Use struct sctp_sack_info instead\n",
2842dfd3d526SChristoph Hellwig 				    current->comm, task_pid_nr(current));
2843dfd3d526SChristoph Hellwig 
2844dfd3d526SChristoph Hellwig 		p.sack_assoc_id = v->assoc_id;
2845dfd3d526SChristoph Hellwig 		p.sack_delay = v->assoc_value;
2846dfd3d526SChristoph Hellwig 		p.sack_freq = v->assoc_value ? 0 : 1;
2847dfd3d526SChristoph Hellwig 		return __sctp_setsockopt_delayed_ack(sk, &p);
2848dfd3d526SChristoph Hellwig 	}
2849dfd3d526SChristoph Hellwig 
2850dfd3d526SChristoph Hellwig 	if (optlen != sizeof(struct sctp_sack_info))
2851dfd3d526SChristoph Hellwig 		return -EINVAL;
2852dfd3d526SChristoph Hellwig 	if (params->sack_delay == 0 && params->sack_freq == 0)
2853dfd3d526SChristoph Hellwig 		return 0;
2854dfd3d526SChristoph Hellwig 	return __sctp_setsockopt_delayed_ack(sk, params);
2855dfd3d526SChristoph Hellwig }
2856dfd3d526SChristoph Hellwig 
28571da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG)
28581da177e4SLinus Torvalds  *
28591da177e4SLinus Torvalds  * Applications can specify protocol parameters for the default association
28601da177e4SLinus Torvalds  * initialization.  The option name argument to setsockopt() and getsockopt()
28611da177e4SLinus Torvalds  * is SCTP_INITMSG.
28621da177e4SLinus Torvalds  *
28631da177e4SLinus Torvalds  * Setting initialization parameters is effective only on an unconnected
28641da177e4SLinus Torvalds  * socket (for UDP-style sockets only future associations are effected
28651da177e4SLinus Torvalds  * by the change).  With TCP-style sockets, this option is inherited by
28661da177e4SLinus Torvalds  * sockets derived from a listener socket.
28671da177e4SLinus Torvalds  */
sctp_setsockopt_initmsg(struct sock * sk,struct sctp_initmsg * sinit,unsigned int optlen)28689dfa6f04SChristoph Hellwig static int sctp_setsockopt_initmsg(struct sock *sk, struct sctp_initmsg *sinit,
28699dfa6f04SChristoph Hellwig 				   unsigned int optlen)
28701da177e4SLinus Torvalds {
28711da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
28721da177e4SLinus Torvalds 
28731da177e4SLinus Torvalds 	if (optlen != sizeof(struct sctp_initmsg))
28741da177e4SLinus Torvalds 		return -EINVAL;
28751da177e4SLinus Torvalds 
28769dfa6f04SChristoph Hellwig 	if (sinit->sinit_num_ostreams)
28779dfa6f04SChristoph Hellwig 		sp->initmsg.sinit_num_ostreams = sinit->sinit_num_ostreams;
28789dfa6f04SChristoph Hellwig 	if (sinit->sinit_max_instreams)
28799dfa6f04SChristoph Hellwig 		sp->initmsg.sinit_max_instreams = sinit->sinit_max_instreams;
28809dfa6f04SChristoph Hellwig 	if (sinit->sinit_max_attempts)
28819dfa6f04SChristoph Hellwig 		sp->initmsg.sinit_max_attempts = sinit->sinit_max_attempts;
28829dfa6f04SChristoph Hellwig 	if (sinit->sinit_max_init_timeo)
28839dfa6f04SChristoph Hellwig 		sp->initmsg.sinit_max_init_timeo = sinit->sinit_max_init_timeo;
28841da177e4SLinus Torvalds 
28851da177e4SLinus Torvalds 	return 0;
28861da177e4SLinus Torvalds }
28871da177e4SLinus Torvalds 
28881da177e4SLinus Torvalds /*
28891da177e4SLinus Torvalds  * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM)
28901da177e4SLinus Torvalds  *
28911da177e4SLinus Torvalds  *   Applications that wish to use the sendto() system call may wish to
28921da177e4SLinus Torvalds  *   specify a default set of parameters that would normally be supplied
28931da177e4SLinus Torvalds  *   through the inclusion of ancillary data.  This socket option allows
28941da177e4SLinus Torvalds  *   such an application to set the default sctp_sndrcvinfo structure.
28951da177e4SLinus Torvalds  *   The application that wishes to use this socket option simply passes
28961da177e4SLinus Torvalds  *   in to this call the sctp_sndrcvinfo structure defined in Section
28971da177e4SLinus Torvalds  *   5.2.2) The input parameters accepted by this call include
28981da177e4SLinus Torvalds  *   sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
28991da177e4SLinus Torvalds  *   sinfo_timetolive.  The user must provide the sinfo_assoc_id field in
29001da177e4SLinus Torvalds  *   to this call if the caller is using the UDP model.
29011da177e4SLinus Torvalds  */
sctp_setsockopt_default_send_param(struct sock * sk,struct sctp_sndrcvinfo * info,unsigned int optlen)29021da177e4SLinus Torvalds static int sctp_setsockopt_default_send_param(struct sock *sk,
2903c23ad6d2SChristoph Hellwig 					      struct sctp_sndrcvinfo *info,
2904b7058842SDavid S. Miller 					      unsigned int optlen)
29051da177e4SLinus Torvalds {
29061da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
29076b3fd5f3SGeir Ola Vaagland 	struct sctp_association *asoc;
29081da177e4SLinus Torvalds 
2909c23ad6d2SChristoph Hellwig 	if (optlen != sizeof(*info))
29101da177e4SLinus Torvalds 		return -EINVAL;
2911c23ad6d2SChristoph Hellwig 	if (info->sinfo_flags &
29126b3fd5f3SGeir Ola Vaagland 	    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
29136b3fd5f3SGeir Ola Vaagland 	      SCTP_ABORT | SCTP_EOF))
29146b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
29151da177e4SLinus Torvalds 
2916c23ad6d2SChristoph Hellwig 	asoc = sctp_id2assoc(sk, info->sinfo_assoc_id);
2917c23ad6d2SChristoph Hellwig 	if (!asoc && info->sinfo_assoc_id > SCTP_ALL_ASSOC &&
2918707e45b3SXin Long 	    sctp_style(sk, UDP))
29191da177e4SLinus Torvalds 		return -EINVAL;
2920707e45b3SXin Long 
29211da177e4SLinus Torvalds 	if (asoc) {
2922c23ad6d2SChristoph Hellwig 		asoc->default_stream = info->sinfo_stream;
2923c23ad6d2SChristoph Hellwig 		asoc->default_flags = info->sinfo_flags;
2924c23ad6d2SChristoph Hellwig 		asoc->default_ppid = info->sinfo_ppid;
2925c23ad6d2SChristoph Hellwig 		asoc->default_context = info->sinfo_context;
2926c23ad6d2SChristoph Hellwig 		asoc->default_timetolive = info->sinfo_timetolive;
2927707e45b3SXin Long 
2928707e45b3SXin Long 		return 0;
2929707e45b3SXin Long 	}
2930707e45b3SXin Long 
29311354e72fSMarcelo Ricardo Leitner 	if (sctp_style(sk, TCP))
2932c23ad6d2SChristoph Hellwig 		info->sinfo_assoc_id = SCTP_FUTURE_ASSOC;
29331354e72fSMarcelo Ricardo Leitner 
2934c23ad6d2SChristoph Hellwig 	if (info->sinfo_assoc_id == SCTP_FUTURE_ASSOC ||
2935c23ad6d2SChristoph Hellwig 	    info->sinfo_assoc_id == SCTP_ALL_ASSOC) {
2936c23ad6d2SChristoph Hellwig 		sp->default_stream = info->sinfo_stream;
2937c23ad6d2SChristoph Hellwig 		sp->default_flags = info->sinfo_flags;
2938c23ad6d2SChristoph Hellwig 		sp->default_ppid = info->sinfo_ppid;
2939c23ad6d2SChristoph Hellwig 		sp->default_context = info->sinfo_context;
2940c23ad6d2SChristoph Hellwig 		sp->default_timetolive = info->sinfo_timetolive;
29411da177e4SLinus Torvalds 	}
29421da177e4SLinus Torvalds 
2943c23ad6d2SChristoph Hellwig 	if (info->sinfo_assoc_id == SCTP_CURRENT_ASSOC ||
2944c23ad6d2SChristoph Hellwig 	    info->sinfo_assoc_id == SCTP_ALL_ASSOC) {
2945707e45b3SXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
2946c23ad6d2SChristoph Hellwig 			asoc->default_stream = info->sinfo_stream;
2947c23ad6d2SChristoph Hellwig 			asoc->default_flags = info->sinfo_flags;
2948c23ad6d2SChristoph Hellwig 			asoc->default_ppid = info->sinfo_ppid;
2949c23ad6d2SChristoph Hellwig 			asoc->default_context = info->sinfo_context;
2950c23ad6d2SChristoph Hellwig 			asoc->default_timetolive = info->sinfo_timetolive;
2951707e45b3SXin Long 		}
2952707e45b3SXin Long 	}
2953707e45b3SXin Long 
29541da177e4SLinus Torvalds 	return 0;
29551da177e4SLinus Torvalds }
29561da177e4SLinus Torvalds 
29576b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters
29586b3fd5f3SGeir Ola Vaagland  * (SCTP_DEFAULT_SNDINFO)
29596b3fd5f3SGeir Ola Vaagland  */
sctp_setsockopt_default_sndinfo(struct sock * sk,struct sctp_sndinfo * info,unsigned int optlen)29606b3fd5f3SGeir Ola Vaagland static int sctp_setsockopt_default_sndinfo(struct sock *sk,
29618a2409d3SChristoph Hellwig 					   struct sctp_sndinfo *info,
29626b3fd5f3SGeir Ola Vaagland 					   unsigned int optlen)
29636b3fd5f3SGeir Ola Vaagland {
29646b3fd5f3SGeir Ola Vaagland 	struct sctp_sock *sp = sctp_sk(sk);
29656b3fd5f3SGeir Ola Vaagland 	struct sctp_association *asoc;
29666b3fd5f3SGeir Ola Vaagland 
29678a2409d3SChristoph Hellwig 	if (optlen != sizeof(*info))
29686b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
29698a2409d3SChristoph Hellwig 	if (info->snd_flags &
29706b3fd5f3SGeir Ola Vaagland 	    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
29716b3fd5f3SGeir Ola Vaagland 	      SCTP_ABORT | SCTP_EOF))
29726b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
29736b3fd5f3SGeir Ola Vaagland 
29748a2409d3SChristoph Hellwig 	asoc = sctp_id2assoc(sk, info->snd_assoc_id);
29758a2409d3SChristoph Hellwig 	if (!asoc && info->snd_assoc_id > SCTP_ALL_ASSOC &&
297692fc3bd9SXin Long 	    sctp_style(sk, UDP))
29776b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
297892fc3bd9SXin Long 
29796b3fd5f3SGeir Ola Vaagland 	if (asoc) {
29808a2409d3SChristoph Hellwig 		asoc->default_stream = info->snd_sid;
29818a2409d3SChristoph Hellwig 		asoc->default_flags = info->snd_flags;
29828a2409d3SChristoph Hellwig 		asoc->default_ppid = info->snd_ppid;
29838a2409d3SChristoph Hellwig 		asoc->default_context = info->snd_context;
298492fc3bd9SXin Long 
298592fc3bd9SXin Long 		return 0;
298692fc3bd9SXin Long 	}
298792fc3bd9SXin Long 
2988a842e65bSXin Long 	if (sctp_style(sk, TCP))
29898a2409d3SChristoph Hellwig 		info->snd_assoc_id = SCTP_FUTURE_ASSOC;
2990a842e65bSXin Long 
29918a2409d3SChristoph Hellwig 	if (info->snd_assoc_id == SCTP_FUTURE_ASSOC ||
29928a2409d3SChristoph Hellwig 	    info->snd_assoc_id == SCTP_ALL_ASSOC) {
29938a2409d3SChristoph Hellwig 		sp->default_stream = info->snd_sid;
29948a2409d3SChristoph Hellwig 		sp->default_flags = info->snd_flags;
29958a2409d3SChristoph Hellwig 		sp->default_ppid = info->snd_ppid;
29968a2409d3SChristoph Hellwig 		sp->default_context = info->snd_context;
29976b3fd5f3SGeir Ola Vaagland 	}
29986b3fd5f3SGeir Ola Vaagland 
29998a2409d3SChristoph Hellwig 	if (info->snd_assoc_id == SCTP_CURRENT_ASSOC ||
30008a2409d3SChristoph Hellwig 	    info->snd_assoc_id == SCTP_ALL_ASSOC) {
300192fc3bd9SXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
30028a2409d3SChristoph Hellwig 			asoc->default_stream = info->snd_sid;
30038a2409d3SChristoph Hellwig 			asoc->default_flags = info->snd_flags;
30048a2409d3SChristoph Hellwig 			asoc->default_ppid = info->snd_ppid;
30058a2409d3SChristoph Hellwig 			asoc->default_context = info->snd_context;
300692fc3bd9SXin Long 		}
300792fc3bd9SXin Long 	}
300892fc3bd9SXin Long 
30096b3fd5f3SGeir Ola Vaagland 	return 0;
30106b3fd5f3SGeir Ola Vaagland }
30116b3fd5f3SGeir Ola Vaagland 
30121da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
30131da177e4SLinus Torvalds  *
30141da177e4SLinus Torvalds  * Requests that the local SCTP stack use the enclosed peer address as
30151da177e4SLinus Torvalds  * the association primary.  The enclosed address must be one of the
30161da177e4SLinus Torvalds  * association peer's addresses.
30171da177e4SLinus Torvalds  */
sctp_setsockopt_primary_addr(struct sock * sk,struct sctp_prim * prim,unsigned int optlen)30181eec6958SChristoph Hellwig static int sctp_setsockopt_primary_addr(struct sock *sk, struct sctp_prim *prim,
3019b7058842SDavid S. Miller 					unsigned int optlen)
30201da177e4SLinus Torvalds {
30211da177e4SLinus Torvalds 	struct sctp_transport *trans;
30222277c7cdSRichard Haines 	struct sctp_af *af;
30232277c7cdSRichard Haines 	int err;
30241da177e4SLinus Torvalds 
30251da177e4SLinus Torvalds 	if (optlen != sizeof(struct sctp_prim))
30261da177e4SLinus Torvalds 		return -EINVAL;
30271da177e4SLinus Torvalds 
30282277c7cdSRichard Haines 	/* Allow security module to validate address but need address len. */
30291eec6958SChristoph Hellwig 	af = sctp_get_af_specific(prim->ssp_addr.ss_family);
30302277c7cdSRichard Haines 	if (!af)
30312277c7cdSRichard Haines 		return -EINVAL;
30322277c7cdSRichard Haines 
30332277c7cdSRichard Haines 	err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR,
30341eec6958SChristoph Hellwig 					 (struct sockaddr *)&prim->ssp_addr,
30352277c7cdSRichard Haines 					 af->sockaddr_len);
30362277c7cdSRichard Haines 	if (err)
30372277c7cdSRichard Haines 		return err;
30382277c7cdSRichard Haines 
30391eec6958SChristoph Hellwig 	trans = sctp_addr_id2transport(sk, &prim->ssp_addr, prim->ssp_assoc_id);
30401da177e4SLinus Torvalds 	if (!trans)
30411da177e4SLinus Torvalds 		return -EINVAL;
30421da177e4SLinus Torvalds 
30431da177e4SLinus Torvalds 	sctp_assoc_set_primary(trans->asoc, trans);
30441da177e4SLinus Torvalds 
30451da177e4SLinus Torvalds 	return 0;
30461da177e4SLinus Torvalds }
30471da177e4SLinus Torvalds 
30481da177e4SLinus Torvalds /*
30491da177e4SLinus Torvalds  * 7.1.5 SCTP_NODELAY
30501da177e4SLinus Torvalds  *
30511da177e4SLinus Torvalds  * Turn on/off any Nagle-like algorithm.  This means that packets are
30521da177e4SLinus Torvalds  * generally sent as soon as possible and no unnecessary delays are
30531da177e4SLinus Torvalds  * introduced, at the cost of more packets in the network.  Expects an
30541da177e4SLinus Torvalds  *  integer boolean flag.
30551da177e4SLinus Torvalds  */
sctp_setsockopt_nodelay(struct sock * sk,int * val,unsigned int optlen)3056f87ddbc0SChristoph Hellwig static int sctp_setsockopt_nodelay(struct sock *sk, int *val,
3057b7058842SDavid S. Miller 				   unsigned int optlen)
30581da177e4SLinus Torvalds {
30591da177e4SLinus Torvalds 	if (optlen < sizeof(int))
30601da177e4SLinus Torvalds 		return -EINVAL;
3061f87ddbc0SChristoph Hellwig 	sctp_sk(sk)->nodelay = (*val == 0) ? 0 : 1;
30621da177e4SLinus Torvalds 	return 0;
30631da177e4SLinus Torvalds }
30641da177e4SLinus Torvalds 
30651da177e4SLinus Torvalds /*
30661da177e4SLinus Torvalds  *
30671da177e4SLinus Torvalds  * 7.1.1 SCTP_RTOINFO
30681da177e4SLinus Torvalds  *
30691da177e4SLinus Torvalds  * The protocol parameters used to initialize and bound retransmission
30701da177e4SLinus Torvalds  * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access
30711da177e4SLinus Torvalds  * and modify these parameters.
30721da177e4SLinus Torvalds  * All parameters are time values, in milliseconds.  A value of 0, when
30731da177e4SLinus Torvalds  * modifying the parameters, indicates that the current value should not
30741da177e4SLinus Torvalds  * be changed.
30751da177e4SLinus Torvalds  *
30761da177e4SLinus Torvalds  */
sctp_setsockopt_rtoinfo(struct sock * sk,struct sctp_rtoinfo * rtoinfo,unsigned int optlen)3077af5ae60eSChristoph Hellwig static int sctp_setsockopt_rtoinfo(struct sock *sk,
3078af5ae60eSChristoph Hellwig 				   struct sctp_rtoinfo *rtoinfo,
3079af5ae60eSChristoph Hellwig 				   unsigned int optlen)
3080b7058842SDavid S. Miller {
30811da177e4SLinus Torvalds 	struct sctp_association *asoc;
308285f935d4Swangweidong 	unsigned long rto_min, rto_max;
308385f935d4Swangweidong 	struct sctp_sock *sp = sctp_sk(sk);
30841da177e4SLinus Torvalds 
30851da177e4SLinus Torvalds 	if (optlen != sizeof (struct sctp_rtoinfo))
30861da177e4SLinus Torvalds 		return -EINVAL;
30871da177e4SLinus Torvalds 
3088af5ae60eSChristoph Hellwig 	asoc = sctp_id2assoc(sk, rtoinfo->srto_assoc_id);
30891da177e4SLinus Torvalds 
30901da177e4SLinus Torvalds 	/* Set the values to the specific association */
3091af5ae60eSChristoph Hellwig 	if (!asoc && rtoinfo->srto_assoc_id != SCTP_FUTURE_ASSOC &&
30927adb5ed5SXin Long 	    sctp_style(sk, UDP))
30931da177e4SLinus Torvalds 		return -EINVAL;
30941da177e4SLinus Torvalds 
3095af5ae60eSChristoph Hellwig 	rto_max = rtoinfo->srto_max;
3096af5ae60eSChristoph Hellwig 	rto_min = rtoinfo->srto_min;
309785f935d4Swangweidong 
309885f935d4Swangweidong 	if (rto_max)
309985f935d4Swangweidong 		rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max;
310085f935d4Swangweidong 	else
310185f935d4Swangweidong 		rto_max = asoc ? asoc->rto_max : sp->rtoinfo.srto_max;
310285f935d4Swangweidong 
310385f935d4Swangweidong 	if (rto_min)
310485f935d4Swangweidong 		rto_min = asoc ? msecs_to_jiffies(rto_min) : rto_min;
310585f935d4Swangweidong 	else
310685f935d4Swangweidong 		rto_min = asoc ? asoc->rto_min : sp->rtoinfo.srto_min;
310785f935d4Swangweidong 
310885f935d4Swangweidong 	if (rto_min > rto_max)
310985f935d4Swangweidong 		return -EINVAL;
311085f935d4Swangweidong 
31111da177e4SLinus Torvalds 	if (asoc) {
3112af5ae60eSChristoph Hellwig 		if (rtoinfo->srto_initial != 0)
31131da177e4SLinus Torvalds 			asoc->rto_initial =
3114af5ae60eSChristoph Hellwig 				msecs_to_jiffies(rtoinfo->srto_initial);
311585f935d4Swangweidong 		asoc->rto_max = rto_max;
311685f935d4Swangweidong 		asoc->rto_min = rto_min;
31171da177e4SLinus Torvalds 	} else {
31181da177e4SLinus Torvalds 		/* If there is no association or the association-id = 0
31191da177e4SLinus Torvalds 		 * set the values to the endpoint.
31201da177e4SLinus Torvalds 		 */
3121af5ae60eSChristoph Hellwig 		if (rtoinfo->srto_initial != 0)
3122af5ae60eSChristoph Hellwig 			sp->rtoinfo.srto_initial = rtoinfo->srto_initial;
312385f935d4Swangweidong 		sp->rtoinfo.srto_max = rto_max;
312485f935d4Swangweidong 		sp->rtoinfo.srto_min = rto_min;
31251da177e4SLinus Torvalds 	}
31261da177e4SLinus Torvalds 
31271da177e4SLinus Torvalds 	return 0;
31281da177e4SLinus Torvalds }
31291da177e4SLinus Torvalds 
31301da177e4SLinus Torvalds /*
31311da177e4SLinus Torvalds  *
31321da177e4SLinus Torvalds  * 7.1.2 SCTP_ASSOCINFO
31331da177e4SLinus Torvalds  *
313459c51591SMichael Opdenacker  * This option is used to tune the maximum retransmission attempts
31351da177e4SLinus Torvalds  * of the association.
31361da177e4SLinus Torvalds  * Returns an error if the new association retransmission value is
31371da177e4SLinus Torvalds  * greater than the sum of the retransmission value  of the peer.
31381da177e4SLinus Torvalds  * See [SCTP] for more information.
31391da177e4SLinus Torvalds  *
31401da177e4SLinus Torvalds  */
sctp_setsockopt_associnfo(struct sock * sk,struct sctp_assocparams * assocparams,unsigned int optlen)31415b864c8dSChristoph Hellwig static int sctp_setsockopt_associnfo(struct sock *sk,
31425b864c8dSChristoph Hellwig 				     struct sctp_assocparams *assocparams,
31435b864c8dSChristoph Hellwig 				     unsigned int optlen)
31441da177e4SLinus Torvalds {
31451da177e4SLinus Torvalds 
31461da177e4SLinus Torvalds 	struct sctp_association *asoc;
31471da177e4SLinus Torvalds 
31481da177e4SLinus Torvalds 	if (optlen != sizeof(struct sctp_assocparams))
31491da177e4SLinus Torvalds 		return -EINVAL;
31501da177e4SLinus Torvalds 
31515b864c8dSChristoph Hellwig 	asoc = sctp_id2assoc(sk, assocparams->sasoc_assoc_id);
31521da177e4SLinus Torvalds 
31535b864c8dSChristoph Hellwig 	if (!asoc && assocparams->sasoc_assoc_id != SCTP_FUTURE_ASSOC &&
31548889394dSXin Long 	    sctp_style(sk, UDP))
31551da177e4SLinus Torvalds 		return -EINVAL;
31561da177e4SLinus Torvalds 
31571da177e4SLinus Torvalds 	/* Set the values to the specific association */
31581da177e4SLinus Torvalds 	if (asoc) {
31595b864c8dSChristoph Hellwig 		if (assocparams->sasoc_asocmaxrxt != 0) {
3160402d68c4SVlad Yasevich 			__u32 path_sum = 0;
3161402d68c4SVlad Yasevich 			int   paths = 0;
3162402d68c4SVlad Yasevich 			struct sctp_transport *peer_addr;
3163402d68c4SVlad Yasevich 
31649dbc15f0SRobert P. J. Day 			list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list,
31659dbc15f0SRobert P. J. Day 					transports) {
3166402d68c4SVlad Yasevich 				path_sum += peer_addr->pathmaxrxt;
3167402d68c4SVlad Yasevich 				paths++;
3168402d68c4SVlad Yasevich 			}
3169402d68c4SVlad Yasevich 
3170025dfdafSFrederik Schwarzer 			/* Only validate asocmaxrxt if we have more than
3171402d68c4SVlad Yasevich 			 * one path/transport.  We do this because path
3172402d68c4SVlad Yasevich 			 * retransmissions are only counted when we have more
3173402d68c4SVlad Yasevich 			 * then one path.
3174402d68c4SVlad Yasevich 			 */
3175402d68c4SVlad Yasevich 			if (paths > 1 &&
31765b864c8dSChristoph Hellwig 			    assocparams->sasoc_asocmaxrxt > path_sum)
3177402d68c4SVlad Yasevich 				return -EINVAL;
3178402d68c4SVlad Yasevich 
31795b864c8dSChristoph Hellwig 			asoc->max_retrans = assocparams->sasoc_asocmaxrxt;
3180402d68c4SVlad Yasevich 		}
3181402d68c4SVlad Yasevich 
31825b864c8dSChristoph Hellwig 		if (assocparams->sasoc_cookie_life != 0)
31835b864c8dSChristoph Hellwig 			asoc->cookie_life =
31845b864c8dSChristoph Hellwig 				ms_to_ktime(assocparams->sasoc_cookie_life);
31851da177e4SLinus Torvalds 	} else {
31861da177e4SLinus Torvalds 		/* Set the values to the endpoint */
31871da177e4SLinus Torvalds 		struct sctp_sock *sp = sctp_sk(sk);
31881da177e4SLinus Torvalds 
31895b864c8dSChristoph Hellwig 		if (assocparams->sasoc_asocmaxrxt != 0)
31901da177e4SLinus Torvalds 			sp->assocparams.sasoc_asocmaxrxt =
31915b864c8dSChristoph Hellwig 						assocparams->sasoc_asocmaxrxt;
31925b864c8dSChristoph Hellwig 		if (assocparams->sasoc_cookie_life != 0)
31931da177e4SLinus Torvalds 			sp->assocparams.sasoc_cookie_life =
31945b864c8dSChristoph Hellwig 						assocparams->sasoc_cookie_life;
31951da177e4SLinus Torvalds 	}
31961da177e4SLinus Torvalds 	return 0;
31971da177e4SLinus Torvalds }
31981da177e4SLinus Torvalds 
31991da177e4SLinus Torvalds /*
32001da177e4SLinus Torvalds  * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
32011da177e4SLinus Torvalds  *
32021da177e4SLinus Torvalds  * This socket option is a boolean flag which turns on or off mapped V4
32031da177e4SLinus Torvalds  * addresses.  If this option is turned on and the socket is type
32041da177e4SLinus Torvalds  * PF_INET6, then IPv4 addresses will be mapped to V6 representation.
32051da177e4SLinus Torvalds  * If this option is turned off, then no mapping will be done of V4
32061da177e4SLinus Torvalds  * addresses and a user will receive both PF_INET6 and PF_INET type
32071da177e4SLinus Torvalds  * addresses on the socket.
32081da177e4SLinus Torvalds  */
sctp_setsockopt_mappedv4(struct sock * sk,int * val,unsigned int optlen)3209ffc08f08SChristoph Hellwig static int sctp_setsockopt_mappedv4(struct sock *sk, int *val,
3210ffc08f08SChristoph Hellwig 				    unsigned int optlen)
32111da177e4SLinus Torvalds {
32121da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
32131da177e4SLinus Torvalds 
32141da177e4SLinus Torvalds 	if (optlen < sizeof(int))
32151da177e4SLinus Torvalds 		return -EINVAL;
3216ffc08f08SChristoph Hellwig 	if (*val)
32171da177e4SLinus Torvalds 		sp->v4mapped = 1;
32181da177e4SLinus Torvalds 	else
32191da177e4SLinus Torvalds 		sp->v4mapped = 0;
32201da177e4SLinus Torvalds 
32211da177e4SLinus Torvalds 	return 0;
32221da177e4SLinus Torvalds }
32231da177e4SLinus Torvalds 
32241da177e4SLinus Torvalds /*
3225e89c2095SWei Yongjun  * 8.1.16.  Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
3226e89c2095SWei Yongjun  * This option will get or set the maximum size to put in any outgoing
3227e89c2095SWei Yongjun  * SCTP DATA chunk.  If a message is larger than this size it will be
32281da177e4SLinus Torvalds  * fragmented by SCTP into the specified size.  Note that the underlying
32291da177e4SLinus Torvalds  * SCTP implementation may fragment into smaller sized chunks when the
32301da177e4SLinus Torvalds  * PMTU of the underlying association is smaller than the value set by
3231e89c2095SWei Yongjun  * the user.  The default value for this option is '0' which indicates
3232e89c2095SWei Yongjun  * the user is NOT limiting fragmentation and only the PMTU will effect
3233e89c2095SWei Yongjun  * SCTP's choice of DATA chunk size.  Note also that values set larger
3234e89c2095SWei Yongjun  * than the maximum size of an IP datagram will effectively let SCTP
3235e89c2095SWei Yongjun  * control fragmentation (i.e. the same as setting this option to 0).
3236e89c2095SWei Yongjun  *
3237e89c2095SWei Yongjun  * The following structure is used to access and modify this parameter:
3238e89c2095SWei Yongjun  *
3239e89c2095SWei Yongjun  * struct sctp_assoc_value {
3240e89c2095SWei Yongjun  *   sctp_assoc_t assoc_id;
3241e89c2095SWei Yongjun  *   uint32_t assoc_value;
3242e89c2095SWei Yongjun  * };
3243e89c2095SWei Yongjun  *
3244e89c2095SWei Yongjun  * assoc_id:  This parameter is ignored for one-to-one style sockets.
3245e89c2095SWei Yongjun  *    For one-to-many style sockets this parameter indicates which
3246e89c2095SWei Yongjun  *    association the user is performing an action upon.  Note that if
3247e89c2095SWei Yongjun  *    this field's value is zero then the endpoints default value is
3248e89c2095SWei Yongjun  *    changed (effecting future associations only).
3249e89c2095SWei Yongjun  * assoc_value:  This parameter specifies the maximum size in bytes.
32501da177e4SLinus Torvalds  */
sctp_setsockopt_maxseg(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)3251dcd03575SChristoph Hellwig static int sctp_setsockopt_maxseg(struct sock *sk,
3252dcd03575SChristoph Hellwig 				  struct sctp_assoc_value *params,
3253dcd03575SChristoph Hellwig 				  unsigned int optlen)
32541da177e4SLinus Torvalds {
3255ecca8f88SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
32561da177e4SLinus Torvalds 	struct sctp_association *asoc;
3257dcd03575SChristoph Hellwig 	sctp_assoc_t assoc_id;
32581da177e4SLinus Torvalds 	int val;
32591da177e4SLinus Torvalds 
3260e89c2095SWei Yongjun 	if (optlen == sizeof(int)) {
326194f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
3262f916ec96SNeil Horman 				    "%s (pid %d) "
326394f65193SNeil Horman 				    "Use of int in maxseg socket option.\n"
3264f916ec96SNeil Horman 				    "Use struct sctp_assoc_value instead\n",
3265f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
3266dcd03575SChristoph Hellwig 		assoc_id = SCTP_FUTURE_ASSOC;
3267dcd03575SChristoph Hellwig 		val = *(int *)params;
3268e89c2095SWei Yongjun 	} else if (optlen == sizeof(struct sctp_assoc_value)) {
3269dcd03575SChristoph Hellwig 		assoc_id = params->assoc_id;
3270dcd03575SChristoph Hellwig 		val = params->assoc_value;
3271ecca8f88SXin Long 	} else {
3272e89c2095SWei Yongjun 		return -EINVAL;
3273ecca8f88SXin Long 	}
3274e89c2095SWei Yongjun 
3275dcd03575SChristoph Hellwig 	asoc = sctp_id2assoc(sk, assoc_id);
3276dcd03575SChristoph Hellwig 	if (!asoc && assoc_id != SCTP_FUTURE_ASSOC &&
32776fd769beSXin Long 	    sctp_style(sk, UDP))
32786fd769beSXin Long 		return -EINVAL;
3279439ef030SMarcelo Ricardo Leitner 
3280ecca8f88SXin Long 	if (val) {
3281ecca8f88SXin Long 		int min_len, max_len;
3282439ef030SMarcelo Ricardo Leitner 		__u16 datasize = asoc ? sctp_datachk_len(&asoc->stream) :
3283ecca8f88SXin Long 				 sizeof(struct sctp_data_chunk);
3284ecca8f88SXin Long 
3285afd0a800SJakub Audykowicz 		min_len = sctp_min_frag_point(sp, datasize);
3286439ef030SMarcelo Ricardo Leitner 		max_len = SCTP_MAX_CHUNK_LEN - datasize;
3287ecca8f88SXin Long 
3288ecca8f88SXin Long 		if (val < min_len || val > max_len)
32891da177e4SLinus Torvalds 			return -EINVAL;
3290ecca8f88SXin Long 	}
3291e89c2095SWei Yongjun 
3292e89c2095SWei Yongjun 	if (asoc) {
3293f68b2e05SVlad Yasevich 		asoc->user_frag = val;
32942f5e3c9dSMarcelo Ricardo Leitner 		sctp_assoc_update_frag_point(asoc);
3295e89c2095SWei Yongjun 	} else {
32961da177e4SLinus Torvalds 		sp->user_frag = val;
3297e89c2095SWei Yongjun 	}
32981da177e4SLinus Torvalds 
32991da177e4SLinus Torvalds 	return 0;
33001da177e4SLinus Torvalds }
33011da177e4SLinus Torvalds 
33021da177e4SLinus Torvalds 
33031da177e4SLinus Torvalds /*
33041da177e4SLinus Torvalds  *  7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR)
33051da177e4SLinus Torvalds  *
33061da177e4SLinus Torvalds  *   Requests that the peer mark the enclosed address as the association
33071da177e4SLinus Torvalds  *   primary. The enclosed address must be one of the association's
33081da177e4SLinus Torvalds  *   locally bound addresses. The following structure is used to make a
33091da177e4SLinus Torvalds  *   set primary request:
33101da177e4SLinus Torvalds  */
sctp_setsockopt_peer_primary_addr(struct sock * sk,struct sctp_setpeerprim * prim,unsigned int optlen)331146a0ae9dSChristoph Hellwig static int sctp_setsockopt_peer_primary_addr(struct sock *sk,
331246a0ae9dSChristoph Hellwig 					     struct sctp_setpeerprim *prim,
3313b7058842SDavid S. Miller 					     unsigned int optlen)
33141da177e4SLinus Torvalds {
33151da177e4SLinus Torvalds 	struct sctp_sock	*sp;
33161da177e4SLinus Torvalds 	struct sctp_association	*asoc = NULL;
33171da177e4SLinus Torvalds 	struct sctp_chunk	*chunk;
331840a01039SWei Yongjun 	struct sctp_af		*af;
33191da177e4SLinus Torvalds 	int 			err;
33201da177e4SLinus Torvalds 
33211da177e4SLinus Torvalds 	sp = sctp_sk(sk);
33221da177e4SLinus Torvalds 
33234e27428fSXin Long 	if (!sp->ep->asconf_enable)
33241da177e4SLinus Torvalds 		return -EPERM;
33251da177e4SLinus Torvalds 
33261da177e4SLinus Torvalds 	if (optlen != sizeof(struct sctp_setpeerprim))
33271da177e4SLinus Torvalds 		return -EINVAL;
33281da177e4SLinus Torvalds 
332946a0ae9dSChristoph Hellwig 	asoc = sctp_id2assoc(sk, prim->sspp_assoc_id);
33301da177e4SLinus Torvalds 	if (!asoc)
33311da177e4SLinus Torvalds 		return -EINVAL;
33321da177e4SLinus Torvalds 
33331da177e4SLinus Torvalds 	if (!asoc->peer.asconf_capable)
33341da177e4SLinus Torvalds 		return -EPERM;
33351da177e4SLinus Torvalds 
33361da177e4SLinus Torvalds 	if (asoc->peer.addip_disabled_mask & SCTP_PARAM_SET_PRIMARY)
33371da177e4SLinus Torvalds 		return -EPERM;
33381da177e4SLinus Torvalds 
33391da177e4SLinus Torvalds 	if (!sctp_state(asoc, ESTABLISHED))
33401da177e4SLinus Torvalds 		return -ENOTCONN;
33411da177e4SLinus Torvalds 
334246a0ae9dSChristoph Hellwig 	af = sctp_get_af_specific(prim->sspp_addr.ss_family);
334340a01039SWei Yongjun 	if (!af)
334440a01039SWei Yongjun 		return -EINVAL;
334540a01039SWei Yongjun 
334646a0ae9dSChristoph Hellwig 	if (!af->addr_valid((union sctp_addr *)&prim->sspp_addr, sp, NULL))
334740a01039SWei Yongjun 		return -EADDRNOTAVAIL;
334840a01039SWei Yongjun 
334946a0ae9dSChristoph Hellwig 	if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim->sspp_addr))
33501da177e4SLinus Torvalds 		return -EADDRNOTAVAIL;
33511da177e4SLinus Torvalds 
33522277c7cdSRichard Haines 	/* Allow security module to validate address. */
33532277c7cdSRichard Haines 	err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR,
335446a0ae9dSChristoph Hellwig 					 (struct sockaddr *)&prim->sspp_addr,
33552277c7cdSRichard Haines 					 af->sockaddr_len);
33562277c7cdSRichard Haines 	if (err)
33572277c7cdSRichard Haines 		return err;
33582277c7cdSRichard Haines 
33591da177e4SLinus Torvalds 	/* Create an ASCONF chunk with SET_PRIMARY parameter	*/
33601da177e4SLinus Torvalds 	chunk = sctp_make_asconf_set_prim(asoc,
336146a0ae9dSChristoph Hellwig 					  (union sctp_addr *)&prim->sspp_addr);
33621da177e4SLinus Torvalds 	if (!chunk)
33631da177e4SLinus Torvalds 		return -ENOMEM;
33641da177e4SLinus Torvalds 
33651da177e4SLinus Torvalds 	err = sctp_send_asconf(asoc, chunk);
33661da177e4SLinus Torvalds 
3367bb33381dSDaniel Borkmann 	pr_debug("%s: we set peer primary addr primitively\n", __func__);
33681da177e4SLinus Torvalds 
33691da177e4SLinus Torvalds 	return err;
33701da177e4SLinus Torvalds }
33711da177e4SLinus Torvalds 
sctp_setsockopt_adaptation_layer(struct sock * sk,struct sctp_setadaptation * adapt,unsigned int optlen)337207e5035cSChristoph Hellwig static int sctp_setsockopt_adaptation_layer(struct sock *sk,
337307e5035cSChristoph Hellwig 					    struct sctp_setadaptation *adapt,
3374b7058842SDavid S. Miller 					    unsigned int optlen)
33751da177e4SLinus Torvalds {
33760f3fffd8SIvan Skytte Jorgensen 	if (optlen != sizeof(struct sctp_setadaptation))
33771da177e4SLinus Torvalds 		return -EINVAL;
33781da177e4SLinus Torvalds 
337907e5035cSChristoph Hellwig 	sctp_sk(sk)->adaptation_ind = adapt->ssb_adaptation_ind;
33801da177e4SLinus Torvalds 
33811da177e4SLinus Torvalds 	return 0;
33821da177e4SLinus Torvalds }
33831da177e4SLinus Torvalds 
33846ab792f5SIvan Skytte Jorgensen /*
33856ab792f5SIvan Skytte Jorgensen  * 7.1.29.  Set or Get the default context (SCTP_CONTEXT)
33866ab792f5SIvan Skytte Jorgensen  *
33876ab792f5SIvan Skytte Jorgensen  * The context field in the sctp_sndrcvinfo structure is normally only
33886ab792f5SIvan Skytte Jorgensen  * used when a failed message is retrieved holding the value that was
33896ab792f5SIvan Skytte Jorgensen  * sent down on the actual send call.  This option allows the setting of
33906ab792f5SIvan Skytte Jorgensen  * a default context on an association basis that will be received on
33916ab792f5SIvan Skytte Jorgensen  * reading messages from the peer.  This is especially helpful in the
33926ab792f5SIvan Skytte Jorgensen  * one-2-many model for an application to keep some reference to an
33936ab792f5SIvan Skytte Jorgensen  * internal state machine that is processing messages on the
33946ab792f5SIvan Skytte Jorgensen  * association.  Note that the setting of this value only effects
33956ab792f5SIvan Skytte Jorgensen  * received messages from the peer and does not effect the value that is
33966ab792f5SIvan Skytte Jorgensen  * saved with outbound messages.
33976ab792f5SIvan Skytte Jorgensen  */
sctp_setsockopt_context(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)3398722eca9eSChristoph Hellwig static int sctp_setsockopt_context(struct sock *sk,
3399722eca9eSChristoph Hellwig 				   struct sctp_assoc_value *params,
3400b7058842SDavid S. Miller 				   unsigned int optlen)
34016ab792f5SIvan Skytte Jorgensen {
340249b037acSXin Long 	struct sctp_sock *sp = sctp_sk(sk);
34036ab792f5SIvan Skytte Jorgensen 	struct sctp_association *asoc;
34046ab792f5SIvan Skytte Jorgensen 
34056ab792f5SIvan Skytte Jorgensen 	if (optlen != sizeof(struct sctp_assoc_value))
34066ab792f5SIvan Skytte Jorgensen 		return -EINVAL;
34076ab792f5SIvan Skytte Jorgensen 
3408722eca9eSChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
3409722eca9eSChristoph Hellwig 	if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
341049b037acSXin Long 	    sctp_style(sk, UDP))
34116ab792f5SIvan Skytte Jorgensen 		return -EINVAL;
341249b037acSXin Long 
341349b037acSXin Long 	if (asoc) {
3414722eca9eSChristoph Hellwig 		asoc->default_rcv_context = params->assoc_value;
341549b037acSXin Long 
341649b037acSXin Long 		return 0;
34176ab792f5SIvan Skytte Jorgensen 	}
34186ab792f5SIvan Skytte Jorgensen 
3419cface2cbSXin Long 	if (sctp_style(sk, TCP))
3420722eca9eSChristoph Hellwig 		params->assoc_id = SCTP_FUTURE_ASSOC;
3421cface2cbSXin Long 
3422722eca9eSChristoph Hellwig 	if (params->assoc_id == SCTP_FUTURE_ASSOC ||
3423722eca9eSChristoph Hellwig 	    params->assoc_id == SCTP_ALL_ASSOC)
3424722eca9eSChristoph Hellwig 		sp->default_rcv_context = params->assoc_value;
342549b037acSXin Long 
3426722eca9eSChristoph Hellwig 	if (params->assoc_id == SCTP_CURRENT_ASSOC ||
3427722eca9eSChristoph Hellwig 	    params->assoc_id == SCTP_ALL_ASSOC)
342849b037acSXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs)
3429722eca9eSChristoph Hellwig 			asoc->default_rcv_context = params->assoc_value;
343049b037acSXin Long 
34316ab792f5SIvan Skytte Jorgensen 	return 0;
34326ab792f5SIvan Skytte Jorgensen }
34336ab792f5SIvan Skytte Jorgensen 
3434b6e1331fSVlad Yasevich /*
3435b6e1331fSVlad Yasevich  * 7.1.24.  Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE)
3436b6e1331fSVlad Yasevich  *
3437b6e1331fSVlad Yasevich  * This options will at a minimum specify if the implementation is doing
3438b6e1331fSVlad Yasevich  * fragmented interleave.  Fragmented interleave, for a one to many
3439b6e1331fSVlad Yasevich  * socket, is when subsequent calls to receive a message may return
3440b6e1331fSVlad Yasevich  * parts of messages from different associations.  Some implementations
3441b6e1331fSVlad Yasevich  * may allow you to turn this value on or off.  If so, when turned off,
3442b6e1331fSVlad Yasevich  * no fragment interleave will occur (which will cause a head of line
3443b6e1331fSVlad Yasevich  * blocking amongst multiple associations sharing the same one to many
3444b6e1331fSVlad Yasevich  * socket).  When this option is turned on, then each receive call may
3445b6e1331fSVlad Yasevich  * come from a different association (thus the user must receive data
3446b6e1331fSVlad Yasevich  * with the extended calls (e.g. sctp_recvmsg) to keep track of which
3447b6e1331fSVlad Yasevich  * association each receive belongs to.
3448b6e1331fSVlad Yasevich  *
3449b6e1331fSVlad Yasevich  * This option takes a boolean value.  A non-zero value indicates that
3450b6e1331fSVlad Yasevich  * fragmented interleave is on.  A value of zero indicates that
3451b6e1331fSVlad Yasevich  * fragmented interleave is off.
3452b6e1331fSVlad Yasevich  *
3453b6e1331fSVlad Yasevich  * Note that it is important that an implementation that allows this
3454b6e1331fSVlad Yasevich  * option to be turned on, have it off by default.  Otherwise an unaware
3455b6e1331fSVlad Yasevich  * application using the one to many model may become confused and act
3456b6e1331fSVlad Yasevich  * incorrectly.
3457b6e1331fSVlad Yasevich  */
sctp_setsockopt_fragment_interleave(struct sock * sk,int * val,unsigned int optlen)34581031cea0SChristoph Hellwig static int sctp_setsockopt_fragment_interleave(struct sock *sk, int *val,
3459b7058842SDavid S. Miller 					       unsigned int optlen)
3460b6e1331fSVlad Yasevich {
3461b6e1331fSVlad Yasevich 	if (optlen != sizeof(int))
3462b6e1331fSVlad Yasevich 		return -EINVAL;
3463b6e1331fSVlad Yasevich 
34641031cea0SChristoph Hellwig 	sctp_sk(sk)->frag_interleave = !!*val;
3465772a5869SXin Long 
3466772a5869SXin Long 	if (!sctp_sk(sk)->frag_interleave)
3467e55f4b8bSXin Long 		sctp_sk(sk)->ep->intl_enable = 0;
3468b6e1331fSVlad Yasevich 
3469b6e1331fSVlad Yasevich 	return 0;
3470b6e1331fSVlad Yasevich }
3471b6e1331fSVlad Yasevich 
3472d49d91d7SVlad Yasevich /*
34738510b937SWei Yongjun  * 8.1.21.  Set or Get the SCTP Partial Delivery Point
3474d49d91d7SVlad Yasevich  *       (SCTP_PARTIAL_DELIVERY_POINT)
34758510b937SWei Yongjun  *
3476d49d91d7SVlad Yasevich  * This option will set or get the SCTP partial delivery point.  This
3477d49d91d7SVlad Yasevich  * point is the size of a message where the partial delivery API will be
3478d49d91d7SVlad Yasevich  * invoked to help free up rwnd space for the peer.  Setting this to a
34798510b937SWei Yongjun  * lower value will cause partial deliveries to happen more often.  The
3480d49d91d7SVlad Yasevich  * calls argument is an integer that sets or gets the partial delivery
34818510b937SWei Yongjun  * point.  Note also that the call will fail if the user attempts to set
34828510b937SWei Yongjun  * this value larger than the socket receive buffer size.
34838510b937SWei Yongjun  *
34848510b937SWei Yongjun  * Note that any single message having a length smaller than or equal to
34858510b937SWei Yongjun  * the SCTP partial delivery point will be delivered in one single read
34868510b937SWei Yongjun  * call as long as the user provided buffer is large enough to hold the
34878510b937SWei Yongjun  * message.
3488d49d91d7SVlad Yasevich  */
sctp_setsockopt_partial_delivery_point(struct sock * sk,u32 * val,unsigned int optlen)3489bb13d647SChristoph Hellwig static int sctp_setsockopt_partial_delivery_point(struct sock *sk, u32 *val,
3490b7058842SDavid S. Miller 						  unsigned int optlen)
3491d49d91d7SVlad Yasevich {
3492d49d91d7SVlad Yasevich 	if (optlen != sizeof(u32))
3493d49d91d7SVlad Yasevich 		return -EINVAL;
3494d49d91d7SVlad Yasevich 
34958510b937SWei Yongjun 	/* Note: We double the receive buffer from what the user sets
34968510b937SWei Yongjun 	 * it to be, also initial rwnd is based on rcvbuf/2.
34978510b937SWei Yongjun 	 */
3498bb13d647SChristoph Hellwig 	if (*val > (sk->sk_rcvbuf >> 1))
34998510b937SWei Yongjun 		return -EINVAL;
35008510b937SWei Yongjun 
3501bb13d647SChristoph Hellwig 	sctp_sk(sk)->pd_point = *val;
3502d49d91d7SVlad Yasevich 
3503d49d91d7SVlad Yasevich 	return 0; /* is this the right error code? */
3504d49d91d7SVlad Yasevich }
3505d49d91d7SVlad Yasevich 
350670331571SVlad Yasevich /*
350770331571SVlad Yasevich  * 7.1.28.  Set or Get the maximum burst (SCTP_MAX_BURST)
350870331571SVlad Yasevich  *
350970331571SVlad Yasevich  * This option will allow a user to change the maximum burst of packets
351070331571SVlad Yasevich  * that can be emitted by this association.  Note that the default value
351170331571SVlad Yasevich  * is 4, and some implementations may restrict this setting so that it
351270331571SVlad Yasevich  * can only be lowered.
351370331571SVlad Yasevich  *
351470331571SVlad Yasevich  * NOTE: This text doesn't seem right.  Do this on a socket basis with
351570331571SVlad Yasevich  * future associations inheriting the socket value.
351670331571SVlad Yasevich  */
sctp_setsockopt_maxburst(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)351770331571SVlad Yasevich static int sctp_setsockopt_maxburst(struct sock *sk,
3518f5bee0adSChristoph Hellwig 				    struct sctp_assoc_value *params,
3519b7058842SDavid S. Miller 				    unsigned int optlen)
352070331571SVlad Yasevich {
3521e0651a0dSXin Long 	struct sctp_sock *sp = sctp_sk(sk);
3522219b99a9SNeil Horman 	struct sctp_association *asoc;
3523f5bee0adSChristoph Hellwig 	sctp_assoc_t assoc_id;
3524f5bee0adSChristoph Hellwig 	u32 assoc_value;
352570331571SVlad Yasevich 
3526219b99a9SNeil Horman 	if (optlen == sizeof(int)) {
352794f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
3528f916ec96SNeil Horman 				    "%s (pid %d) "
352994f65193SNeil Horman 				    "Use of int in max_burst socket option deprecated.\n"
3530f916ec96SNeil Horman 				    "Use struct sctp_assoc_value instead\n",
3531f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
3532f5bee0adSChristoph Hellwig 		assoc_id = SCTP_FUTURE_ASSOC;
3533f5bee0adSChristoph Hellwig 		assoc_value = *((int *)params);
3534219b99a9SNeil Horman 	} else if (optlen == sizeof(struct sctp_assoc_value)) {
3535f5bee0adSChristoph Hellwig 		assoc_id = params->assoc_id;
3536f5bee0adSChristoph Hellwig 		assoc_value = params->assoc_value;
3537219b99a9SNeil Horman 	} else
353870331571SVlad Yasevich 		return -EINVAL;
353970331571SVlad Yasevich 
3540f5bee0adSChristoph Hellwig 	asoc = sctp_id2assoc(sk, assoc_id);
3541f5bee0adSChristoph Hellwig 	if (!asoc && assoc_id > SCTP_ALL_ASSOC && sctp_style(sk, UDP))
3542219b99a9SNeil Horman 		return -EINVAL;
3543e0651a0dSXin Long 
3544e0651a0dSXin Long 	if (asoc) {
3545f5bee0adSChristoph Hellwig 		asoc->max_burst = assoc_value;
3546e0651a0dSXin Long 
3547e0651a0dSXin Long 		return 0;
3548e0651a0dSXin Long 	}
3549e0651a0dSXin Long 
3550746bc215SXin Long 	if (sctp_style(sk, TCP))
3551f5bee0adSChristoph Hellwig 		assoc_id = SCTP_FUTURE_ASSOC;
3552746bc215SXin Long 
3553f5bee0adSChristoph Hellwig 	if (assoc_id == SCTP_FUTURE_ASSOC || assoc_id == SCTP_ALL_ASSOC)
3554f5bee0adSChristoph Hellwig 		sp->max_burst = assoc_value;
3555e0651a0dSXin Long 
3556f5bee0adSChristoph Hellwig 	if (assoc_id == SCTP_CURRENT_ASSOC || assoc_id == SCTP_ALL_ASSOC)
3557e0651a0dSXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs)
3558f5bee0adSChristoph Hellwig 			asoc->max_burst = assoc_value;
355970331571SVlad Yasevich 
356070331571SVlad Yasevich 	return 0;
356170331571SVlad Yasevich }
356270331571SVlad Yasevich 
356365b07e5dSVlad Yasevich /*
356465b07e5dSVlad Yasevich  * 7.1.18.  Add a chunk that must be authenticated (SCTP_AUTH_CHUNK)
356565b07e5dSVlad Yasevich  *
356665b07e5dSVlad Yasevich  * This set option adds a chunk type that the user is requesting to be
356765b07e5dSVlad Yasevich  * received only in an authenticated way.  Changes to the list of chunks
356865b07e5dSVlad Yasevich  * will only effect future associations on the socket.
356965b07e5dSVlad Yasevich  */
sctp_setsockopt_auth_chunk(struct sock * sk,struct sctp_authchunk * val,unsigned int optlen)357065b07e5dSVlad Yasevich static int sctp_setsockopt_auth_chunk(struct sock *sk,
357188266d31SChristoph Hellwig 				      struct sctp_authchunk *val,
3572b7058842SDavid S. Miller 				      unsigned int optlen)
357365b07e5dSVlad Yasevich {
3574b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
357565b07e5dSVlad Yasevich 
3576b14878ccSVlad Yasevich 	if (!ep->auth_enable)
35775e739d17SVlad Yasevich 		return -EACCES;
35785e739d17SVlad Yasevich 
357965b07e5dSVlad Yasevich 	if (optlen != sizeof(struct sctp_authchunk))
358065b07e5dSVlad Yasevich 		return -EINVAL;
358165b07e5dSVlad Yasevich 
358288266d31SChristoph Hellwig 	switch (val->sauth_chunk) {
358365b07e5dSVlad Yasevich 	case SCTP_CID_INIT:
358465b07e5dSVlad Yasevich 	case SCTP_CID_INIT_ACK:
358565b07e5dSVlad Yasevich 	case SCTP_CID_SHUTDOWN_COMPLETE:
358665b07e5dSVlad Yasevich 	case SCTP_CID_AUTH:
358765b07e5dSVlad Yasevich 		return -EINVAL;
358865b07e5dSVlad Yasevich 	}
358965b07e5dSVlad Yasevich 
359065b07e5dSVlad Yasevich 	/* add this chunk id to the endpoint */
359188266d31SChristoph Hellwig 	return sctp_auth_ep_add_chunkid(ep, val->sauth_chunk);
359265b07e5dSVlad Yasevich }
359365b07e5dSVlad Yasevich 
359465b07e5dSVlad Yasevich /*
359565b07e5dSVlad Yasevich  * 7.1.19.  Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT)
359665b07e5dSVlad Yasevich  *
359765b07e5dSVlad Yasevich  * This option gets or sets the list of HMAC algorithms that the local
359865b07e5dSVlad Yasevich  * endpoint requires the peer to use.
359965b07e5dSVlad Yasevich  */
sctp_setsockopt_hmac_ident(struct sock * sk,struct sctp_hmacalgo * hmacs,unsigned int optlen)360065b07e5dSVlad Yasevich static int sctp_setsockopt_hmac_ident(struct sock *sk,
36013564ef44SChristoph Hellwig 				      struct sctp_hmacalgo *hmacs,
3602b7058842SDavid S. Miller 				      unsigned int optlen)
360365b07e5dSVlad Yasevich {
3604b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
3605d9724055SVlad Yasevich 	u32 idents;
360665b07e5dSVlad Yasevich 
3607b14878ccSVlad Yasevich 	if (!ep->auth_enable)
36085e739d17SVlad Yasevich 		return -EACCES;
36095e739d17SVlad Yasevich 
361065b07e5dSVlad Yasevich 	if (optlen < sizeof(struct sctp_hmacalgo))
361165b07e5dSVlad Yasevich 		return -EINVAL;
36125960cefaSMarcelo Ricardo Leitner 	optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) +
36135960cefaSMarcelo Ricardo Leitner 					     SCTP_AUTH_NUM_HMACS * sizeof(u16));
361465b07e5dSVlad Yasevich 
3615d9724055SVlad Yasevich 	idents = hmacs->shmac_num_idents;
3616d9724055SVlad Yasevich 	if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS ||
36173564ef44SChristoph Hellwig 	    (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo)))
36183564ef44SChristoph Hellwig 		return -EINVAL;
361965b07e5dSVlad Yasevich 
36203564ef44SChristoph Hellwig 	return sctp_auth_ep_set_hmacs(ep, hmacs);
362165b07e5dSVlad Yasevich }
362265b07e5dSVlad Yasevich 
362365b07e5dSVlad Yasevich /*
362465b07e5dSVlad Yasevich  * 7.1.20.  Set a shared key (SCTP_AUTH_KEY)
362565b07e5dSVlad Yasevich  *
362665b07e5dSVlad Yasevich  * This option will set a shared secret key which is used to build an
362765b07e5dSVlad Yasevich  * association shared key.
362865b07e5dSVlad Yasevich  */
sctp_setsockopt_auth_key(struct sock * sk,struct sctp_authkey * authkey,unsigned int optlen)362965b07e5dSVlad Yasevich static int sctp_setsockopt_auth_key(struct sock *sk,
3630534d13d0SChristoph Hellwig 				    struct sctp_authkey *authkey,
3631b7058842SDavid S. Miller 				    unsigned int optlen)
363265b07e5dSVlad Yasevich {
3633b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
363465b07e5dSVlad Yasevich 	struct sctp_association *asoc;
36357fb3be13SXin Long 	int ret = -EINVAL;
363665b07e5dSVlad Yasevich 
363765b07e5dSVlad Yasevich 	if (optlen <= sizeof(struct sctp_authkey))
363865b07e5dSVlad Yasevich 		return -EINVAL;
36395960cefaSMarcelo Ricardo Leitner 	/* authkey->sca_keylength is u16, so optlen can't be bigger than
36405960cefaSMarcelo Ricardo Leitner 	 * this.
36415960cefaSMarcelo Ricardo Leitner 	 */
36427fb3be13SXin Long 	optlen = min_t(unsigned int, optlen, USHRT_MAX + sizeof(*authkey));
364365b07e5dSVlad Yasevich 
36447fb3be13SXin Long 	if (authkey->sca_keylength > optlen - sizeof(*authkey))
364530c2235cSVlad Yasevich 		goto out;
364630c2235cSVlad Yasevich 
364765b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, authkey->sca_assoc_id);
36487fb3be13SXin Long 	if (!asoc && authkey->sca_assoc_id > SCTP_ALL_ASSOC &&
36497fb3be13SXin Long 	    sctp_style(sk, UDP))
36507fb3be13SXin Long 		goto out;
36517fb3be13SXin Long 
36527fb3be13SXin Long 	if (asoc) {
36537fb3be13SXin Long 		ret = sctp_auth_set_key(ep, asoc, authkey);
365465b07e5dSVlad Yasevich 		goto out;
365565b07e5dSVlad Yasevich 	}
365665b07e5dSVlad Yasevich 
36570685d6b7SXin Long 	if (sctp_style(sk, TCP))
36580685d6b7SXin Long 		authkey->sca_assoc_id = SCTP_FUTURE_ASSOC;
36590685d6b7SXin Long 
36607fb3be13SXin Long 	if (authkey->sca_assoc_id == SCTP_FUTURE_ASSOC ||
36617fb3be13SXin Long 	    authkey->sca_assoc_id == SCTP_ALL_ASSOC) {
3662b14878ccSVlad Yasevich 		ret = sctp_auth_set_key(ep, asoc, authkey);
36637fb3be13SXin Long 		if (ret)
36647fb3be13SXin Long 			goto out;
36657fb3be13SXin Long 	}
36667fb3be13SXin Long 
36677fb3be13SXin Long 	ret = 0;
36687fb3be13SXin Long 
36697fb3be13SXin Long 	if (authkey->sca_assoc_id == SCTP_CURRENT_ASSOC ||
36707fb3be13SXin Long 	    authkey->sca_assoc_id == SCTP_ALL_ASSOC) {
36717fb3be13SXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs) {
36727fb3be13SXin Long 			int res = sctp_auth_set_key(ep, asoc, authkey);
36737fb3be13SXin Long 
36747fb3be13SXin Long 			if (res && !ret)
36757fb3be13SXin Long 				ret = res;
36767fb3be13SXin Long 		}
36777fb3be13SXin Long 	}
36787fb3be13SXin Long 
367965b07e5dSVlad Yasevich out:
368089fae01eSChristoph Hellwig 	memzero_explicit(authkey, optlen);
368165b07e5dSVlad Yasevich 	return ret;
368265b07e5dSVlad Yasevich }
368365b07e5dSVlad Yasevich 
368465b07e5dSVlad Yasevich /*
368565b07e5dSVlad Yasevich  * 7.1.21.  Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY)
368665b07e5dSVlad Yasevich  *
368765b07e5dSVlad Yasevich  * This option will get or set the active shared key to be used to build
368865b07e5dSVlad Yasevich  * the association shared key.
368965b07e5dSVlad Yasevich  */
sctp_setsockopt_active_key(struct sock * sk,struct sctp_authkeyid * val,unsigned int optlen)369065b07e5dSVlad Yasevich static int sctp_setsockopt_active_key(struct sock *sk,
3691dcab0a7aSChristoph Hellwig 				      struct sctp_authkeyid *val,
3692b7058842SDavid S. Miller 				      unsigned int optlen)
369365b07e5dSVlad Yasevich {
3694b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
369565b07e5dSVlad Yasevich 	struct sctp_association *asoc;
3696bf9fb6adSXin Long 	int ret = 0;
369765b07e5dSVlad Yasevich 
369865b07e5dSVlad Yasevich 	if (optlen != sizeof(struct sctp_authkeyid))
369965b07e5dSVlad Yasevich 		return -EINVAL;
370065b07e5dSVlad Yasevich 
3701dcab0a7aSChristoph Hellwig 	asoc = sctp_id2assoc(sk, val->scact_assoc_id);
3702dcab0a7aSChristoph Hellwig 	if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC &&
3703bf9fb6adSXin Long 	    sctp_style(sk, UDP))
370465b07e5dSVlad Yasevich 		return -EINVAL;
370565b07e5dSVlad Yasevich 
3706bf9fb6adSXin Long 	if (asoc)
3707dcab0a7aSChristoph Hellwig 		return sctp_auth_set_active_key(ep, asoc, val->scact_keynumber);
3708bf9fb6adSXin Long 
370906b39e85SXin Long 	if (sctp_style(sk, TCP))
3710dcab0a7aSChristoph Hellwig 		val->scact_assoc_id = SCTP_FUTURE_ASSOC;
371106b39e85SXin Long 
3712dcab0a7aSChristoph Hellwig 	if (val->scact_assoc_id == SCTP_FUTURE_ASSOC ||
3713dcab0a7aSChristoph Hellwig 	    val->scact_assoc_id == SCTP_ALL_ASSOC) {
3714dcab0a7aSChristoph Hellwig 		ret = sctp_auth_set_active_key(ep, asoc, val->scact_keynumber);
3715bf9fb6adSXin Long 		if (ret)
3716bf9fb6adSXin Long 			return ret;
3717bf9fb6adSXin Long 	}
3718bf9fb6adSXin Long 
3719dcab0a7aSChristoph Hellwig 	if (val->scact_assoc_id == SCTP_CURRENT_ASSOC ||
3720dcab0a7aSChristoph Hellwig 	    val->scact_assoc_id == SCTP_ALL_ASSOC) {
3721bf9fb6adSXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs) {
3722bf9fb6adSXin Long 			int res = sctp_auth_set_active_key(ep, asoc,
3723dcab0a7aSChristoph Hellwig 							   val->scact_keynumber);
3724bf9fb6adSXin Long 
3725bf9fb6adSXin Long 			if (res && !ret)
3726bf9fb6adSXin Long 				ret = res;
3727bf9fb6adSXin Long 		}
3728bf9fb6adSXin Long 	}
3729bf9fb6adSXin Long 
3730bf9fb6adSXin Long 	return ret;
373165b07e5dSVlad Yasevich }
373265b07e5dSVlad Yasevich 
373365b07e5dSVlad Yasevich /*
373465b07e5dSVlad Yasevich  * 7.1.22.  Delete a shared key (SCTP_AUTH_DELETE_KEY)
373565b07e5dSVlad Yasevich  *
373665b07e5dSVlad Yasevich  * This set option will delete a shared secret key from use.
373765b07e5dSVlad Yasevich  */
sctp_setsockopt_del_key(struct sock * sk,struct sctp_authkeyid * val,unsigned int optlen)373865b07e5dSVlad Yasevich static int sctp_setsockopt_del_key(struct sock *sk,
373997dc9f2eSChristoph Hellwig 				   struct sctp_authkeyid *val,
3740b7058842SDavid S. Miller 				   unsigned int optlen)
374165b07e5dSVlad Yasevich {
3742b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
374365b07e5dSVlad Yasevich 	struct sctp_association *asoc;
37443adcc300SXin Long 	int ret = 0;
374565b07e5dSVlad Yasevich 
374665b07e5dSVlad Yasevich 	if (optlen != sizeof(struct sctp_authkeyid))
374765b07e5dSVlad Yasevich 		return -EINVAL;
374865b07e5dSVlad Yasevich 
374997dc9f2eSChristoph Hellwig 	asoc = sctp_id2assoc(sk, val->scact_assoc_id);
375097dc9f2eSChristoph Hellwig 	if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC &&
37513adcc300SXin Long 	    sctp_style(sk, UDP))
375265b07e5dSVlad Yasevich 		return -EINVAL;
375365b07e5dSVlad Yasevich 
37543adcc300SXin Long 	if (asoc)
375597dc9f2eSChristoph Hellwig 		return sctp_auth_del_key_id(ep, asoc, val->scact_keynumber);
375665b07e5dSVlad Yasevich 
3757220675ebSXin Long 	if (sctp_style(sk, TCP))
375897dc9f2eSChristoph Hellwig 		val->scact_assoc_id = SCTP_FUTURE_ASSOC;
3759220675ebSXin Long 
376097dc9f2eSChristoph Hellwig 	if (val->scact_assoc_id == SCTP_FUTURE_ASSOC ||
376197dc9f2eSChristoph Hellwig 	    val->scact_assoc_id == SCTP_ALL_ASSOC) {
376297dc9f2eSChristoph Hellwig 		ret = sctp_auth_del_key_id(ep, asoc, val->scact_keynumber);
37633adcc300SXin Long 		if (ret)
37643adcc300SXin Long 			return ret;
37653adcc300SXin Long 	}
37663adcc300SXin Long 
376797dc9f2eSChristoph Hellwig 	if (val->scact_assoc_id == SCTP_CURRENT_ASSOC ||
376897dc9f2eSChristoph Hellwig 	    val->scact_assoc_id == SCTP_ALL_ASSOC) {
37693adcc300SXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs) {
37703adcc300SXin Long 			int res = sctp_auth_del_key_id(ep, asoc,
377197dc9f2eSChristoph Hellwig 						       val->scact_keynumber);
37723adcc300SXin Long 
37733adcc300SXin Long 			if (res && !ret)
37743adcc300SXin Long 				ret = res;
37753adcc300SXin Long 		}
37763adcc300SXin Long 	}
37773adcc300SXin Long 
37783adcc300SXin Long 	return ret;
377965b07e5dSVlad Yasevich }
378065b07e5dSVlad Yasevich 
37817dc04d71SMichio Honda /*
3782601590ecSXin Long  * 8.3.4  Deactivate a Shared Key (SCTP_AUTH_DEACTIVATE_KEY)
3783601590ecSXin Long  *
3784601590ecSXin Long  * This set option will deactivate a shared secret key.
3785601590ecSXin Long  */
sctp_setsockopt_deactivate_key(struct sock * sk,struct sctp_authkeyid * val,unsigned int optlen)378676b3d0c4SChristoph Hellwig static int sctp_setsockopt_deactivate_key(struct sock *sk,
378776b3d0c4SChristoph Hellwig 					  struct sctp_authkeyid *val,
3788601590ecSXin Long 					  unsigned int optlen)
3789601590ecSXin Long {
3790601590ecSXin Long 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
3791601590ecSXin Long 	struct sctp_association *asoc;
37922af66ff3SXin Long 	int ret = 0;
3793601590ecSXin Long 
3794601590ecSXin Long 	if (optlen != sizeof(struct sctp_authkeyid))
3795601590ecSXin Long 		return -EINVAL;
3796601590ecSXin Long 
379776b3d0c4SChristoph Hellwig 	asoc = sctp_id2assoc(sk, val->scact_assoc_id);
379876b3d0c4SChristoph Hellwig 	if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC &&
37992af66ff3SXin Long 	    sctp_style(sk, UDP))
3800601590ecSXin Long 		return -EINVAL;
3801601590ecSXin Long 
38022af66ff3SXin Long 	if (asoc)
380376b3d0c4SChristoph Hellwig 		return sctp_auth_deact_key_id(ep, asoc, val->scact_keynumber);
38042af66ff3SXin Long 
3805200f3a3bSXin Long 	if (sctp_style(sk, TCP))
380676b3d0c4SChristoph Hellwig 		val->scact_assoc_id = SCTP_FUTURE_ASSOC;
3807200f3a3bSXin Long 
380876b3d0c4SChristoph Hellwig 	if (val->scact_assoc_id == SCTP_FUTURE_ASSOC ||
380976b3d0c4SChristoph Hellwig 	    val->scact_assoc_id == SCTP_ALL_ASSOC) {
381076b3d0c4SChristoph Hellwig 		ret = sctp_auth_deact_key_id(ep, asoc, val->scact_keynumber);
38112af66ff3SXin Long 		if (ret)
38122af66ff3SXin Long 			return ret;
38132af66ff3SXin Long 	}
38142af66ff3SXin Long 
381576b3d0c4SChristoph Hellwig 	if (val->scact_assoc_id == SCTP_CURRENT_ASSOC ||
381676b3d0c4SChristoph Hellwig 	    val->scact_assoc_id == SCTP_ALL_ASSOC) {
38172af66ff3SXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs) {
38182af66ff3SXin Long 			int res = sctp_auth_deact_key_id(ep, asoc,
381976b3d0c4SChristoph Hellwig 							 val->scact_keynumber);
38202af66ff3SXin Long 
38212af66ff3SXin Long 			if (res && !ret)
38222af66ff3SXin Long 				ret = res;
38232af66ff3SXin Long 		}
38242af66ff3SXin Long 	}
38252af66ff3SXin Long 
38262af66ff3SXin Long 	return ret;
3827601590ecSXin Long }
3828601590ecSXin Long 
3829601590ecSXin Long /*
38307dc04d71SMichio Honda  * 8.1.23 SCTP_AUTO_ASCONF
38317dc04d71SMichio Honda  *
38327dc04d71SMichio Honda  * This option will enable or disable the use of the automatic generation of
38337dc04d71SMichio Honda  * ASCONF chunks to add and delete addresses to an existing association.  Note
38347dc04d71SMichio Honda  * that this option has two caveats namely: a) it only affects sockets that
38357dc04d71SMichio Honda  * are bound to all addresses available to the SCTP stack, and b) the system
38367dc04d71SMichio Honda  * administrator may have an overriding control that turns the ASCONF feature
38377dc04d71SMichio Honda  * off no matter what setting the socket option may have.
38387dc04d71SMichio Honda  * This option expects an integer boolean flag, where a non-zero value turns on
38397dc04d71SMichio Honda  * the option, and a zero value turns off the option.
38407dc04d71SMichio Honda  * Note. In this implementation, socket operation overrides default parameter
38417dc04d71SMichio Honda  * being set by sysctl as well as FreeBSD implementation
38427dc04d71SMichio Honda  */
sctp_setsockopt_auto_asconf(struct sock * sk,int * val,unsigned int optlen)3843c9abc2c1SChristoph Hellwig static int sctp_setsockopt_auto_asconf(struct sock *sk, int *val,
38447dc04d71SMichio Honda 					unsigned int optlen)
38457dc04d71SMichio Honda {
38467dc04d71SMichio Honda 	struct sctp_sock *sp = sctp_sk(sk);
38477dc04d71SMichio Honda 
38487dc04d71SMichio Honda 	if (optlen < sizeof(int))
38497dc04d71SMichio Honda 		return -EINVAL;
3850c9abc2c1SChristoph Hellwig 	if (!sctp_is_ep_boundall(sk) && *val)
38517dc04d71SMichio Honda 		return -EINVAL;
3852c9abc2c1SChristoph Hellwig 	if ((*val && sp->do_auto_asconf) || (!*val && !sp->do_auto_asconf))
38537dc04d71SMichio Honda 		return 0;
38547dc04d71SMichio Honda 
38552d45a02dSMarcelo Ricardo Leitner 	spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock);
3856c9abc2c1SChristoph Hellwig 	if (*val == 0 && sp->do_auto_asconf) {
38577dc04d71SMichio Honda 		list_del(&sp->auto_asconf_list);
38587dc04d71SMichio Honda 		sp->do_auto_asconf = 0;
3859c9abc2c1SChristoph Hellwig 	} else if (*val && !sp->do_auto_asconf) {
38607dc04d71SMichio Honda 		list_add_tail(&sp->auto_asconf_list,
38614db67e80SEric W. Biederman 		    &sock_net(sk)->sctp.auto_asconf_splist);
38627dc04d71SMichio Honda 		sp->do_auto_asconf = 1;
38637dc04d71SMichio Honda 	}
38642d45a02dSMarcelo Ricardo Leitner 	spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock);
38657dc04d71SMichio Honda 	return 0;
38667dc04d71SMichio Honda }
38677dc04d71SMichio Honda 
38685aa93bcfSNeil Horman /*
38695aa93bcfSNeil Horman  * SCTP_PEER_ADDR_THLDS
38705aa93bcfSNeil Horman  *
38715aa93bcfSNeil Horman  * This option allows us to alter the partially failed threshold for one or all
38725aa93bcfSNeil Horman  * transports in an association.  See Section 6.1 of:
38735aa93bcfSNeil Horman  * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt
38745aa93bcfSNeil Horman  */
sctp_setsockopt_paddr_thresholds(struct sock * sk,struct sctp_paddrthlds_v2 * val,unsigned int optlen,bool v2)38755aa93bcfSNeil Horman static int sctp_setsockopt_paddr_thresholds(struct sock *sk,
3876b0ac3bb8SChristoph Hellwig 					    struct sctp_paddrthlds_v2 *val,
3877d467ac0aSXin Long 					    unsigned int optlen, bool v2)
38785aa93bcfSNeil Horman {
38795aa93bcfSNeil Horman 	struct sctp_transport *trans;
38805aa93bcfSNeil Horman 	struct sctp_association *asoc;
3881d467ac0aSXin Long 	int len;
38825aa93bcfSNeil Horman 
3883b0ac3bb8SChristoph Hellwig 	len = v2 ? sizeof(*val) : sizeof(struct sctp_paddrthlds);
3884d467ac0aSXin Long 	if (optlen < len)
38855aa93bcfSNeil Horman 		return -EINVAL;
38865aa93bcfSNeil Horman 
3887b0ac3bb8SChristoph Hellwig 	if (v2 && val->spt_pathpfthld > val->spt_pathcpthld)
3888d467ac0aSXin Long 		return -EINVAL;
3889d467ac0aSXin Long 
3890b0ac3bb8SChristoph Hellwig 	if (!sctp_is_any(sk, (const union sctp_addr *)&val->spt_address)) {
3891b0ac3bb8SChristoph Hellwig 		trans = sctp_addr_id2transport(sk, &val->spt_address,
3892b0ac3bb8SChristoph Hellwig 					       val->spt_assoc_id);
38938add543eSXin Long 		if (!trans)
38945aa93bcfSNeil Horman 			return -ENOENT;
38958add543eSXin Long 
3896b0ac3bb8SChristoph Hellwig 		if (val->spt_pathmaxrxt)
3897b0ac3bb8SChristoph Hellwig 			trans->pathmaxrxt = val->spt_pathmaxrxt;
3898d467ac0aSXin Long 		if (v2)
3899b0ac3bb8SChristoph Hellwig 			trans->ps_retrans = val->spt_pathcpthld;
3900b0ac3bb8SChristoph Hellwig 		trans->pf_retrans = val->spt_pathpfthld;
39018add543eSXin Long 
39028add543eSXin Long 		return 0;
39038add543eSXin Long 	}
39048add543eSXin Long 
3905b0ac3bb8SChristoph Hellwig 	asoc = sctp_id2assoc(sk, val->spt_assoc_id);
3906b0ac3bb8SChristoph Hellwig 	if (!asoc && val->spt_assoc_id != SCTP_FUTURE_ASSOC &&
39078add543eSXin Long 	    sctp_style(sk, UDP))
39088add543eSXin Long 		return -EINVAL;
39098add543eSXin Long 
39108add543eSXin Long 	if (asoc) {
39115aa93bcfSNeil Horman 		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
39125aa93bcfSNeil Horman 				    transports) {
3913b0ac3bb8SChristoph Hellwig 			if (val->spt_pathmaxrxt)
3914b0ac3bb8SChristoph Hellwig 				trans->pathmaxrxt = val->spt_pathmaxrxt;
3915d467ac0aSXin Long 			if (v2)
3916b0ac3bb8SChristoph Hellwig 				trans->ps_retrans = val->spt_pathcpthld;
3917b0ac3bb8SChristoph Hellwig 			trans->pf_retrans = val->spt_pathpfthld;
39185aa93bcfSNeil Horman 		}
39195aa93bcfSNeil Horman 
3920b0ac3bb8SChristoph Hellwig 		if (val->spt_pathmaxrxt)
3921b0ac3bb8SChristoph Hellwig 			asoc->pathmaxrxt = val->spt_pathmaxrxt;
3922d467ac0aSXin Long 		if (v2)
3923b0ac3bb8SChristoph Hellwig 			asoc->ps_retrans = val->spt_pathcpthld;
3924b0ac3bb8SChristoph Hellwig 		asoc->pf_retrans = val->spt_pathpfthld;
39255aa93bcfSNeil Horman 	} else {
39268add543eSXin Long 		struct sctp_sock *sp = sctp_sk(sk);
39275aa93bcfSNeil Horman 
3928b0ac3bb8SChristoph Hellwig 		if (val->spt_pathmaxrxt)
3929b0ac3bb8SChristoph Hellwig 			sp->pathmaxrxt = val->spt_pathmaxrxt;
3930d467ac0aSXin Long 		if (v2)
3931b0ac3bb8SChristoph Hellwig 			sp->ps_retrans = val->spt_pathcpthld;
3932b0ac3bb8SChristoph Hellwig 		sp->pf_retrans = val->spt_pathpfthld;
39335aa93bcfSNeil Horman 	}
39345aa93bcfSNeil Horman 
39355aa93bcfSNeil Horman 	return 0;
39365aa93bcfSNeil Horman }
39375aa93bcfSNeil Horman 
sctp_setsockopt_recvrcvinfo(struct sock * sk,int * val,unsigned int optlen)3938a98af7c8SChristoph Hellwig static int sctp_setsockopt_recvrcvinfo(struct sock *sk, int *val,
39390d3a421dSGeir Ola Vaagland 				       unsigned int optlen)
39400d3a421dSGeir Ola Vaagland {
39410d3a421dSGeir Ola Vaagland 	if (optlen < sizeof(int))
39420d3a421dSGeir Ola Vaagland 		return -EINVAL;
39430d3a421dSGeir Ola Vaagland 
3944a98af7c8SChristoph Hellwig 	sctp_sk(sk)->recvrcvinfo = (*val == 0) ? 0 : 1;
39450d3a421dSGeir Ola Vaagland 
39460d3a421dSGeir Ola Vaagland 	return 0;
39470d3a421dSGeir Ola Vaagland }
39480d3a421dSGeir Ola Vaagland 
sctp_setsockopt_recvnxtinfo(struct sock * sk,int * val,unsigned int optlen)3949cfa6fde2SChristoph Hellwig static int sctp_setsockopt_recvnxtinfo(struct sock *sk, int *val,
39502347c80fSGeir Ola Vaagland 				       unsigned int optlen)
39512347c80fSGeir Ola Vaagland {
39522347c80fSGeir Ola Vaagland 	if (optlen < sizeof(int))
39532347c80fSGeir Ola Vaagland 		return -EINVAL;
39542347c80fSGeir Ola Vaagland 
3955cfa6fde2SChristoph Hellwig 	sctp_sk(sk)->recvnxtinfo = (*val == 0) ? 0 : 1;
39562347c80fSGeir Ola Vaagland 
39572347c80fSGeir Ola Vaagland 	return 0;
39582347c80fSGeir Ola Vaagland }
39592347c80fSGeir Ola Vaagland 
sctp_setsockopt_pr_supported(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)396028aa4c26SXin Long static int sctp_setsockopt_pr_supported(struct sock *sk,
39614a97fa4fSChristoph Hellwig 					struct sctp_assoc_value *params,
396228aa4c26SXin Long 					unsigned int optlen)
396328aa4c26SXin Long {
3964fb195605SXin Long 	struct sctp_association *asoc;
396528aa4c26SXin Long 
39664a97fa4fSChristoph Hellwig 	if (optlen != sizeof(*params))
3967cc3ccf26SXin Long 		return -EINVAL;
396828aa4c26SXin Long 
39694a97fa4fSChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
39704a97fa4fSChristoph Hellwig 	if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
3971fb195605SXin Long 	    sctp_style(sk, UDP))
3972fb195605SXin Long 		return -EINVAL;
3973fb195605SXin Long 
39744a97fa4fSChristoph Hellwig 	sctp_sk(sk)->ep->prsctp_enable = !!params->assoc_value;
397528aa4c26SXin Long 
3976cc3ccf26SXin Long 	return 0;
397728aa4c26SXin Long }
397828aa4c26SXin Long 
sctp_setsockopt_default_prinfo(struct sock * sk,struct sctp_default_prinfo * info,unsigned int optlen)3979f959fb44SXin Long static int sctp_setsockopt_default_prinfo(struct sock *sk,
3980ac37435bSChristoph Hellwig 					  struct sctp_default_prinfo *info,
3981f959fb44SXin Long 					  unsigned int optlen)
3982f959fb44SXin Long {
39833a583059SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
3984f959fb44SXin Long 	struct sctp_association *asoc;
3985f959fb44SXin Long 	int retval = -EINVAL;
3986f959fb44SXin Long 
3987ac37435bSChristoph Hellwig 	if (optlen != sizeof(*info))
3988f959fb44SXin Long 		goto out;
3989f959fb44SXin Long 
3990ac37435bSChristoph Hellwig 	if (info->pr_policy & ~SCTP_PR_SCTP_MASK)
3991f959fb44SXin Long 		goto out;
3992f959fb44SXin Long 
3993ac37435bSChristoph Hellwig 	if (info->pr_policy == SCTP_PR_SCTP_NONE)
3994ac37435bSChristoph Hellwig 		info->pr_value = 0;
3995f959fb44SXin Long 
3996ac37435bSChristoph Hellwig 	asoc = sctp_id2assoc(sk, info->pr_assoc_id);
3997ac37435bSChristoph Hellwig 	if (!asoc && info->pr_assoc_id > SCTP_ALL_ASSOC &&
39983a583059SXin Long 	    sctp_style(sk, UDP))
39993a583059SXin Long 		goto out;
40003a583059SXin Long 
40013a583059SXin Long 	retval = 0;
40023a583059SXin Long 
4003f959fb44SXin Long 	if (asoc) {
4004ac37435bSChristoph Hellwig 		SCTP_PR_SET_POLICY(asoc->default_flags, info->pr_policy);
4005ac37435bSChristoph Hellwig 		asoc->default_timetolive = info->pr_value;
4006f959fb44SXin Long 		goto out;
4007f959fb44SXin Long 	}
4008f959fb44SXin Long 
4009cbb45c6cSXin Long 	if (sctp_style(sk, TCP))
4010ac37435bSChristoph Hellwig 		info->pr_assoc_id = SCTP_FUTURE_ASSOC;
4011cbb45c6cSXin Long 
4012ac37435bSChristoph Hellwig 	if (info->pr_assoc_id == SCTP_FUTURE_ASSOC ||
4013ac37435bSChristoph Hellwig 	    info->pr_assoc_id == SCTP_ALL_ASSOC) {
4014ac37435bSChristoph Hellwig 		SCTP_PR_SET_POLICY(sp->default_flags, info->pr_policy);
4015ac37435bSChristoph Hellwig 		sp->default_timetolive = info->pr_value;
40163a583059SXin Long 	}
40173a583059SXin Long 
4018ac37435bSChristoph Hellwig 	if (info->pr_assoc_id == SCTP_CURRENT_ASSOC ||
4019ac37435bSChristoph Hellwig 	    info->pr_assoc_id == SCTP_ALL_ASSOC) {
40203a583059SXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
4021ac37435bSChristoph Hellwig 			SCTP_PR_SET_POLICY(asoc->default_flags,
4022ac37435bSChristoph Hellwig 					   info->pr_policy);
4023ac37435bSChristoph Hellwig 			asoc->default_timetolive = info->pr_value;
40243a583059SXin Long 		}
40253a583059SXin Long 	}
4026f959fb44SXin Long 
4027f959fb44SXin Long out:
4028f959fb44SXin Long 	return retval;
4029f959fb44SXin Long }
4030f959fb44SXin Long 
sctp_setsockopt_reconfig_supported(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)4031c0d8bab6SXin Long static int sctp_setsockopt_reconfig_supported(struct sock *sk,
40323f49f720SChristoph Hellwig 					      struct sctp_assoc_value *params,
4033c0d8bab6SXin Long 					      unsigned int optlen)
4034c0d8bab6SXin Long {
4035c0d8bab6SXin Long 	struct sctp_association *asoc;
4036c0d8bab6SXin Long 	int retval = -EINVAL;
4037c0d8bab6SXin Long 
40383f49f720SChristoph Hellwig 	if (optlen != sizeof(*params))
4039c0d8bab6SXin Long 		goto out;
4040c0d8bab6SXin Long 
40413f49f720SChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
40423f49f720SChristoph Hellwig 	if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
4043acce7f3bSXin Long 	    sctp_style(sk, UDP))
4044c0d8bab6SXin Long 		goto out;
4045acce7f3bSXin Long 
40463f49f720SChristoph Hellwig 	sctp_sk(sk)->ep->reconf_enable = !!params->assoc_value;
4047c0d8bab6SXin Long 
4048c0d8bab6SXin Long 	retval = 0;
4049c0d8bab6SXin Long 
4050c0d8bab6SXin Long out:
4051c0d8bab6SXin Long 	return retval;
4052c0d8bab6SXin Long }
4053c0d8bab6SXin Long 
sctp_setsockopt_enable_strreset(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)40549fb657aeSXin Long static int sctp_setsockopt_enable_strreset(struct sock *sk,
4055356dc6f1SChristoph Hellwig 					   struct sctp_assoc_value *params,
40569fb657aeSXin Long 					   unsigned int optlen)
40579fb657aeSXin Long {
405899a62135SXin Long 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
40599fb657aeSXin Long 	struct sctp_association *asoc;
40609fb657aeSXin Long 	int retval = -EINVAL;
40619fb657aeSXin Long 
4062356dc6f1SChristoph Hellwig 	if (optlen != sizeof(*params))
40639fb657aeSXin Long 		goto out;
40649fb657aeSXin Long 
4065356dc6f1SChristoph Hellwig 	if (params->assoc_value & (~SCTP_ENABLE_STRRESET_MASK))
40669fb657aeSXin Long 		goto out;
40679fb657aeSXin Long 
4068356dc6f1SChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
4069356dc6f1SChristoph Hellwig 	if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
407099a62135SXin Long 	    sctp_style(sk, UDP))
407199a62135SXin Long 		goto out;
407299a62135SXin Long 
407399a62135SXin Long 	retval = 0;
407499a62135SXin Long 
40759fb657aeSXin Long 	if (asoc) {
4076356dc6f1SChristoph Hellwig 		asoc->strreset_enable = params->assoc_value;
40779fb657aeSXin Long 		goto out;
40789fb657aeSXin Long 	}
40799fb657aeSXin Long 
40809430ff99SXin Long 	if (sctp_style(sk, TCP))
4081356dc6f1SChristoph Hellwig 		params->assoc_id = SCTP_FUTURE_ASSOC;
40829430ff99SXin Long 
4083356dc6f1SChristoph Hellwig 	if (params->assoc_id == SCTP_FUTURE_ASSOC ||
4084356dc6f1SChristoph Hellwig 	    params->assoc_id == SCTP_ALL_ASSOC)
4085356dc6f1SChristoph Hellwig 		ep->strreset_enable = params->assoc_value;
408699a62135SXin Long 
4087356dc6f1SChristoph Hellwig 	if (params->assoc_id == SCTP_CURRENT_ASSOC ||
4088356dc6f1SChristoph Hellwig 	    params->assoc_id == SCTP_ALL_ASSOC)
408999a62135SXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs)
4090356dc6f1SChristoph Hellwig 			asoc->strreset_enable = params->assoc_value;
40919fb657aeSXin Long 
40929fb657aeSXin Long out:
40939fb657aeSXin Long 	return retval;
40949fb657aeSXin Long }
40959fb657aeSXin Long 
sctp_setsockopt_reset_streams(struct sock * sk,struct sctp_reset_streams * params,unsigned int optlen)40967f9d68acSXin Long static int sctp_setsockopt_reset_streams(struct sock *sk,
4097d4922434SChristoph Hellwig 					 struct sctp_reset_streams *params,
40987f9d68acSXin Long 					 unsigned int optlen)
40997f9d68acSXin Long {
41007f9d68acSXin Long 	struct sctp_association *asoc;
41017f9d68acSXin Long 
41022342b8d9SXin Long 	if (optlen < sizeof(*params))
41037f9d68acSXin Long 		return -EINVAL;
41045960cefaSMarcelo Ricardo Leitner 	/* srs_number_streams is u16, so optlen can't be bigger than this. */
41055960cefaSMarcelo Ricardo Leitner 	optlen = min_t(unsigned int, optlen, USHRT_MAX +
41065960cefaSMarcelo Ricardo Leitner 					     sizeof(__u16) * sizeof(*params));
41077f9d68acSXin Long 
41082342b8d9SXin Long 	if (params->srs_number_streams * sizeof(__u16) >
41092342b8d9SXin Long 	    optlen - sizeof(*params))
4110d4922434SChristoph Hellwig 		return -EINVAL;
41112342b8d9SXin Long 
41127f9d68acSXin Long 	asoc = sctp_id2assoc(sk, params->srs_assoc_id);
41137f9d68acSXin Long 	if (!asoc)
4114d4922434SChristoph Hellwig 		return -EINVAL;
41157f9d68acSXin Long 
4116d4922434SChristoph Hellwig 	return sctp_send_reset_streams(asoc, params);
41177f9d68acSXin Long }
41187f9d68acSXin Long 
sctp_setsockopt_reset_assoc(struct sock * sk,sctp_assoc_t * associd,unsigned int optlen)4119b97d20ceSChristoph Hellwig static int sctp_setsockopt_reset_assoc(struct sock *sk, sctp_assoc_t *associd,
4120a92ce1a4SXin Long 				       unsigned int optlen)
4121a92ce1a4SXin Long {
4122a92ce1a4SXin Long 	struct sctp_association *asoc;
4123a92ce1a4SXin Long 
4124b97d20ceSChristoph Hellwig 	if (optlen != sizeof(*associd))
4125b97d20ceSChristoph Hellwig 		return -EINVAL;
4126a92ce1a4SXin Long 
4127b97d20ceSChristoph Hellwig 	asoc = sctp_id2assoc(sk, *associd);
4128a92ce1a4SXin Long 	if (!asoc)
4129b97d20ceSChristoph Hellwig 		return -EINVAL;
4130a92ce1a4SXin Long 
4131b97d20ceSChristoph Hellwig 	return sctp_send_reset_assoc(asoc);
4132a92ce1a4SXin Long }
4133a92ce1a4SXin Long 
sctp_setsockopt_add_streams(struct sock * sk,struct sctp_add_streams * params,unsigned int optlen)4134242bd2d5SXin Long static int sctp_setsockopt_add_streams(struct sock *sk,
41354d6fb260SChristoph Hellwig 				       struct sctp_add_streams *params,
4136242bd2d5SXin Long 				       unsigned int optlen)
4137242bd2d5SXin Long {
4138242bd2d5SXin Long 	struct sctp_association *asoc;
4139242bd2d5SXin Long 
41404d6fb260SChristoph Hellwig 	if (optlen != sizeof(*params))
41414d6fb260SChristoph Hellwig 		return -EINVAL;
4142242bd2d5SXin Long 
41434d6fb260SChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->sas_assoc_id);
4144242bd2d5SXin Long 	if (!asoc)
41454d6fb260SChristoph Hellwig 		return -EINVAL;
4146242bd2d5SXin Long 
41474d6fb260SChristoph Hellwig 	return sctp_send_add_streams(asoc, params);
4148242bd2d5SXin Long }
4149242bd2d5SXin Long 
sctp_setsockopt_scheduler(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)415013aa8770SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler(struct sock *sk,
41514d2fba3aSChristoph Hellwig 				     struct sctp_assoc_value *params,
415213aa8770SMarcelo Ricardo Leitner 				     unsigned int optlen)
415313aa8770SMarcelo Ricardo Leitner {
41547efba10dSXin Long 	struct sctp_sock *sp = sctp_sk(sk);
415513aa8770SMarcelo Ricardo Leitner 	struct sctp_association *asoc;
41567efba10dSXin Long 	int retval = 0;
415713aa8770SMarcelo Ricardo Leitner 
41584d2fba3aSChristoph Hellwig 	if (optlen < sizeof(*params))
41597efba10dSXin Long 		return -EINVAL;
416013aa8770SMarcelo Ricardo Leitner 
41614d2fba3aSChristoph Hellwig 	if (params->assoc_value > SCTP_SS_MAX)
41627efba10dSXin Long 		return -EINVAL;
416313aa8770SMarcelo Ricardo Leitner 
41644d2fba3aSChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
41654d2fba3aSChristoph Hellwig 	if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
41667efba10dSXin Long 	    sctp_style(sk, UDP))
41677efba10dSXin Long 		return -EINVAL;
416813aa8770SMarcelo Ricardo Leitner 
41697efba10dSXin Long 	if (asoc)
41704d2fba3aSChristoph Hellwig 		return sctp_sched_set_sched(asoc, params->assoc_value);
417113aa8770SMarcelo Ricardo Leitner 
4172b59c19d9SXin Long 	if (sctp_style(sk, TCP))
41734d2fba3aSChristoph Hellwig 		params->assoc_id = SCTP_FUTURE_ASSOC;
4174b59c19d9SXin Long 
41754d2fba3aSChristoph Hellwig 	if (params->assoc_id == SCTP_FUTURE_ASSOC ||
41764d2fba3aSChristoph Hellwig 	    params->assoc_id == SCTP_ALL_ASSOC)
41774d2fba3aSChristoph Hellwig 		sp->default_ss = params->assoc_value;
41787efba10dSXin Long 
41794d2fba3aSChristoph Hellwig 	if (params->assoc_id == SCTP_CURRENT_ASSOC ||
41804d2fba3aSChristoph Hellwig 	    params->assoc_id == SCTP_ALL_ASSOC) {
41817efba10dSXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
41827efba10dSXin Long 			int ret = sctp_sched_set_sched(asoc,
41834d2fba3aSChristoph Hellwig 						       params->assoc_value);
41847efba10dSXin Long 
41857efba10dSXin Long 			if (ret && !retval)
41867efba10dSXin Long 				retval = ret;
41877efba10dSXin Long 		}
41887efba10dSXin Long 	}
41897efba10dSXin Long 
419013aa8770SMarcelo Ricardo Leitner 	return retval;
419113aa8770SMarcelo Ricardo Leitner }
419213aa8770SMarcelo Ricardo Leitner 
sctp_setsockopt_scheduler_value(struct sock * sk,struct sctp_stream_value * params,unsigned int optlen)41930ccdf3c7SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler_value(struct sock *sk,
4194d636e7f3SChristoph Hellwig 					   struct sctp_stream_value *params,
41950ccdf3c7SMarcelo Ricardo Leitner 					   unsigned int optlen)
41960ccdf3c7SMarcelo Ricardo Leitner {
4197e7f28248SXin Long 	struct sctp_association *asoc;
41980ccdf3c7SMarcelo Ricardo Leitner 	int retval = -EINVAL;
41990ccdf3c7SMarcelo Ricardo Leitner 
4200d636e7f3SChristoph Hellwig 	if (optlen < sizeof(*params))
42010ccdf3c7SMarcelo Ricardo Leitner 		goto out;
42020ccdf3c7SMarcelo Ricardo Leitner 
4203d636e7f3SChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
4204d636e7f3SChristoph Hellwig 	if (!asoc && params->assoc_id != SCTP_CURRENT_ASSOC &&
4205e7f28248SXin Long 	    sctp_style(sk, UDP))
42060ccdf3c7SMarcelo Ricardo Leitner 		goto out;
42070ccdf3c7SMarcelo Ricardo Leitner 
4208e7f28248SXin Long 	if (asoc) {
4209d636e7f3SChristoph Hellwig 		retval = sctp_sched_set_value(asoc, params->stream_id,
4210d636e7f3SChristoph Hellwig 					      params->stream_value, GFP_KERNEL);
4211e7f28248SXin Long 		goto out;
4212e7f28248SXin Long 	}
4213e7f28248SXin Long 
4214e7f28248SXin Long 	retval = 0;
4215e7f28248SXin Long 
4216e7f28248SXin Long 	list_for_each_entry(asoc, &sctp_sk(sk)->ep->asocs, asocs) {
4217d636e7f3SChristoph Hellwig 		int ret = sctp_sched_set_value(asoc, params->stream_id,
4218d636e7f3SChristoph Hellwig 					       params->stream_value,
4219d636e7f3SChristoph Hellwig 					       GFP_KERNEL);
4220e7f28248SXin Long 		if (ret && !retval) /* try to return the 1st error. */
4221e7f28248SXin Long 			retval = ret;
4222e7f28248SXin Long 	}
42230ccdf3c7SMarcelo Ricardo Leitner 
42240ccdf3c7SMarcelo Ricardo Leitner out:
42250ccdf3c7SMarcelo Ricardo Leitner 	return retval;
42260ccdf3c7SMarcelo Ricardo Leitner }
42270ccdf3c7SMarcelo Ricardo Leitner 
sctp_setsockopt_interleaving_supported(struct sock * sk,struct sctp_assoc_value * p,unsigned int optlen)4228772a5869SXin Long static int sctp_setsockopt_interleaving_supported(struct sock *sk,
42295b8d3b24SChristoph Hellwig 						  struct sctp_assoc_value *p,
4230772a5869SXin Long 						  unsigned int optlen)
4231772a5869SXin Long {
4232772a5869SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
42332e7709d1SXin Long 	struct sctp_association *asoc;
4234772a5869SXin Long 
42355b8d3b24SChristoph Hellwig 	if (optlen < sizeof(*p))
42365b8d3b24SChristoph Hellwig 		return -EINVAL;
4237772a5869SXin Long 
42385b8d3b24SChristoph Hellwig 	asoc = sctp_id2assoc(sk, p->assoc_id);
42395b8d3b24SChristoph Hellwig 	if (!asoc && p->assoc_id != SCTP_FUTURE_ASSOC && sctp_style(sk, UDP))
42405b8d3b24SChristoph Hellwig 		return -EINVAL;
4241772a5869SXin Long 
42422e7709d1SXin Long 	if (!sock_net(sk)->sctp.intl_enable || !sp->frag_interleave) {
42435b8d3b24SChristoph Hellwig 		return -EPERM;
4244772a5869SXin Long 	}
4245772a5869SXin Long 
42465b8d3b24SChristoph Hellwig 	sp->ep->intl_enable = !!p->assoc_value;
42475b8d3b24SChristoph Hellwig 	return 0;
4248772a5869SXin Long }
4249772a5869SXin Long 
sctp_setsockopt_reuse_port(struct sock * sk,int * val,unsigned int optlen)4250a4262466SChristoph Hellwig static int sctp_setsockopt_reuse_port(struct sock *sk, int *val,
4251b0e9a2feSXin Long 				      unsigned int optlen)
4252b0e9a2feSXin Long {
4253b0e9a2feSXin Long 	if (!sctp_style(sk, TCP))
4254b0e9a2feSXin Long 		return -EOPNOTSUPP;
4255b0e9a2feSXin Long 
4256b0e9a2feSXin Long 	if (sctp_sk(sk)->ep->base.bind_addr.port)
4257b0e9a2feSXin Long 		return -EFAULT;
4258b0e9a2feSXin Long 
4259b0e9a2feSXin Long 	if (optlen < sizeof(int))
4260b0e9a2feSXin Long 		return -EINVAL;
4261b0e9a2feSXin Long 
4262a4262466SChristoph Hellwig 	sctp_sk(sk)->reuse = !!*val;
4263b0e9a2feSXin Long 
4264b0e9a2feSXin Long 	return 0;
4265b0e9a2feSXin Long }
4266b0e9a2feSXin Long 
sctp_assoc_ulpevent_type_set(struct sctp_event * param,struct sctp_association * asoc)4267d251f05eSXin Long static int sctp_assoc_ulpevent_type_set(struct sctp_event *param,
4268d251f05eSXin Long 					struct sctp_association *asoc)
4269480ba9c1SXin Long {
4270480ba9c1SXin Long 	struct sctp_ulpevent *event;
4271480ba9c1SXin Long 
4272d251f05eSXin Long 	sctp_ulpevent_type_set(&asoc->subscribe, param->se_type, param->se_on);
4273480ba9c1SXin Long 
4274d251f05eSXin Long 	if (param->se_type == SCTP_SENDER_DRY_EVENT && param->se_on) {
4275480ba9c1SXin Long 		if (sctp_outq_is_empty(&asoc->outqueue)) {
4276480ba9c1SXin Long 			event = sctp_ulpevent_make_sender_dry_event(asoc,
4277480ba9c1SXin Long 					GFP_USER | __GFP_NOWARN);
4278d251f05eSXin Long 			if (!event)
4279d251f05eSXin Long 				return -ENOMEM;
4280480ba9c1SXin Long 
4281480ba9c1SXin Long 			asoc->stream.si->enqueue_event(&asoc->ulpq, event);
4282480ba9c1SXin Long 		}
4283480ba9c1SXin Long 	}
4284480ba9c1SXin Long 
4285d251f05eSXin Long 	return 0;
4286d251f05eSXin Long }
4287d251f05eSXin Long 
sctp_setsockopt_event(struct sock * sk,struct sctp_event * param,unsigned int optlen)4288565059cbSChristoph Hellwig static int sctp_setsockopt_event(struct sock *sk, struct sctp_event *param,
4289d251f05eSXin Long 				 unsigned int optlen)
4290d251f05eSXin Long {
4291d251f05eSXin Long 	struct sctp_sock *sp = sctp_sk(sk);
4292d251f05eSXin Long 	struct sctp_association *asoc;
4293d251f05eSXin Long 	int retval = 0;
4294d251f05eSXin Long 
4295565059cbSChristoph Hellwig 	if (optlen < sizeof(*param))
4296d251f05eSXin Long 		return -EINVAL;
4297d251f05eSXin Long 
4298565059cbSChristoph Hellwig 	if (param->se_type < SCTP_SN_TYPE_BASE ||
4299565059cbSChristoph Hellwig 	    param->se_type > SCTP_SN_TYPE_MAX)
4300d251f05eSXin Long 		return -EINVAL;
4301d251f05eSXin Long 
4302565059cbSChristoph Hellwig 	asoc = sctp_id2assoc(sk, param->se_assoc_id);
4303565059cbSChristoph Hellwig 	if (!asoc && param->se_assoc_id > SCTP_ALL_ASSOC &&
4304d251f05eSXin Long 	    sctp_style(sk, UDP))
4305d251f05eSXin Long 		return -EINVAL;
4306d251f05eSXin Long 
4307d251f05eSXin Long 	if (asoc)
4308565059cbSChristoph Hellwig 		return sctp_assoc_ulpevent_type_set(param, asoc);
4309d251f05eSXin Long 
431099518619SXin Long 	if (sctp_style(sk, TCP))
4311565059cbSChristoph Hellwig 		param->se_assoc_id = SCTP_FUTURE_ASSOC;
431299518619SXin Long 
4313565059cbSChristoph Hellwig 	if (param->se_assoc_id == SCTP_FUTURE_ASSOC ||
4314565059cbSChristoph Hellwig 	    param->se_assoc_id == SCTP_ALL_ASSOC)
4315d251f05eSXin Long 		sctp_ulpevent_type_set(&sp->subscribe,
4316565059cbSChristoph Hellwig 				       param->se_type, param->se_on);
4317d251f05eSXin Long 
4318565059cbSChristoph Hellwig 	if (param->se_assoc_id == SCTP_CURRENT_ASSOC ||
4319565059cbSChristoph Hellwig 	    param->se_assoc_id == SCTP_ALL_ASSOC) {
4320d251f05eSXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
4321565059cbSChristoph Hellwig 			int ret = sctp_assoc_ulpevent_type_set(param, asoc);
4322d251f05eSXin Long 
4323d251f05eSXin Long 			if (ret && !retval)
4324d251f05eSXin Long 				retval = ret;
4325d251f05eSXin Long 		}
4326d251f05eSXin Long 	}
4327d251f05eSXin Long 
4328480ba9c1SXin Long 	return retval;
4329480ba9c1SXin Long }
4330480ba9c1SXin Long 
sctp_setsockopt_asconf_supported(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)4331df2c71ffSXin Long static int sctp_setsockopt_asconf_supported(struct sock *sk,
43329263ac97SChristoph Hellwig 					    struct sctp_assoc_value *params,
4333df2c71ffSXin Long 					    unsigned int optlen)
4334df2c71ffSXin Long {
4335df2c71ffSXin Long 	struct sctp_association *asoc;
4336df2c71ffSXin Long 	struct sctp_endpoint *ep;
4337df2c71ffSXin Long 	int retval = -EINVAL;
4338df2c71ffSXin Long 
43399263ac97SChristoph Hellwig 	if (optlen != sizeof(*params))
4340df2c71ffSXin Long 		goto out;
4341df2c71ffSXin Long 
43429263ac97SChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
43439263ac97SChristoph Hellwig 	if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
4344df2c71ffSXin Long 	    sctp_style(sk, UDP))
4345df2c71ffSXin Long 		goto out;
4346df2c71ffSXin Long 
4347df2c71ffSXin Long 	ep = sctp_sk(sk)->ep;
43489263ac97SChristoph Hellwig 	ep->asconf_enable = !!params->assoc_value;
4349df2c71ffSXin Long 
4350df2c71ffSXin Long 	if (ep->asconf_enable && ep->auth_enable) {
4351df2c71ffSXin Long 		sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
4352df2c71ffSXin Long 		sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
4353df2c71ffSXin Long 	}
4354df2c71ffSXin Long 
4355df2c71ffSXin Long 	retval = 0;
4356df2c71ffSXin Long 
4357df2c71ffSXin Long out:
4358df2c71ffSXin Long 	return retval;
4359df2c71ffSXin Long }
4360df2c71ffSXin Long 
sctp_setsockopt_auth_supported(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)436156dd525aSXin Long static int sctp_setsockopt_auth_supported(struct sock *sk,
4362963855a9SChristoph Hellwig 					  struct sctp_assoc_value *params,
436356dd525aSXin Long 					  unsigned int optlen)
436456dd525aSXin Long {
436556dd525aSXin Long 	struct sctp_association *asoc;
436656dd525aSXin Long 	struct sctp_endpoint *ep;
436756dd525aSXin Long 	int retval = -EINVAL;
436856dd525aSXin Long 
4369963855a9SChristoph Hellwig 	if (optlen != sizeof(*params))
437056dd525aSXin Long 		goto out;
437156dd525aSXin Long 
4372963855a9SChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
4373963855a9SChristoph Hellwig 	if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
437456dd525aSXin Long 	    sctp_style(sk, UDP))
437556dd525aSXin Long 		goto out;
437656dd525aSXin Long 
437756dd525aSXin Long 	ep = sctp_sk(sk)->ep;
4378963855a9SChristoph Hellwig 	if (params->assoc_value) {
437956dd525aSXin Long 		retval = sctp_auth_init(ep, GFP_KERNEL);
438056dd525aSXin Long 		if (retval)
438156dd525aSXin Long 			goto out;
438256dd525aSXin Long 		if (ep->asconf_enable) {
438356dd525aSXin Long 			sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
438456dd525aSXin Long 			sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
438556dd525aSXin Long 		}
438656dd525aSXin Long 	}
438756dd525aSXin Long 
4388963855a9SChristoph Hellwig 	ep->auth_enable = !!params->assoc_value;
438956dd525aSXin Long 	retval = 0;
439056dd525aSXin Long 
439156dd525aSXin Long out:
439256dd525aSXin Long 	return retval;
439356dd525aSXin Long }
439456dd525aSXin Long 
sctp_setsockopt_ecn_supported(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)4395d5886b91SXin Long static int sctp_setsockopt_ecn_supported(struct sock *sk,
439692c4f172SChristoph Hellwig 					 struct sctp_assoc_value *params,
4397d5886b91SXin Long 					 unsigned int optlen)
4398d5886b91SXin Long {
4399d5886b91SXin Long 	struct sctp_association *asoc;
4400d5886b91SXin Long 	int retval = -EINVAL;
4401d5886b91SXin Long 
440292c4f172SChristoph Hellwig 	if (optlen != sizeof(*params))
4403d5886b91SXin Long 		goto out;
4404d5886b91SXin Long 
440592c4f172SChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
440692c4f172SChristoph Hellwig 	if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
4407d5886b91SXin Long 	    sctp_style(sk, UDP))
4408d5886b91SXin Long 		goto out;
4409d5886b91SXin Long 
441092c4f172SChristoph Hellwig 	sctp_sk(sk)->ep->ecn_enable = !!params->assoc_value;
4411d5886b91SXin Long 	retval = 0;
4412d5886b91SXin Long 
4413d5886b91SXin Long out:
4414d5886b91SXin Long 	return retval;
4415d5886b91SXin Long }
4416d5886b91SXin Long 
sctp_setsockopt_pf_expose(struct sock * sk,struct sctp_assoc_value * params,unsigned int optlen)44178d2a6935SXin Long static int sctp_setsockopt_pf_expose(struct sock *sk,
441826feba80SChristoph Hellwig 				     struct sctp_assoc_value *params,
44198d2a6935SXin Long 				     unsigned int optlen)
44208d2a6935SXin Long {
44218d2a6935SXin Long 	struct sctp_association *asoc;
44228d2a6935SXin Long 	int retval = -EINVAL;
44238d2a6935SXin Long 
442426feba80SChristoph Hellwig 	if (optlen != sizeof(*params))
44258d2a6935SXin Long 		goto out;
44268d2a6935SXin Long 
442726feba80SChristoph Hellwig 	if (params->assoc_value > SCTP_PF_EXPOSE_MAX)
44288d2a6935SXin Long 		goto out;
44298d2a6935SXin Long 
443026feba80SChristoph Hellwig 	asoc = sctp_id2assoc(sk, params->assoc_id);
443126feba80SChristoph Hellwig 	if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
44328d2a6935SXin Long 	    sctp_style(sk, UDP))
44338d2a6935SXin Long 		goto out;
44348d2a6935SXin Long 
44358d2a6935SXin Long 	if (asoc)
443626feba80SChristoph Hellwig 		asoc->pf_expose = params->assoc_value;
44378d2a6935SXin Long 	else
443826feba80SChristoph Hellwig 		sctp_sk(sk)->pf_expose = params->assoc_value;
44398d2a6935SXin Long 	retval = 0;
44408d2a6935SXin Long 
44418d2a6935SXin Long out:
44428d2a6935SXin Long 	return retval;
44438d2a6935SXin Long }
44448d2a6935SXin Long 
sctp_setsockopt_encap_port(struct sock * sk,struct sctp_udpencaps * encap,unsigned int optlen)44458dba2960SXin Long static int sctp_setsockopt_encap_port(struct sock *sk,
44468dba2960SXin Long 				      struct sctp_udpencaps *encap,
44478dba2960SXin Long 				      unsigned int optlen)
44488dba2960SXin Long {
44498dba2960SXin Long 	struct sctp_association *asoc;
44508dba2960SXin Long 	struct sctp_transport *t;
44518dba2960SXin Long 	__be16 encap_port;
44528dba2960SXin Long 
44538dba2960SXin Long 	if (optlen != sizeof(*encap))
44548dba2960SXin Long 		return -EINVAL;
44558dba2960SXin Long 
44568dba2960SXin Long 	/* If an address other than INADDR_ANY is specified, and
44578dba2960SXin Long 	 * no transport is found, then the request is invalid.
44588dba2960SXin Long 	 */
44598dba2960SXin Long 	encap_port = (__force __be16)encap->sue_port;
44608dba2960SXin Long 	if (!sctp_is_any(sk, (union sctp_addr *)&encap->sue_address)) {
44618dba2960SXin Long 		t = sctp_addr_id2transport(sk, &encap->sue_address,
44628dba2960SXin Long 					   encap->sue_assoc_id);
44638dba2960SXin Long 		if (!t)
44648dba2960SXin Long 			return -EINVAL;
44658dba2960SXin Long 
44668dba2960SXin Long 		t->encap_port = encap_port;
44678dba2960SXin Long 		return 0;
44688dba2960SXin Long 	}
44698dba2960SXin Long 
44708dba2960SXin Long 	/* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the
44718dba2960SXin Long 	 * socket is a one to many style socket, and an association
44728dba2960SXin Long 	 * was not found, then the id was invalid.
44738dba2960SXin Long 	 */
44748dba2960SXin Long 	asoc = sctp_id2assoc(sk, encap->sue_assoc_id);
44758dba2960SXin Long 	if (!asoc && encap->sue_assoc_id != SCTP_FUTURE_ASSOC &&
44768dba2960SXin Long 	    sctp_style(sk, UDP))
44778dba2960SXin Long 		return -EINVAL;
44788dba2960SXin Long 
44798dba2960SXin Long 	/* If changes are for association, also apply encap_port to
44808dba2960SXin Long 	 * each transport.
44818dba2960SXin Long 	 */
44828dba2960SXin Long 	if (asoc) {
44838dba2960SXin Long 		list_for_each_entry(t, &asoc->peer.transport_addr_list,
44848dba2960SXin Long 				    transports)
44858dba2960SXin Long 			t->encap_port = encap_port;
44868dba2960SXin Long 
4487297739bdSXin Long 		asoc->encap_port = encap_port;
44888dba2960SXin Long 		return 0;
44898dba2960SXin Long 	}
44908dba2960SXin Long 
44918dba2960SXin Long 	sctp_sk(sk)->encap_port = encap_port;
44928dba2960SXin Long 	return 0;
44938dba2960SXin Long }
44948dba2960SXin Long 
sctp_setsockopt_probe_interval(struct sock * sk,struct sctp_probeinterval * params,unsigned int optlen)44953190b649SXin Long static int sctp_setsockopt_probe_interval(struct sock *sk,
44963190b649SXin Long 					  struct sctp_probeinterval *params,
44973190b649SXin Long 					  unsigned int optlen)
44983190b649SXin Long {
44993190b649SXin Long 	struct sctp_association *asoc;
45003190b649SXin Long 	struct sctp_transport *t;
45013190b649SXin Long 	__u32 probe_interval;
45023190b649SXin Long 
45033190b649SXin Long 	if (optlen != sizeof(*params))
45043190b649SXin Long 		return -EINVAL;
45053190b649SXin Long 
45063190b649SXin Long 	probe_interval = params->spi_interval;
45073190b649SXin Long 	if (probe_interval && probe_interval < SCTP_PROBE_TIMER_MIN)
45083190b649SXin Long 		return -EINVAL;
45093190b649SXin Long 
45103190b649SXin Long 	/* If an address other than INADDR_ANY is specified, and
45113190b649SXin Long 	 * no transport is found, then the request is invalid.
45123190b649SXin Long 	 */
45133190b649SXin Long 	if (!sctp_is_any(sk, (union sctp_addr *)&params->spi_address)) {
45143190b649SXin Long 		t = sctp_addr_id2transport(sk, &params->spi_address,
45153190b649SXin Long 					   params->spi_assoc_id);
45163190b649SXin Long 		if (!t)
45173190b649SXin Long 			return -EINVAL;
45183190b649SXin Long 
45193190b649SXin Long 		t->probe_interval = msecs_to_jiffies(probe_interval);
45207307e4faSXin Long 		sctp_transport_pl_reset(t);
45213190b649SXin Long 		return 0;
45223190b649SXin Long 	}
45233190b649SXin Long 
45243190b649SXin Long 	/* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the
45253190b649SXin Long 	 * socket is a one to many style socket, and an association
45263190b649SXin Long 	 * was not found, then the id was invalid.
45273190b649SXin Long 	 */
45283190b649SXin Long 	asoc = sctp_id2assoc(sk, params->spi_assoc_id);
45293190b649SXin Long 	if (!asoc && params->spi_assoc_id != SCTP_FUTURE_ASSOC &&
45303190b649SXin Long 	    sctp_style(sk, UDP))
45313190b649SXin Long 		return -EINVAL;
45323190b649SXin Long 
45333190b649SXin Long 	/* If changes are for association, also apply probe_interval to
45343190b649SXin Long 	 * each transport.
45353190b649SXin Long 	 */
45363190b649SXin Long 	if (asoc) {
45377307e4faSXin Long 		list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) {
45383190b649SXin Long 			t->probe_interval = msecs_to_jiffies(probe_interval);
45397307e4faSXin Long 			sctp_transport_pl_reset(t);
45407307e4faSXin Long 		}
45413190b649SXin Long 
45423190b649SXin Long 		asoc->probe_interval = msecs_to_jiffies(probe_interval);
45433190b649SXin Long 		return 0;
45443190b649SXin Long 	}
45453190b649SXin Long 
45463190b649SXin Long 	sctp_sk(sk)->probe_interval = probe_interval;
45473190b649SXin Long 	return 0;
45483190b649SXin Long }
45493190b649SXin Long 
45501da177e4SLinus Torvalds /* API 6.2 setsockopt(), getsockopt()
45511da177e4SLinus Torvalds  *
45521da177e4SLinus Torvalds  * Applications use setsockopt() and getsockopt() to set or retrieve
45531da177e4SLinus Torvalds  * socket options.  Socket options are used to change the default
45541da177e4SLinus Torvalds  * behavior of sockets calls.  They are described in Section 7.
45551da177e4SLinus Torvalds  *
45561da177e4SLinus Torvalds  * The syntax is:
45571da177e4SLinus Torvalds  *
45581da177e4SLinus Torvalds  *   ret = getsockopt(int sd, int level, int optname, void __user *optval,
45591da177e4SLinus Torvalds  *                    int __user *optlen);
45601da177e4SLinus Torvalds  *   ret = setsockopt(int sd, int level, int optname, const void __user *optval,
45611da177e4SLinus Torvalds  *                    int optlen);
45621da177e4SLinus Torvalds  *
45631da177e4SLinus Torvalds  *   sd      - the socket descript.
45641da177e4SLinus Torvalds  *   level   - set to IPPROTO_SCTP for all SCTP options.
45651da177e4SLinus Torvalds  *   optname - the option name.
45661da177e4SLinus Torvalds  *   optval  - the buffer to store the value of the option.
45671da177e4SLinus Torvalds  *   optlen  - the size of the buffer.
45681da177e4SLinus Torvalds  */
sctp_setsockopt(struct sock * sk,int level,int optname,sockptr_t optval,unsigned int optlen)4569dda91928SDaniel Borkmann static int sctp_setsockopt(struct sock *sk, int level, int optname,
4570a7b75c5aSChristoph Hellwig 			   sockptr_t optval, unsigned int optlen)
45711da177e4SLinus Torvalds {
4572ca84bd05SChristoph Hellwig 	void *kopt = NULL;
45731da177e4SLinus Torvalds 	int retval = 0;
45741da177e4SLinus Torvalds 
4575bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname);
45761da177e4SLinus Torvalds 
45771da177e4SLinus Torvalds 	/* I can hardly begin to describe how wrong this is.  This is
45781da177e4SLinus Torvalds 	 * so broken as to be worse than useless.  The API draft
45791da177e4SLinus Torvalds 	 * REALLY is NOT helpful here...  I am not convinced that the
45801da177e4SLinus Torvalds 	 * semantics of setsockopt() with a level OTHER THAN SOL_SCTP
45811da177e4SLinus Torvalds 	 * are at all well-founded.
45821da177e4SLinus Torvalds 	 */
45831da177e4SLinus Torvalds 	if (level != SOL_SCTP) {
45841da177e4SLinus Torvalds 		struct sctp_af *af = sctp_sk(sk)->pf->af;
45856c8983a6SChristoph Hellwig 
45866c8983a6SChristoph Hellwig 		return af->setsockopt(sk, level, optname, optval, optlen);
45871da177e4SLinus Torvalds 	}
45881da177e4SLinus Torvalds 
4589ca84bd05SChristoph Hellwig 	if (optlen > 0) {
45902f3fdd8dSXin Long 		/* Trim it to the biggest size sctp sockopt may need if necessary */
45912f3fdd8dSXin Long 		optlen = min_t(unsigned int, optlen,
45922f3fdd8dSXin Long 			       PAGE_ALIGN(USHRT_MAX +
45932f3fdd8dSXin Long 					  sizeof(__u16) * sizeof(struct sctp_reset_streams)));
4594a7b75c5aSChristoph Hellwig 		kopt = memdup_sockptr(optval, optlen);
4595ca84bd05SChristoph Hellwig 		if (IS_ERR(kopt))
4596ca84bd05SChristoph Hellwig 			return PTR_ERR(kopt);
4597ca84bd05SChristoph Hellwig 	}
4598ca84bd05SChristoph Hellwig 
4599048ed4b6Swangweidong 	lock_sock(sk);
46001da177e4SLinus Torvalds 
46011da177e4SLinus Torvalds 	switch (optname) {
46021da177e4SLinus Torvalds 	case SCTP_SOCKOPT_BINDX_ADD:
46031da177e4SLinus Torvalds 		/* 'optlen' is the size of the addresses buffer. */
46048c7517f5SChristoph Hellwig 		retval = sctp_setsockopt_bindx(sk, kopt, optlen,
46058c7517f5SChristoph Hellwig 					       SCTP_BINDX_ADD_ADDR);
46061da177e4SLinus Torvalds 		break;
46071da177e4SLinus Torvalds 
46081da177e4SLinus Torvalds 	case SCTP_SOCKOPT_BINDX_REM:
46091da177e4SLinus Torvalds 		/* 'optlen' is the size of the addresses buffer. */
46108c7517f5SChristoph Hellwig 		retval = sctp_setsockopt_bindx(sk, kopt, optlen,
46118c7517f5SChristoph Hellwig 					       SCTP_BINDX_REM_ADDR);
46121da177e4SLinus Torvalds 		break;
46131da177e4SLinus Torvalds 
461488a0a948SVlad Yasevich 	case SCTP_SOCKOPT_CONNECTX_OLD:
461588a0a948SVlad Yasevich 		/* 'optlen' is the size of the addresses buffer. */
4616ce5b2f89SChristoph Hellwig 		retval = sctp_setsockopt_connectx_old(sk, kopt, optlen);
461788a0a948SVlad Yasevich 		break;
461888a0a948SVlad Yasevich 
46193f7a87d2SFrank Filz 	case SCTP_SOCKOPT_CONNECTX:
46203f7a87d2SFrank Filz 		/* 'optlen' is the size of the addresses buffer. */
4621ce5b2f89SChristoph Hellwig 		retval = sctp_setsockopt_connectx(sk, kopt, optlen);
46223f7a87d2SFrank Filz 		break;
46233f7a87d2SFrank Filz 
46241da177e4SLinus Torvalds 	case SCTP_DISABLE_FRAGMENTS:
462510835825SChristoph Hellwig 		retval = sctp_setsockopt_disable_fragments(sk, kopt, optlen);
46261da177e4SLinus Torvalds 		break;
46271da177e4SLinus Torvalds 
46281da177e4SLinus Torvalds 	case SCTP_EVENTS:
4629a98d21a1SChristoph Hellwig 		retval = sctp_setsockopt_events(sk, kopt, optlen);
46301da177e4SLinus Torvalds 		break;
46311da177e4SLinus Torvalds 
46321da177e4SLinus Torvalds 	case SCTP_AUTOCLOSE:
46330b49a65cSChristoph Hellwig 		retval = sctp_setsockopt_autoclose(sk, kopt, optlen);
46341da177e4SLinus Torvalds 		break;
46351da177e4SLinus Torvalds 
46361da177e4SLinus Torvalds 	case SCTP_PEER_ADDR_PARAMS:
46379b7b0d1aSChristoph Hellwig 		retval = sctp_setsockopt_peer_addr_params(sk, kopt, optlen);
46381da177e4SLinus Torvalds 		break;
46391da177e4SLinus Torvalds 
46404580ccc0SShan Wei 	case SCTP_DELAYED_SACK:
4641ebb25defSChristoph Hellwig 		retval = sctp_setsockopt_delayed_ack(sk, kopt, optlen);
46427708610bSFrank Filz 		break;
4643d49d91d7SVlad Yasevich 	case SCTP_PARTIAL_DELIVERY_POINT:
4644bb13d647SChristoph Hellwig 		retval = sctp_setsockopt_partial_delivery_point(sk, kopt, optlen);
4645d49d91d7SVlad Yasevich 		break;
46467708610bSFrank Filz 
46471da177e4SLinus Torvalds 	case SCTP_INITMSG:
46489dfa6f04SChristoph Hellwig 		retval = sctp_setsockopt_initmsg(sk, kopt, optlen);
46491da177e4SLinus Torvalds 		break;
46501da177e4SLinus Torvalds 	case SCTP_DEFAULT_SEND_PARAM:
4651c23ad6d2SChristoph Hellwig 		retval = sctp_setsockopt_default_send_param(sk, kopt, optlen);
46521da177e4SLinus Torvalds 		break;
46536b3fd5f3SGeir Ola Vaagland 	case SCTP_DEFAULT_SNDINFO:
46548a2409d3SChristoph Hellwig 		retval = sctp_setsockopt_default_sndinfo(sk, kopt, optlen);
46556b3fd5f3SGeir Ola Vaagland 		break;
46561da177e4SLinus Torvalds 	case SCTP_PRIMARY_ADDR:
46571eec6958SChristoph Hellwig 		retval = sctp_setsockopt_primary_addr(sk, kopt, optlen);
46581da177e4SLinus Torvalds 		break;
46591da177e4SLinus Torvalds 	case SCTP_SET_PEER_PRIMARY_ADDR:
466046a0ae9dSChristoph Hellwig 		retval = sctp_setsockopt_peer_primary_addr(sk, kopt, optlen);
46611da177e4SLinus Torvalds 		break;
46621da177e4SLinus Torvalds 	case SCTP_NODELAY:
4663f87ddbc0SChristoph Hellwig 		retval = sctp_setsockopt_nodelay(sk, kopt, optlen);
46641da177e4SLinus Torvalds 		break;
46651da177e4SLinus Torvalds 	case SCTP_RTOINFO:
4666af5ae60eSChristoph Hellwig 		retval = sctp_setsockopt_rtoinfo(sk, kopt, optlen);
46671da177e4SLinus Torvalds 		break;
46681da177e4SLinus Torvalds 	case SCTP_ASSOCINFO:
46695b864c8dSChristoph Hellwig 		retval = sctp_setsockopt_associnfo(sk, kopt, optlen);
46701da177e4SLinus Torvalds 		break;
46711da177e4SLinus Torvalds 	case SCTP_I_WANT_MAPPED_V4_ADDR:
4672ffc08f08SChristoph Hellwig 		retval = sctp_setsockopt_mappedv4(sk, kopt, optlen);
46731da177e4SLinus Torvalds 		break;
46741da177e4SLinus Torvalds 	case SCTP_MAXSEG:
4675dcd03575SChristoph Hellwig 		retval = sctp_setsockopt_maxseg(sk, kopt, optlen);
46761da177e4SLinus Torvalds 		break;
46770f3fffd8SIvan Skytte Jorgensen 	case SCTP_ADAPTATION_LAYER:
467807e5035cSChristoph Hellwig 		retval = sctp_setsockopt_adaptation_layer(sk, kopt, optlen);
46791da177e4SLinus Torvalds 		break;
46806ab792f5SIvan Skytte Jorgensen 	case SCTP_CONTEXT:
4681722eca9eSChristoph Hellwig 		retval = sctp_setsockopt_context(sk, kopt, optlen);
46826ab792f5SIvan Skytte Jorgensen 		break;
4683b6e1331fSVlad Yasevich 	case SCTP_FRAGMENT_INTERLEAVE:
46841031cea0SChristoph Hellwig 		retval = sctp_setsockopt_fragment_interleave(sk, kopt, optlen);
4685b6e1331fSVlad Yasevich 		break;
468670331571SVlad Yasevich 	case SCTP_MAX_BURST:
4687f5bee0adSChristoph Hellwig 		retval = sctp_setsockopt_maxburst(sk, kopt, optlen);
468870331571SVlad Yasevich 		break;
468965b07e5dSVlad Yasevich 	case SCTP_AUTH_CHUNK:
469088266d31SChristoph Hellwig 		retval = sctp_setsockopt_auth_chunk(sk, kopt, optlen);
469165b07e5dSVlad Yasevich 		break;
469265b07e5dSVlad Yasevich 	case SCTP_HMAC_IDENT:
46933564ef44SChristoph Hellwig 		retval = sctp_setsockopt_hmac_ident(sk, kopt, optlen);
469465b07e5dSVlad Yasevich 		break;
469565b07e5dSVlad Yasevich 	case SCTP_AUTH_KEY:
4696534d13d0SChristoph Hellwig 		retval = sctp_setsockopt_auth_key(sk, kopt, optlen);
469765b07e5dSVlad Yasevich 		break;
469865b07e5dSVlad Yasevich 	case SCTP_AUTH_ACTIVE_KEY:
4699dcab0a7aSChristoph Hellwig 		retval = sctp_setsockopt_active_key(sk, kopt, optlen);
470065b07e5dSVlad Yasevich 		break;
470165b07e5dSVlad Yasevich 	case SCTP_AUTH_DELETE_KEY:
470297dc9f2eSChristoph Hellwig 		retval = sctp_setsockopt_del_key(sk, kopt, optlen);
470365b07e5dSVlad Yasevich 		break;
4704601590ecSXin Long 	case SCTP_AUTH_DEACTIVATE_KEY:
470576b3d0c4SChristoph Hellwig 		retval = sctp_setsockopt_deactivate_key(sk, kopt, optlen);
4706601590ecSXin Long 		break;
47077dc04d71SMichio Honda 	case SCTP_AUTO_ASCONF:
4708c9abc2c1SChristoph Hellwig 		retval = sctp_setsockopt_auto_asconf(sk, kopt, optlen);
47097dc04d71SMichio Honda 		break;
47105aa93bcfSNeil Horman 	case SCTP_PEER_ADDR_THLDS:
4711b0ac3bb8SChristoph Hellwig 		retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen,
4712d467ac0aSXin Long 							  false);
4713d467ac0aSXin Long 		break;
4714d467ac0aSXin Long 	case SCTP_PEER_ADDR_THLDS_V2:
4715b0ac3bb8SChristoph Hellwig 		retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen,
4716d467ac0aSXin Long 							  true);
47175aa93bcfSNeil Horman 		break;
47180d3a421dSGeir Ola Vaagland 	case SCTP_RECVRCVINFO:
4719a98af7c8SChristoph Hellwig 		retval = sctp_setsockopt_recvrcvinfo(sk, kopt, optlen);
47200d3a421dSGeir Ola Vaagland 		break;
47212347c80fSGeir Ola Vaagland 	case SCTP_RECVNXTINFO:
4722cfa6fde2SChristoph Hellwig 		retval = sctp_setsockopt_recvnxtinfo(sk, kopt, optlen);
47232347c80fSGeir Ola Vaagland 		break;
472428aa4c26SXin Long 	case SCTP_PR_SUPPORTED:
47254a97fa4fSChristoph Hellwig 		retval = sctp_setsockopt_pr_supported(sk, kopt, optlen);
472628aa4c26SXin Long 		break;
4727f959fb44SXin Long 	case SCTP_DEFAULT_PRINFO:
4728ac37435bSChristoph Hellwig 		retval = sctp_setsockopt_default_prinfo(sk, kopt, optlen);
4729f959fb44SXin Long 		break;
4730c0d8bab6SXin Long 	case SCTP_RECONFIG_SUPPORTED:
47313f49f720SChristoph Hellwig 		retval = sctp_setsockopt_reconfig_supported(sk, kopt, optlen);
4732c0d8bab6SXin Long 		break;
47339fb657aeSXin Long 	case SCTP_ENABLE_STREAM_RESET:
4734356dc6f1SChristoph Hellwig 		retval = sctp_setsockopt_enable_strreset(sk, kopt, optlen);
47359fb657aeSXin Long 		break;
47367f9d68acSXin Long 	case SCTP_RESET_STREAMS:
4737d4922434SChristoph Hellwig 		retval = sctp_setsockopt_reset_streams(sk, kopt, optlen);
47387f9d68acSXin Long 		break;
4739a92ce1a4SXin Long 	case SCTP_RESET_ASSOC:
4740b97d20ceSChristoph Hellwig 		retval = sctp_setsockopt_reset_assoc(sk, kopt, optlen);
4741a92ce1a4SXin Long 		break;
4742242bd2d5SXin Long 	case SCTP_ADD_STREAMS:
47434d6fb260SChristoph Hellwig 		retval = sctp_setsockopt_add_streams(sk, kopt, optlen);
4744242bd2d5SXin Long 		break;
474513aa8770SMarcelo Ricardo Leitner 	case SCTP_STREAM_SCHEDULER:
47464d2fba3aSChristoph Hellwig 		retval = sctp_setsockopt_scheduler(sk, kopt, optlen);
474713aa8770SMarcelo Ricardo Leitner 		break;
47480ccdf3c7SMarcelo Ricardo Leitner 	case SCTP_STREAM_SCHEDULER_VALUE:
4749d636e7f3SChristoph Hellwig 		retval = sctp_setsockopt_scheduler_value(sk, kopt, optlen);
47500ccdf3c7SMarcelo Ricardo Leitner 		break;
4751772a5869SXin Long 	case SCTP_INTERLEAVING_SUPPORTED:
47525b8d3b24SChristoph Hellwig 		retval = sctp_setsockopt_interleaving_supported(sk, kopt,
4753772a5869SXin Long 								optlen);
4754772a5869SXin Long 		break;
4755b0e9a2feSXin Long 	case SCTP_REUSE_PORT:
4756a4262466SChristoph Hellwig 		retval = sctp_setsockopt_reuse_port(sk, kopt, optlen);
4757b0e9a2feSXin Long 		break;
4758480ba9c1SXin Long 	case SCTP_EVENT:
4759565059cbSChristoph Hellwig 		retval = sctp_setsockopt_event(sk, kopt, optlen);
4760480ba9c1SXin Long 		break;
4761df2c71ffSXin Long 	case SCTP_ASCONF_SUPPORTED:
47629263ac97SChristoph Hellwig 		retval = sctp_setsockopt_asconf_supported(sk, kopt, optlen);
4763df2c71ffSXin Long 		break;
476456dd525aSXin Long 	case SCTP_AUTH_SUPPORTED:
4765963855a9SChristoph Hellwig 		retval = sctp_setsockopt_auth_supported(sk, kopt, optlen);
476656dd525aSXin Long 		break;
4767d5886b91SXin Long 	case SCTP_ECN_SUPPORTED:
476892c4f172SChristoph Hellwig 		retval = sctp_setsockopt_ecn_supported(sk, kopt, optlen);
4769d5886b91SXin Long 		break;
47708d2a6935SXin Long 	case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
477126feba80SChristoph Hellwig 		retval = sctp_setsockopt_pf_expose(sk, kopt, optlen);
47728d2a6935SXin Long 		break;
47738dba2960SXin Long 	case SCTP_REMOTE_UDP_ENCAPS_PORT:
47748dba2960SXin Long 		retval = sctp_setsockopt_encap_port(sk, kopt, optlen);
47758dba2960SXin Long 		break;
47763190b649SXin Long 	case SCTP_PLPMTUD_PROBE_INTERVAL:
47773190b649SXin Long 		retval = sctp_setsockopt_probe_interval(sk, kopt, optlen);
47783190b649SXin Long 		break;
47791da177e4SLinus Torvalds 	default:
47801da177e4SLinus Torvalds 		retval = -ENOPROTOOPT;
47811da177e4SLinus Torvalds 		break;
47823ff50b79SStephen Hemminger 	}
47831da177e4SLinus Torvalds 
4784048ed4b6Swangweidong 	release_sock(sk);
4785ca84bd05SChristoph Hellwig 	kfree(kopt);
47861da177e4SLinus Torvalds 	return retval;
47871da177e4SLinus Torvalds }
47881da177e4SLinus Torvalds 
47891da177e4SLinus Torvalds /* API 3.1.6 connect() - UDP Style Syntax
47901da177e4SLinus Torvalds  *
47911da177e4SLinus Torvalds  * An application may use the connect() call in the UDP model to initiate an
47921da177e4SLinus Torvalds  * association without sending data.
47931da177e4SLinus Torvalds  *
47941da177e4SLinus Torvalds  * The syntax is:
47951da177e4SLinus Torvalds  *
47961da177e4SLinus Torvalds  * ret = connect(int sd, const struct sockaddr *nam, socklen_t len);
47971da177e4SLinus Torvalds  *
47981da177e4SLinus Torvalds  * sd: the socket descriptor to have a new association added to.
47991da177e4SLinus Torvalds  *
48001da177e4SLinus Torvalds  * nam: the address structure (either struct sockaddr_in or struct
48011da177e4SLinus Torvalds  *    sockaddr_in6 defined in RFC2553 [7]).
48021da177e4SLinus Torvalds  *
48031da177e4SLinus Torvalds  * len: the size of the address.
48041da177e4SLinus Torvalds  */
sctp_connect(struct sock * sk,struct sockaddr * addr,int addr_len,int flags)4805dda91928SDaniel Borkmann static int sctp_connect(struct sock *sk, struct sockaddr *addr,
4806644fbdeaSXin Long 			int addr_len, int flags)
48071da177e4SLinus Torvalds {
48083f7a87d2SFrank Filz 	struct sctp_af *af;
48099b6c0887SXin Long 	int err = -EINVAL;
48101da177e4SLinus Torvalds 
4811048ed4b6Swangweidong 	lock_sock(sk);
4812bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk,
4813bb33381dSDaniel Borkmann 		 addr, addr_len);
48141da177e4SLinus Torvalds 
48153f7a87d2SFrank Filz 	/* Validate addr_len before calling common connect/connectx routine. */
48169b6c0887SXin Long 	af = sctp_get_af_specific(addr->sa_family);
48179b6c0887SXin Long 	if (af && addr_len >= af->sockaddr_len)
4818644fbdeaSXin Long 		err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL);
48191da177e4SLinus Torvalds 
4820048ed4b6Swangweidong 	release_sock(sk);
48211da177e4SLinus Torvalds 	return err;
48221da177e4SLinus Torvalds }
48231da177e4SLinus Torvalds 
sctp_inet_connect(struct socket * sock,struct sockaddr * uaddr,int addr_len,int flags)4824644fbdeaSXin Long int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr,
4825644fbdeaSXin Long 		      int addr_len, int flags)
4826644fbdeaSXin Long {
4827644fbdeaSXin Long 	if (addr_len < sizeof(uaddr->sa_family))
4828644fbdeaSXin Long 		return -EINVAL;
4829644fbdeaSXin Long 
4830644fbdeaSXin Long 	if (uaddr->sa_family == AF_UNSPEC)
4831644fbdeaSXin Long 		return -EOPNOTSUPP;
4832644fbdeaSXin Long 
4833644fbdeaSXin Long 	return sctp_connect(sock->sk, uaddr, addr_len, flags);
4834644fbdeaSXin Long }
4835644fbdeaSXin Long 
48361da177e4SLinus Torvalds /* FIXME: Write comments. */
sctp_disconnect(struct sock * sk,int flags)4837dda91928SDaniel Borkmann static int sctp_disconnect(struct sock *sk, int flags)
48381da177e4SLinus Torvalds {
48391da177e4SLinus Torvalds 	return -EOPNOTSUPP; /* STUB */
48401da177e4SLinus Torvalds }
48411da177e4SLinus Torvalds 
48421da177e4SLinus Torvalds /* 4.1.4 accept() - TCP Style Syntax
48431da177e4SLinus Torvalds  *
48441da177e4SLinus Torvalds  * Applications use accept() call to remove an established SCTP
48451da177e4SLinus Torvalds  * association from the accept queue of the endpoint.  A new socket
48461da177e4SLinus Torvalds  * descriptor will be returned from accept() to represent the newly
48471da177e4SLinus Torvalds  * formed association.
48481da177e4SLinus Torvalds  */
sctp_accept(struct sock * sk,int flags,int * err,bool kern)4849cdfbabfbSDavid Howells static struct sock *sctp_accept(struct sock *sk, int flags, int *err, bool kern)
48501da177e4SLinus Torvalds {
48511da177e4SLinus Torvalds 	struct sctp_sock *sp;
48521da177e4SLinus Torvalds 	struct sctp_endpoint *ep;
48531da177e4SLinus Torvalds 	struct sock *newsk = NULL;
48541da177e4SLinus Torvalds 	struct sctp_association *asoc;
48551da177e4SLinus Torvalds 	long timeo;
48561da177e4SLinus Torvalds 	int error = 0;
48571da177e4SLinus Torvalds 
4858048ed4b6Swangweidong 	lock_sock(sk);
48591da177e4SLinus Torvalds 
48601da177e4SLinus Torvalds 	sp = sctp_sk(sk);
48611da177e4SLinus Torvalds 	ep = sp->ep;
48621da177e4SLinus Torvalds 
48631da177e4SLinus Torvalds 	if (!sctp_style(sk, TCP)) {
48641da177e4SLinus Torvalds 		error = -EOPNOTSUPP;
48651da177e4SLinus Torvalds 		goto out;
48661da177e4SLinus Torvalds 	}
48671da177e4SLinus Torvalds 
48681da177e4SLinus Torvalds 	if (!sctp_sstate(sk, LISTENING)) {
48691da177e4SLinus Torvalds 		error = -EINVAL;
48701da177e4SLinus Torvalds 		goto out;
48711da177e4SLinus Torvalds 	}
48721da177e4SLinus Torvalds 
48738abfedd8SSridhar Samudrala 	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
48741da177e4SLinus Torvalds 
48751da177e4SLinus Torvalds 	error = sctp_wait_for_accept(sk, timeo);
48761da177e4SLinus Torvalds 	if (error)
48771da177e4SLinus Torvalds 		goto out;
48781da177e4SLinus Torvalds 
48791da177e4SLinus Torvalds 	/* We treat the list of associations on the endpoint as the accept
48801da177e4SLinus Torvalds 	 * queue and pick the first association on the list.
48811da177e4SLinus Torvalds 	 */
48821da177e4SLinus Torvalds 	asoc = list_entry(ep->asocs.next, struct sctp_association, asocs);
48831da177e4SLinus Torvalds 
4884cdfbabfbSDavid Howells 	newsk = sp->pf->create_accept_sk(sk, asoc, kern);
48851da177e4SLinus Torvalds 	if (!newsk) {
48861da177e4SLinus Torvalds 		error = -ENOMEM;
48871da177e4SLinus Torvalds 		goto out;
48881da177e4SLinus Torvalds 	}
48891da177e4SLinus Torvalds 
48901da177e4SLinus Torvalds 	/* Populate the fields of the newsk from the oldsk and migrate the
48911da177e4SLinus Torvalds 	 * asoc to the newsk.
48921da177e4SLinus Torvalds 	 */
489389664c62SXin Long 	error = sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP);
489489664c62SXin Long 	if (error) {
489589664c62SXin Long 		sk_common_release(newsk);
489689664c62SXin Long 		newsk = NULL;
489789664c62SXin Long 	}
48981da177e4SLinus Torvalds 
48991da177e4SLinus Torvalds out:
4900048ed4b6Swangweidong 	release_sock(sk);
49011da177e4SLinus Torvalds 	*err = error;
49021da177e4SLinus Torvalds 	return newsk;
49031da177e4SLinus Torvalds }
49041da177e4SLinus Torvalds 
49051da177e4SLinus Torvalds /* The SCTP ioctl handler. */
sctp_ioctl(struct sock * sk,int cmd,int * karg)4906e1d001faSBreno Leitao static int sctp_ioctl(struct sock *sk, int cmd, int *karg)
49071da177e4SLinus Torvalds {
490865040c33SDiego Elio 'Flameeyes' Pettenò 	int rc = -ENOTCONN;
490965040c33SDiego Elio 'Flameeyes' Pettenò 
4910048ed4b6Swangweidong 	lock_sock(sk);
491165040c33SDiego Elio 'Flameeyes' Pettenò 
491265040c33SDiego Elio 'Flameeyes' Pettenò 	/*
491365040c33SDiego Elio 'Flameeyes' Pettenò 	 * SEQPACKET-style sockets in LISTENING state are valid, for
491465040c33SDiego Elio 'Flameeyes' Pettenò 	 * SCTP, so only discard TCP-style sockets in LISTENING state.
491565040c33SDiego Elio 'Flameeyes' Pettenò 	 */
491665040c33SDiego Elio 'Flameeyes' Pettenò 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
491765040c33SDiego Elio 'Flameeyes' Pettenò 		goto out;
491865040c33SDiego Elio 'Flameeyes' Pettenò 
491965040c33SDiego Elio 'Flameeyes' Pettenò 	switch (cmd) {
492065040c33SDiego Elio 'Flameeyes' Pettenò 	case SIOCINQ: {
492165040c33SDiego Elio 'Flameeyes' Pettenò 		struct sk_buff *skb;
4922e1d001faSBreno Leitao 		*karg = 0;
492365040c33SDiego Elio 'Flameeyes' Pettenò 
492465040c33SDiego Elio 'Flameeyes' Pettenò 		skb = skb_peek(&sk->sk_receive_queue);
492565040c33SDiego Elio 'Flameeyes' Pettenò 		if (skb != NULL) {
492665040c33SDiego Elio 'Flameeyes' Pettenò 			/*
492765040c33SDiego Elio 'Flameeyes' Pettenò 			 * We will only return the amount of this packet since
492865040c33SDiego Elio 'Flameeyes' Pettenò 			 * that is all that will be read.
492965040c33SDiego Elio 'Flameeyes' Pettenò 			 */
4930e1d001faSBreno Leitao 			*karg = skb->len;
493165040c33SDiego Elio 'Flameeyes' Pettenò 		}
4932e1d001faSBreno Leitao 		rc = 0;
493365040c33SDiego Elio 'Flameeyes' Pettenò 		break;
49349a7241c2SDavid S. Miller 	}
493565040c33SDiego Elio 'Flameeyes' Pettenò 	default:
493665040c33SDiego Elio 'Flameeyes' Pettenò 		rc = -ENOIOCTLCMD;
493765040c33SDiego Elio 'Flameeyes' Pettenò 		break;
493865040c33SDiego Elio 'Flameeyes' Pettenò 	}
493965040c33SDiego Elio 'Flameeyes' Pettenò out:
4940048ed4b6Swangweidong 	release_sock(sk);
494165040c33SDiego Elio 'Flameeyes' Pettenò 	return rc;
49421da177e4SLinus Torvalds }
49431da177e4SLinus Torvalds 
49441da177e4SLinus Torvalds /* This is the function which gets called during socket creation to
49451da177e4SLinus Torvalds  * initialized the SCTP-specific portion of the sock.
49461da177e4SLinus Torvalds  * The sock structure should already be zero-filled memory.
49471da177e4SLinus Torvalds  */
sctp_init_sock(struct sock * sk)4948dda91928SDaniel Borkmann static int sctp_init_sock(struct sock *sk)
49491da177e4SLinus Torvalds {
4950e1fc3b14SEric W. Biederman 	struct net *net = sock_net(sk);
49511da177e4SLinus Torvalds 	struct sctp_sock *sp;
49521da177e4SLinus Torvalds 
4953bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p\n", __func__, sk);
49541da177e4SLinus Torvalds 
49551da177e4SLinus Torvalds 	sp = sctp_sk(sk);
49561da177e4SLinus Torvalds 
49571da177e4SLinus Torvalds 	/* Initialize the SCTP per socket area.  */
49581da177e4SLinus Torvalds 	switch (sk->sk_type) {
49591da177e4SLinus Torvalds 	case SOCK_SEQPACKET:
49601da177e4SLinus Torvalds 		sp->type = SCTP_SOCKET_UDP;
49611da177e4SLinus Torvalds 		break;
49621da177e4SLinus Torvalds 	case SOCK_STREAM:
49631da177e4SLinus Torvalds 		sp->type = SCTP_SOCKET_TCP;
49641da177e4SLinus Torvalds 		break;
49651da177e4SLinus Torvalds 	default:
49661da177e4SLinus Torvalds 		return -ESOCKTNOSUPPORT;
49671da177e4SLinus Torvalds 	}
49681da177e4SLinus Torvalds 
496990017accSMarcelo Ricardo Leitner 	sk->sk_gso_type = SKB_GSO_SCTP;
497090017accSMarcelo Ricardo Leitner 
49711da177e4SLinus Torvalds 	/* Initialize default send parameters. These parameters can be
49721da177e4SLinus Torvalds 	 * modified with the SCTP_DEFAULT_SEND_PARAM socket option.
49731da177e4SLinus Torvalds 	 */
49741da177e4SLinus Torvalds 	sp->default_stream = 0;
49751da177e4SLinus Torvalds 	sp->default_ppid = 0;
49761da177e4SLinus Torvalds 	sp->default_flags = 0;
49771da177e4SLinus Torvalds 	sp->default_context = 0;
49781da177e4SLinus Torvalds 	sp->default_timetolive = 0;
49791da177e4SLinus Torvalds 
49806ab792f5SIvan Skytte Jorgensen 	sp->default_rcv_context = 0;
4981e1fc3b14SEric W. Biederman 	sp->max_burst = net->sctp.max_burst;
49826ab792f5SIvan Skytte Jorgensen 
49833c68198eSNeil Horman 	sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg;
49843c68198eSNeil Horman 
49851da177e4SLinus Torvalds 	/* Initialize default setup parameters. These parameters
49861da177e4SLinus Torvalds 	 * can be modified with the SCTP_INITMSG socket option or
49871da177e4SLinus Torvalds 	 * overridden by the SCTP_INIT CMSG.
49881da177e4SLinus Torvalds 	 */
49891da177e4SLinus Torvalds 	sp->initmsg.sinit_num_ostreams   = sctp_max_outstreams;
49901da177e4SLinus Torvalds 	sp->initmsg.sinit_max_instreams  = sctp_max_instreams;
4991e1fc3b14SEric W. Biederman 	sp->initmsg.sinit_max_attempts   = net->sctp.max_retrans_init;
4992e1fc3b14SEric W. Biederman 	sp->initmsg.sinit_max_init_timeo = net->sctp.rto_max;
49931da177e4SLinus Torvalds 
49941da177e4SLinus Torvalds 	/* Initialize default RTO related parameters.  These parameters can
49951da177e4SLinus Torvalds 	 * be modified for with the SCTP_RTOINFO socket option.
49961da177e4SLinus Torvalds 	 */
4997e1fc3b14SEric W. Biederman 	sp->rtoinfo.srto_initial = net->sctp.rto_initial;
4998e1fc3b14SEric W. Biederman 	sp->rtoinfo.srto_max     = net->sctp.rto_max;
4999e1fc3b14SEric W. Biederman 	sp->rtoinfo.srto_min     = net->sctp.rto_min;
50001da177e4SLinus Torvalds 
50011da177e4SLinus Torvalds 	/* Initialize default association related parameters. These parameters
50021da177e4SLinus Torvalds 	 * can be modified with the SCTP_ASSOCINFO socket option.
50031da177e4SLinus Torvalds 	 */
5004e1fc3b14SEric W. Biederman 	sp->assocparams.sasoc_asocmaxrxt = net->sctp.max_retrans_association;
50051da177e4SLinus Torvalds 	sp->assocparams.sasoc_number_peer_destinations = 0;
50061da177e4SLinus Torvalds 	sp->assocparams.sasoc_peer_rwnd = 0;
50071da177e4SLinus Torvalds 	sp->assocparams.sasoc_local_rwnd = 0;
5008e1fc3b14SEric W. Biederman 	sp->assocparams.sasoc_cookie_life = net->sctp.valid_cookie_life;
50091da177e4SLinus Torvalds 
50101da177e4SLinus Torvalds 	/* Initialize default event subscriptions. By default, all the
50111da177e4SLinus Torvalds 	 * options are off.
50121da177e4SLinus Torvalds 	 */
50132cc0eeb6SXin Long 	sp->subscribe = 0;
50141da177e4SLinus Torvalds 
50151da177e4SLinus Torvalds 	/* Default Peer Address Parameters.  These defaults can
50161da177e4SLinus Torvalds 	 * be modified via SCTP_PEER_ADDR_PARAMS
50171da177e4SLinus Torvalds 	 */
5018e1fc3b14SEric W. Biederman 	sp->hbinterval  = net->sctp.hb_interval;
5019f1bfe8b5SXin Long 	sp->udp_port    = htons(net->sctp.udp_port);
5020e8a3001cSXin Long 	sp->encap_port  = htons(net->sctp.encap_port);
5021e1fc3b14SEric W. Biederman 	sp->pathmaxrxt  = net->sctp.max_retrans_path;
50228add543eSXin Long 	sp->pf_retrans  = net->sctp.pf_retrans;
502334515e94SXin Long 	sp->ps_retrans  = net->sctp.ps_retrans;
5024aef587beSXin Long 	sp->pf_expose   = net->sctp.pf_expose;
50254e2d52bfSwangweidong 	sp->pathmtu     = 0; /* allow default discovery */
5026e1fc3b14SEric W. Biederman 	sp->sackdelay   = net->sctp.sack_timeout;
50277bfe8bdbSVlad Yasevich 	sp->sackfreq	= 2;
502852ccb8e9SFrank Filz 	sp->param_flags = SPP_HB_ENABLE |
502952ccb8e9SFrank Filz 			  SPP_PMTUD_ENABLE |
503052ccb8e9SFrank Filz 			  SPP_SACKDELAY_ENABLE;
50317efba10dSXin Long 	sp->default_ss = SCTP_SS_DEFAULT;
50321da177e4SLinus Torvalds 
50331da177e4SLinus Torvalds 	/* If enabled no SCTP message fragmentation will be performed.
50341da177e4SLinus Torvalds 	 * Configure through SCTP_DISABLE_FRAGMENTS socket option.
50351da177e4SLinus Torvalds 	 */
50361da177e4SLinus Torvalds 	sp->disable_fragments = 0;
50371da177e4SLinus Torvalds 
5038208edef6SSridhar Samudrala 	/* Enable Nagle algorithm by default.  */
5039208edef6SSridhar Samudrala 	sp->nodelay           = 0;
50401da177e4SLinus Torvalds 
50410d3a421dSGeir Ola Vaagland 	sp->recvrcvinfo = 0;
50422347c80fSGeir Ola Vaagland 	sp->recvnxtinfo = 0;
50430d3a421dSGeir Ola Vaagland 
50441da177e4SLinus Torvalds 	/* Enable by default. */
50451da177e4SLinus Torvalds 	sp->v4mapped          = 1;
50461da177e4SLinus Torvalds 
50471da177e4SLinus Torvalds 	/* Auto-close idle associations after the configured
50481da177e4SLinus Torvalds 	 * number of seconds.  A value of 0 disables this
50491da177e4SLinus Torvalds 	 * feature.  Configure through the SCTP_AUTOCLOSE socket option,
50501da177e4SLinus Torvalds 	 * for UDP-style sockets only.
50511da177e4SLinus Torvalds 	 */
50521da177e4SLinus Torvalds 	sp->autoclose         = 0;
50531da177e4SLinus Torvalds 
50541da177e4SLinus Torvalds 	/* User specified fragmentation limit. */
50551da177e4SLinus Torvalds 	sp->user_frag         = 0;
50561da177e4SLinus Torvalds 
50570f3fffd8SIvan Skytte Jorgensen 	sp->adaptation_ind = 0;
50581da177e4SLinus Torvalds 
50591da177e4SLinus Torvalds 	sp->pf = sctp_get_pf_specific(sk->sk_family);
50601da177e4SLinus Torvalds 
50611da177e4SLinus Torvalds 	/* Control variables for partial data delivery. */
5062b6e1331fSVlad Yasevich 	atomic_set(&sp->pd_mode, 0);
50631da177e4SLinus Torvalds 	skb_queue_head_init(&sp->pd_lobby);
5064b6e1331fSVlad Yasevich 	sp->frag_interleave = 0;
5065d1e462a7SXin Long 	sp->probe_interval = net->sctp.probe_interval;
50661da177e4SLinus Torvalds 
50671da177e4SLinus Torvalds 	/* Create a per socket endpoint structure.  Even if we
50681da177e4SLinus Torvalds 	 * change the data structure relationships, this may still
50691da177e4SLinus Torvalds 	 * be useful for storing pre-connect address information.
50701da177e4SLinus Torvalds 	 */
5071c164b838SDaniel Borkmann 	sp->ep = sctp_endpoint_new(sk, GFP_KERNEL);
5072c164b838SDaniel Borkmann 	if (!sp->ep)
50731da177e4SLinus Torvalds 		return -ENOMEM;
50741da177e4SLinus Torvalds 
50751da177e4SLinus Torvalds 	sp->hmac = NULL;
50761da177e4SLinus Torvalds 
50770a2fbac1SDaniel Borkmann 	sk->sk_destruct = sctp_destruct_sock;
50780a2fbac1SDaniel Borkmann 
50791da177e4SLinus Torvalds 	SCTP_DBG_OBJCNT_INC(sock);
50806f756a8cSDavid S. Miller 
50818cb38a60STonghao Zhang 	sk_sockets_allocated_inc(sk);
5082e1fc3b14SEric W. Biederman 	sock_prot_inuse_add(net, sk->sk_prot, 1);
50832d45a02dSMarcelo Ricardo Leitner 
50841da177e4SLinus Torvalds 	return 0;
50851da177e4SLinus Torvalds }
50861da177e4SLinus Torvalds 
50872d45a02dSMarcelo Ricardo Leitner /* Cleanup any SCTP per socket resources. Must be called with
50882d45a02dSMarcelo Ricardo Leitner  * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true
50892d45a02dSMarcelo Ricardo Leitner  */
sctp_destroy_sock(struct sock * sk)5090dda91928SDaniel Borkmann static void sctp_destroy_sock(struct sock *sk)
50911da177e4SLinus Torvalds {
50929f7d653bSMichio Honda 	struct sctp_sock *sp;
50931da177e4SLinus Torvalds 
5094bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p\n", __func__, sk);
50951da177e4SLinus Torvalds 
50961da177e4SLinus Torvalds 	/* Release our hold on the endpoint. */
50979f7d653bSMichio Honda 	sp = sctp_sk(sk);
50981abd165eSDaniel Borkmann 	/* This could happen during socket init, thus we bail out
50991abd165eSDaniel Borkmann 	 * early, since the rest of the below is not setup either.
51001abd165eSDaniel Borkmann 	 */
51011abd165eSDaniel Borkmann 	if (sp->ep == NULL)
51021abd165eSDaniel Borkmann 		return;
51031abd165eSDaniel Borkmann 
51049f7d653bSMichio Honda 	if (sp->do_auto_asconf) {
51059f7d653bSMichio Honda 		sp->do_auto_asconf = 0;
51069f7d653bSMichio Honda 		list_del(&sp->auto_asconf_list);
51079f7d653bSMichio Honda 	}
51089f7d653bSMichio Honda 	sctp_endpoint_free(sp->ep);
51098cb38a60STonghao Zhang 	sk_sockets_allocated_dec(sk);
51109a57f7faSEric Dumazet 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
51111da177e4SLinus Torvalds }
51121da177e4SLinus Torvalds 
51130a2fbac1SDaniel Borkmann /* Triggered when there are no references on the socket anymore */
sctp_destruct_common(struct sock * sk)51146431b0f6SKuniyuki Iwashima static void sctp_destruct_common(struct sock *sk)
51150a2fbac1SDaniel Borkmann {
51160a2fbac1SDaniel Borkmann 	struct sctp_sock *sp = sctp_sk(sk);
51170a2fbac1SDaniel Borkmann 
51180a2fbac1SDaniel Borkmann 	/* Free up the HMAC transform. */
51195821c769SHerbert Xu 	crypto_free_shash(sp->hmac);
51206431b0f6SKuniyuki Iwashima }
51210a2fbac1SDaniel Borkmann 
sctp_destruct_sock(struct sock * sk)51226431b0f6SKuniyuki Iwashima static void sctp_destruct_sock(struct sock *sk)
51236431b0f6SKuniyuki Iwashima {
51246431b0f6SKuniyuki Iwashima 	sctp_destruct_common(sk);
51250a2fbac1SDaniel Borkmann 	inet_sock_destruct(sk);
51260a2fbac1SDaniel Borkmann }
51270a2fbac1SDaniel Borkmann 
51281da177e4SLinus Torvalds /* API 4.1.7 shutdown() - TCP Style Syntax
51291da177e4SLinus Torvalds  *     int shutdown(int socket, int how);
51301da177e4SLinus Torvalds  *
51311da177e4SLinus Torvalds  *     sd      - the socket descriptor of the association to be closed.
51321da177e4SLinus Torvalds  *     how     - Specifies the type of shutdown.  The  values  are
51331da177e4SLinus Torvalds  *               as follows:
51341da177e4SLinus Torvalds  *               SHUT_RD
51351da177e4SLinus Torvalds  *                     Disables further receive operations. No SCTP
51361da177e4SLinus Torvalds  *                     protocol action is taken.
51371da177e4SLinus Torvalds  *               SHUT_WR
51381da177e4SLinus Torvalds  *                     Disables further send operations, and initiates
51391da177e4SLinus Torvalds  *                     the SCTP shutdown sequence.
51401da177e4SLinus Torvalds  *               SHUT_RDWR
51411da177e4SLinus Torvalds  *                     Disables further send  and  receive  operations
51421da177e4SLinus Torvalds  *                     and initiates the SCTP shutdown sequence.
51431da177e4SLinus Torvalds  */
sctp_shutdown(struct sock * sk,int how)5144dda91928SDaniel Borkmann static void sctp_shutdown(struct sock *sk, int how)
51451da177e4SLinus Torvalds {
514655e26eb9SEric W. Biederman 	struct net *net = sock_net(sk);
51471da177e4SLinus Torvalds 	struct sctp_endpoint *ep;
51481da177e4SLinus Torvalds 
51491da177e4SLinus Torvalds 	if (!sctp_style(sk, TCP))
51501da177e4SLinus Torvalds 		return;
51511da177e4SLinus Torvalds 
51521da177e4SLinus Torvalds 	ep = sctp_sk(sk)->ep;
51535bf35ddfSXin Long 	if (how & SEND_SHUTDOWN && !list_empty(&ep->asocs)) {
51545bf35ddfSXin Long 		struct sctp_association *asoc;
51555bf35ddfSXin Long 
5156cbabf463SYafang Shao 		inet_sk_set_state(sk, SCTP_SS_CLOSING);
51571da177e4SLinus Torvalds 		asoc = list_entry(ep->asocs.next,
51581da177e4SLinus Torvalds 				  struct sctp_association, asocs);
515955e26eb9SEric W. Biederman 		sctp_primitive_SHUTDOWN(net, asoc, NULL);
51601da177e4SLinus Torvalds 	}
51611da177e4SLinus Torvalds }
51621da177e4SLinus Torvalds 
sctp_get_sctp_info(struct sock * sk,struct sctp_association * asoc,struct sctp_info * info)516352c52a61SXin Long int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
516452c52a61SXin Long 		       struct sctp_info *info)
516552c52a61SXin Long {
516652c52a61SXin Long 	struct sctp_transport *prim;
516752c52a61SXin Long 	struct list_head *pos;
516852c52a61SXin Long 	int mask;
516952c52a61SXin Long 
517052c52a61SXin Long 	memset(info, 0, sizeof(*info));
517152c52a61SXin Long 	if (!asoc) {
517252c52a61SXin Long 		struct sctp_sock *sp = sctp_sk(sk);
517352c52a61SXin Long 
517452c52a61SXin Long 		info->sctpi_s_autoclose = sp->autoclose;
517552c52a61SXin Long 		info->sctpi_s_adaptation_ind = sp->adaptation_ind;
517652c52a61SXin Long 		info->sctpi_s_pd_point = sp->pd_point;
517752c52a61SXin Long 		info->sctpi_s_nodelay = sp->nodelay;
517852c52a61SXin Long 		info->sctpi_s_disable_fragments = sp->disable_fragments;
517952c52a61SXin Long 		info->sctpi_s_v4mapped = sp->v4mapped;
518052c52a61SXin Long 		info->sctpi_s_frag_interleave = sp->frag_interleave;
518140eb90e9SXin Long 		info->sctpi_s_type = sp->type;
518252c52a61SXin Long 
518352c52a61SXin Long 		return 0;
518452c52a61SXin Long 	}
518552c52a61SXin Long 
518652c52a61SXin Long 	info->sctpi_tag = asoc->c.my_vtag;
518752c52a61SXin Long 	info->sctpi_state = asoc->state;
518852c52a61SXin Long 	info->sctpi_rwnd = asoc->a_rwnd;
518952c52a61SXin Long 	info->sctpi_unackdata = asoc->unack_data;
519052c52a61SXin Long 	info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
5191cee360abSXin Long 	info->sctpi_instrms = asoc->stream.incnt;
5192cee360abSXin Long 	info->sctpi_outstrms = asoc->stream.outcnt;
519352c52a61SXin Long 	list_for_each(pos, &asoc->base.inqueue.in_chunk_list)
519452c52a61SXin Long 		info->sctpi_inqueue++;
519552c52a61SXin Long 	list_for_each(pos, &asoc->outqueue.out_chunk_list)
519652c52a61SXin Long 		info->sctpi_outqueue++;
519752c52a61SXin Long 	info->sctpi_overall_error = asoc->overall_error_count;
519852c52a61SXin Long 	info->sctpi_max_burst = asoc->max_burst;
519952c52a61SXin Long 	info->sctpi_maxseg = asoc->frag_point;
520052c52a61SXin Long 	info->sctpi_peer_rwnd = asoc->peer.rwnd;
520152c52a61SXin Long 	info->sctpi_peer_tag = asoc->c.peer_vtag;
520252c52a61SXin Long 
5203ab4f1e28SXin Long 	mask = asoc->peer.intl_capable << 1;
5204ab4f1e28SXin Long 	mask = (mask | asoc->peer.ecn_capable) << 1;
520552c52a61SXin Long 	mask = (mask | asoc->peer.ipv4_address) << 1;
520652c52a61SXin Long 	mask = (mask | asoc->peer.ipv6_address) << 1;
5207ab4f1e28SXin Long 	mask = (mask | asoc->peer.reconf_capable) << 1;
520852c52a61SXin Long 	mask = (mask | asoc->peer.asconf_capable) << 1;
520952c52a61SXin Long 	mask = (mask | asoc->peer.prsctp_capable) << 1;
521052c52a61SXin Long 	mask = (mask | asoc->peer.auth_capable);
521152c52a61SXin Long 	info->sctpi_peer_capable = mask;
521252c52a61SXin Long 	mask = asoc->peer.sack_needed << 1;
521352c52a61SXin Long 	mask = (mask | asoc->peer.sack_generation) << 1;
521452c52a61SXin Long 	mask = (mask | asoc->peer.zero_window_announced);
521552c52a61SXin Long 	info->sctpi_peer_sack = mask;
521652c52a61SXin Long 
521752c52a61SXin Long 	info->sctpi_isacks = asoc->stats.isacks;
521852c52a61SXin Long 	info->sctpi_osacks = asoc->stats.osacks;
521952c52a61SXin Long 	info->sctpi_opackets = asoc->stats.opackets;
522052c52a61SXin Long 	info->sctpi_ipackets = asoc->stats.ipackets;
522152c52a61SXin Long 	info->sctpi_rtxchunks = asoc->stats.rtxchunks;
522252c52a61SXin Long 	info->sctpi_outofseqtsns = asoc->stats.outofseqtsns;
522352c52a61SXin Long 	info->sctpi_idupchunks = asoc->stats.idupchunks;
522452c52a61SXin Long 	info->sctpi_gapcnt = asoc->stats.gapcnt;
522552c52a61SXin Long 	info->sctpi_ouodchunks = asoc->stats.ouodchunks;
522652c52a61SXin Long 	info->sctpi_iuodchunks = asoc->stats.iuodchunks;
522752c52a61SXin Long 	info->sctpi_oodchunks = asoc->stats.oodchunks;
522852c52a61SXin Long 	info->sctpi_iodchunks = asoc->stats.iodchunks;
522952c52a61SXin Long 	info->sctpi_octrlchunks = asoc->stats.octrlchunks;
523052c52a61SXin Long 	info->sctpi_ictrlchunks = asoc->stats.ictrlchunks;
523152c52a61SXin Long 
523252c52a61SXin Long 	prim = asoc->peer.primary_path;
5233ee6c88bbSStefano Brivio 	memcpy(&info->sctpi_p_address, &prim->ipaddr, sizeof(prim->ipaddr));
523452c52a61SXin Long 	info->sctpi_p_state = prim->state;
523552c52a61SXin Long 	info->sctpi_p_cwnd = prim->cwnd;
523652c52a61SXin Long 	info->sctpi_p_srtt = prim->srtt;
523752c52a61SXin Long 	info->sctpi_p_rto = jiffies_to_msecs(prim->rto);
523852c52a61SXin Long 	info->sctpi_p_hbinterval = prim->hbinterval;
523952c52a61SXin Long 	info->sctpi_p_pathmaxrxt = prim->pathmaxrxt;
524052c52a61SXin Long 	info->sctpi_p_sackdelay = jiffies_to_msecs(prim->sackdelay);
524152c52a61SXin Long 	info->sctpi_p_ssthresh = prim->ssthresh;
524252c52a61SXin Long 	info->sctpi_p_partial_bytes_acked = prim->partial_bytes_acked;
524352c52a61SXin Long 	info->sctpi_p_flight_size = prim->flight_size;
524452c52a61SXin Long 	info->sctpi_p_error = prim->error_count;
524552c52a61SXin Long 
524652c52a61SXin Long 	return 0;
524752c52a61SXin Long }
524852c52a61SXin Long EXPORT_SYMBOL_GPL(sctp_get_sctp_info);
524952c52a61SXin Long 
5250626d16f5SXin Long /* use callback to avoid exporting the core structure */
sctp_transport_walk_start(struct rhashtable_iter * iter)52516c72b774SJules Irenge void sctp_transport_walk_start(struct rhashtable_iter *iter) __acquires(RCU)
5252626d16f5SXin Long {
52537fda702fSXin Long 	rhltable_walk_enter(&sctp_transport_hashtable, iter);
5254626d16f5SXin Long 
525597a6ec4aSTom Herbert 	rhashtable_walk_start(iter);
5256626d16f5SXin Long }
5257626d16f5SXin Long 
sctp_transport_walk_stop(struct rhashtable_iter * iter)5258b77b4f63SJules Irenge void sctp_transport_walk_stop(struct rhashtable_iter *iter) __releases(RCU)
5259626d16f5SXin Long {
5260626d16f5SXin Long 	rhashtable_walk_stop(iter);
5261626d16f5SXin Long 	rhashtable_walk_exit(iter);
5262626d16f5SXin Long }
5263626d16f5SXin Long 
sctp_transport_get_next(struct net * net,struct rhashtable_iter * iter)5264626d16f5SXin Long struct sctp_transport *sctp_transport_get_next(struct net *net,
5265626d16f5SXin Long 					       struct rhashtable_iter *iter)
5266626d16f5SXin Long {
5267626d16f5SXin Long 	struct sctp_transport *t;
5268626d16f5SXin Long 
5269626d16f5SXin Long 	t = rhashtable_walk_next(iter);
5270626d16f5SXin Long 	for (; t; t = rhashtable_walk_next(iter)) {
5271626d16f5SXin Long 		if (IS_ERR(t)) {
5272626d16f5SXin Long 			if (PTR_ERR(t) == -EAGAIN)
5273626d16f5SXin Long 				continue;
5274626d16f5SXin Long 			break;
5275626d16f5SXin Long 		}
5276626d16f5SXin Long 
5277bab1be79SXin Long 		if (!sctp_transport_hold(t))
5278bab1be79SXin Long 			continue;
5279bab1be79SXin Long 
52804e7696d9SXin Long 		if (net_eq(t->asoc->base.net, net) &&
5281626d16f5SXin Long 		    t->asoc->peer.primary_path == t)
5282626d16f5SXin Long 			break;
5283bab1be79SXin Long 
5284bab1be79SXin Long 		sctp_transport_put(t);
5285626d16f5SXin Long 	}
5286626d16f5SXin Long 
5287626d16f5SXin Long 	return t;
5288626d16f5SXin Long }
5289626d16f5SXin Long 
sctp_transport_get_idx(struct net * net,struct rhashtable_iter * iter,int pos)5290626d16f5SXin Long struct sctp_transport *sctp_transport_get_idx(struct net *net,
5291626d16f5SXin Long 					      struct rhashtable_iter *iter,
5292626d16f5SXin Long 					      int pos)
5293626d16f5SXin Long {
5294bab1be79SXin Long 	struct sctp_transport *t;
5295626d16f5SXin Long 
5296bab1be79SXin Long 	if (!pos)
5297bab1be79SXin Long 		return SEQ_START_TOKEN;
5298626d16f5SXin Long 
5299bab1be79SXin Long 	while ((t = sctp_transport_get_next(net, iter)) && !IS_ERR(t)) {
5300bab1be79SXin Long 		if (!--pos)
5301bab1be79SXin Long 			break;
5302bab1be79SXin Long 		sctp_transport_put(t);
5303bab1be79SXin Long 	}
5304bab1be79SXin Long 
5305bab1be79SXin Long 	return t;
5306626d16f5SXin Long }
5307626d16f5SXin Long 
sctp_for_each_endpoint(int (* cb)(struct sctp_endpoint *,void *),void * p)5308626d16f5SXin Long int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *),
5309626d16f5SXin Long 			   void *p) {
5310626d16f5SXin Long 	int err = 0;
5311626d16f5SXin Long 	int hash = 0;
53123d3b2f57SXin Long 	struct sctp_endpoint *ep;
5313626d16f5SXin Long 	struct sctp_hashbucket *head;
5314626d16f5SXin Long 
5315626d16f5SXin Long 	for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize;
5316626d16f5SXin Long 	     hash++, head++) {
5317581409daSXin Long 		read_lock_bh(&head->lock);
53183d3b2f57SXin Long 		sctp_for_each_hentry(ep, &head->chain) {
53193d3b2f57SXin Long 			err = cb(ep, p);
5320626d16f5SXin Long 			if (err)
5321626d16f5SXin Long 				break;
5322626d16f5SXin Long 		}
5323581409daSXin Long 		read_unlock_bh(&head->lock);
5324626d16f5SXin Long 	}
5325626d16f5SXin Long 
5326626d16f5SXin Long 	return err;
5327626d16f5SXin Long }
5328626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_for_each_endpoint);
5329626d16f5SXin Long 
sctp_transport_lookup_process(sctp_callback_t cb,struct net * net,const union sctp_addr * laddr,const union sctp_addr * paddr,void * p,int dif)5330f9d31c4cSXin Long int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net,
5331626d16f5SXin Long 				  const union sctp_addr *laddr,
53320af03170SXin Long 				  const union sctp_addr *paddr, void *p, int dif)
5333626d16f5SXin Long {
5334626d16f5SXin Long 	struct sctp_transport *transport;
5335f9d31c4cSXin Long 	struct sctp_endpoint *ep;
5336f9d31c4cSXin Long 	int err = -ENOENT;
5337626d16f5SXin Long 
5338626d16f5SXin Long 	rcu_read_lock();
53390af03170SXin Long 	transport = sctp_addrs_lookup_transport(net, laddr, paddr, dif, dif);
5340f9d31c4cSXin Long 	if (!transport) {
5341626d16f5SXin Long 		rcu_read_unlock();
5342f9d31c4cSXin Long 		return err;
5343f9d31c4cSXin Long 	}
5344f9d31c4cSXin Long 	ep = transport->asoc->ep;
5345f9d31c4cSXin Long 	if (!sctp_endpoint_hold(ep)) { /* asoc can be peeled off */
5346cd26da4fSXin Long 		sctp_transport_put(transport);
5347f9d31c4cSXin Long 		rcu_read_unlock();
5348f9d31c4cSXin Long 		return err;
5349f9d31c4cSXin Long 	}
5350f9d31c4cSXin Long 	rcu_read_unlock();
53511cceda78SXin Long 
5352f9d31c4cSXin Long 	err = cb(ep, transport, p);
5353f9d31c4cSXin Long 	sctp_endpoint_put(ep);
5354f9d31c4cSXin Long 	sctp_transport_put(transport);
5355626d16f5SXin Long 	return err;
5356626d16f5SXin Long }
5357626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_transport_lookup_process);
5358626d16f5SXin Long 
sctp_transport_traverse_process(sctp_callback_t cb,sctp_callback_t cb_done,struct net * net,int * pos,void * p)53595ec7d18dSXin Long int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done,
53605ec7d18dSXin Long 				    struct net *net, int *pos, void *p)
53615ec7d18dSXin Long {
5362626d16f5SXin Long 	struct rhashtable_iter hti;
5363d25adbebSXin Long 	struct sctp_transport *tsp;
53645ec7d18dSXin Long 	struct sctp_endpoint *ep;
5365d25adbebSXin Long 	int ret;
5366626d16f5SXin Long 
5367d25adbebSXin Long again:
5368f53d77e1SXin Long 	ret = 0;
536997a6ec4aSTom Herbert 	sctp_transport_walk_start(&hti);
5370626d16f5SXin Long 
5371d25adbebSXin Long 	tsp = sctp_transport_get_idx(net, &hti, *pos + 1);
5372d25adbebSXin Long 	for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) {
53735ec7d18dSXin Long 		ep = tsp->asoc->ep;
53745ec7d18dSXin Long 		if (sctp_endpoint_hold(ep)) { /* asoc can be peeled off */
53755ec7d18dSXin Long 			ret = cb(ep, tsp, p);
5376d25adbebSXin Long 			if (ret)
5377626d16f5SXin Long 				break;
53785ec7d18dSXin Long 			sctp_endpoint_put(ep);
53795ec7d18dSXin Long 		}
5380d25adbebSXin Long 		(*pos)++;
5381d25adbebSXin Long 		sctp_transport_put(tsp);
5382626d16f5SXin Long 	}
5383626d16f5SXin Long 	sctp_transport_walk_stop(&hti);
538453fa1036SXin Long 
5385d25adbebSXin Long 	if (ret) {
53865ec7d18dSXin Long 		if (cb_done && !cb_done(ep, tsp, p)) {
5387d25adbebSXin Long 			(*pos)++;
53885ec7d18dSXin Long 			sctp_endpoint_put(ep);
5389d25adbebSXin Long 			sctp_transport_put(tsp);
5390d25adbebSXin Long 			goto again;
5391d25adbebSXin Long 		}
53925ec7d18dSXin Long 		sctp_endpoint_put(ep);
5393d25adbebSXin Long 		sctp_transport_put(tsp);
5394d25adbebSXin Long 	}
5395d25adbebSXin Long 
5396d25adbebSXin Long 	return ret;
5397626d16f5SXin Long }
53985ec7d18dSXin Long EXPORT_SYMBOL_GPL(sctp_transport_traverse_process);
5399626d16f5SXin Long 
54001da177e4SLinus Torvalds /* 7.2.1 Association Status (SCTP_STATUS)
54011da177e4SLinus Torvalds 
54021da177e4SLinus Torvalds  * Applications can retrieve current status information about an
54031da177e4SLinus Torvalds  * association, including association state, peer receiver window size,
54041da177e4SLinus Torvalds  * number of unacked data chunks, and number of data chunks pending
54051da177e4SLinus Torvalds  * receipt.  This information is read-only.
54061da177e4SLinus Torvalds  */
sctp_getsockopt_sctp_status(struct sock * sk,int len,char __user * optval,int __user * optlen)54071da177e4SLinus Torvalds static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
54081da177e4SLinus Torvalds 				       char __user *optval,
54091da177e4SLinus Torvalds 				       int __user *optlen)
54101da177e4SLinus Torvalds {
54111da177e4SLinus Torvalds 	struct sctp_status status;
54121da177e4SLinus Torvalds 	struct sctp_association *asoc = NULL;
54131da177e4SLinus Torvalds 	struct sctp_transport *transport;
54141da177e4SLinus Torvalds 	sctp_assoc_t associd;
54151da177e4SLinus Torvalds 	int retval = 0;
54161da177e4SLinus Torvalds 
5417408f22e8SNeil Horman 	if (len < sizeof(status)) {
54181da177e4SLinus Torvalds 		retval = -EINVAL;
54191da177e4SLinus Torvalds 		goto out;
54201da177e4SLinus Torvalds 	}
54211da177e4SLinus Torvalds 
5422408f22e8SNeil Horman 	len = sizeof(status);
5423408f22e8SNeil Horman 	if (copy_from_user(&status, optval, len)) {
54241da177e4SLinus Torvalds 		retval = -EFAULT;
54251da177e4SLinus Torvalds 		goto out;
54261da177e4SLinus Torvalds 	}
54271da177e4SLinus Torvalds 
54281da177e4SLinus Torvalds 	associd = status.sstat_assoc_id;
54291da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, associd);
54301da177e4SLinus Torvalds 	if (!asoc) {
54311da177e4SLinus Torvalds 		retval = -EINVAL;
54321da177e4SLinus Torvalds 		goto out;
54331da177e4SLinus Torvalds 	}
54341da177e4SLinus Torvalds 
54351da177e4SLinus Torvalds 	transport = asoc->peer.primary_path;
54361da177e4SLinus Torvalds 
54371da177e4SLinus Torvalds 	status.sstat_assoc_id = sctp_assoc2id(asoc);
543838ab1fa9SDaniel Borkmann 	status.sstat_state = sctp_assoc_to_state(asoc);
54391da177e4SLinus Torvalds 	status.sstat_rwnd =  asoc->peer.rwnd;
54401da177e4SLinus Torvalds 	status.sstat_unackdata = asoc->unack_data;
54411da177e4SLinus Torvalds 
54421da177e4SLinus Torvalds 	status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
5443cee360abSXin Long 	status.sstat_instrms = asoc->stream.incnt;
5444cee360abSXin Long 	status.sstat_outstrms = asoc->stream.outcnt;
54451da177e4SLinus Torvalds 	status.sstat_fragmentation_point = asoc->frag_point;
54461da177e4SLinus Torvalds 	status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
54478cec6b80SAl Viro 	memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr,
54488cec6b80SAl Viro 			transport->af_specific->sockaddr_len);
54491da177e4SLinus Torvalds 	/* Map ipv4 address into v4-mapped-on-v6 address.  */
5450299ee123SJason Gunthorpe 	sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk),
54511da177e4SLinus Torvalds 		(union sctp_addr *)&status.sstat_primary.spinfo_address);
54523f7a87d2SFrank Filz 	status.sstat_primary.spinfo_state = transport->state;
54531da177e4SLinus Torvalds 	status.sstat_primary.spinfo_cwnd = transport->cwnd;
54541da177e4SLinus Torvalds 	status.sstat_primary.spinfo_srtt = transport->srtt;
54551da177e4SLinus Torvalds 	status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto);
545652ccb8e9SFrank Filz 	status.sstat_primary.spinfo_mtu = transport->pathmtu;
54571da177e4SLinus Torvalds 
54583f7a87d2SFrank Filz 	if (status.sstat_primary.spinfo_state == SCTP_UNKNOWN)
54593f7a87d2SFrank Filz 		status.sstat_primary.spinfo_state = SCTP_ACTIVE;
54603f7a87d2SFrank Filz 
54611da177e4SLinus Torvalds 	if (put_user(len, optlen)) {
54621da177e4SLinus Torvalds 		retval = -EFAULT;
54631da177e4SLinus Torvalds 		goto out;
54641da177e4SLinus Torvalds 	}
54651da177e4SLinus Torvalds 
5466bb33381dSDaniel Borkmann 	pr_debug("%s: len:%d, state:%d, rwnd:%d, assoc_id:%d\n",
5467bb33381dSDaniel Borkmann 		 __func__, len, status.sstat_state, status.sstat_rwnd,
54681da177e4SLinus Torvalds 		 status.sstat_assoc_id);
54691da177e4SLinus Torvalds 
54701da177e4SLinus Torvalds 	if (copy_to_user(optval, &status, len)) {
54711da177e4SLinus Torvalds 		retval = -EFAULT;
54721da177e4SLinus Torvalds 		goto out;
54731da177e4SLinus Torvalds 	}
54741da177e4SLinus Torvalds 
54751da177e4SLinus Torvalds out:
5476a02cec21SEric Dumazet 	return retval;
54771da177e4SLinus Torvalds }
54781da177e4SLinus Torvalds 
54791da177e4SLinus Torvalds 
54801da177e4SLinus Torvalds /* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO)
54811da177e4SLinus Torvalds  *
54821da177e4SLinus Torvalds  * Applications can retrieve information about a specific peer address
54831da177e4SLinus Torvalds  * of an association, including its reachability state, congestion
54841da177e4SLinus Torvalds  * window, and retransmission timer values.  This information is
54851da177e4SLinus Torvalds  * read-only.
54861da177e4SLinus Torvalds  */
sctp_getsockopt_peer_addr_info(struct sock * sk,int len,char __user * optval,int __user * optlen)54871da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
54881da177e4SLinus Torvalds 					  char __user *optval,
54891da177e4SLinus Torvalds 					  int __user *optlen)
54901da177e4SLinus Torvalds {
54911da177e4SLinus Torvalds 	struct sctp_paddrinfo pinfo;
54921da177e4SLinus Torvalds 	struct sctp_transport *transport;
54931da177e4SLinus Torvalds 	int retval = 0;
54941da177e4SLinus Torvalds 
5495408f22e8SNeil Horman 	if (len < sizeof(pinfo)) {
54961da177e4SLinus Torvalds 		retval = -EINVAL;
54971da177e4SLinus Torvalds 		goto out;
54981da177e4SLinus Torvalds 	}
54991da177e4SLinus Torvalds 
5500408f22e8SNeil Horman 	len = sizeof(pinfo);
5501408f22e8SNeil Horman 	if (copy_from_user(&pinfo, optval, len)) {
55021da177e4SLinus Torvalds 		retval = -EFAULT;
55031da177e4SLinus Torvalds 		goto out;
55041da177e4SLinus Torvalds 	}
55051da177e4SLinus Torvalds 
55061da177e4SLinus Torvalds 	transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address,
55071da177e4SLinus Torvalds 					   pinfo.spinfo_assoc_id);
5508aef587beSXin Long 	if (!transport) {
5509aef587beSXin Long 		retval = -EINVAL;
5510aef587beSXin Long 		goto out;
5511aef587beSXin Long 	}
5512aef587beSXin Long 
5513aef587beSXin Long 	if (transport->state == SCTP_PF &&
5514aef587beSXin Long 	    transport->asoc->pf_expose == SCTP_PF_EXPOSE_DISABLE) {
5515aef587beSXin Long 		retval = -EACCES;
5516aef587beSXin Long 		goto out;
5517aef587beSXin Long 	}
55181da177e4SLinus Torvalds 
55191da177e4SLinus Torvalds 	pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
55203f7a87d2SFrank Filz 	pinfo.spinfo_state = transport->state;
55211da177e4SLinus Torvalds 	pinfo.spinfo_cwnd = transport->cwnd;
55221da177e4SLinus Torvalds 	pinfo.spinfo_srtt = transport->srtt;
55231da177e4SLinus Torvalds 	pinfo.spinfo_rto = jiffies_to_msecs(transport->rto);
552452ccb8e9SFrank Filz 	pinfo.spinfo_mtu = transport->pathmtu;
55251da177e4SLinus Torvalds 
55263f7a87d2SFrank Filz 	if (pinfo.spinfo_state == SCTP_UNKNOWN)
55273f7a87d2SFrank Filz 		pinfo.spinfo_state = SCTP_ACTIVE;
55283f7a87d2SFrank Filz 
55291da177e4SLinus Torvalds 	if (put_user(len, optlen)) {
55301da177e4SLinus Torvalds 		retval = -EFAULT;
55311da177e4SLinus Torvalds 		goto out;
55321da177e4SLinus Torvalds 	}
55331da177e4SLinus Torvalds 
55341da177e4SLinus Torvalds 	if (copy_to_user(optval, &pinfo, len)) {
55351da177e4SLinus Torvalds 		retval = -EFAULT;
55361da177e4SLinus Torvalds 		goto out;
55371da177e4SLinus Torvalds 	}
55381da177e4SLinus Torvalds 
55391da177e4SLinus Torvalds out:
5540a02cec21SEric Dumazet 	return retval;
55411da177e4SLinus Torvalds }
55421da177e4SLinus Torvalds 
55431da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
55441da177e4SLinus Torvalds  *
55451da177e4SLinus Torvalds  * This option is a on/off flag.  If enabled no SCTP message
55461da177e4SLinus Torvalds  * fragmentation will be performed.  Instead if a message being sent
55471da177e4SLinus Torvalds  * exceeds the current PMTU size, the message will NOT be sent and
55481da177e4SLinus Torvalds  * instead a error will be indicated to the user.
55491da177e4SLinus Torvalds  */
sctp_getsockopt_disable_fragments(struct sock * sk,int len,char __user * optval,int __user * optlen)55501da177e4SLinus Torvalds static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
55511da177e4SLinus Torvalds 					char __user *optval, int __user *optlen)
55521da177e4SLinus Torvalds {
55531da177e4SLinus Torvalds 	int val;
55541da177e4SLinus Torvalds 
55551da177e4SLinus Torvalds 	if (len < sizeof(int))
55561da177e4SLinus Torvalds 		return -EINVAL;
55571da177e4SLinus Torvalds 
55581da177e4SLinus Torvalds 	len = sizeof(int);
55591da177e4SLinus Torvalds 	val = (sctp_sk(sk)->disable_fragments == 1);
55601da177e4SLinus Torvalds 	if (put_user(len, optlen))
55611da177e4SLinus Torvalds 		return -EFAULT;
55621da177e4SLinus Torvalds 	if (copy_to_user(optval, &val, len))
55631da177e4SLinus Torvalds 		return -EFAULT;
55641da177e4SLinus Torvalds 	return 0;
55651da177e4SLinus Torvalds }
55661da177e4SLinus Torvalds 
55671da177e4SLinus Torvalds /* 7.1.15 Set notification and ancillary events (SCTP_EVENTS)
55681da177e4SLinus Torvalds  *
55691da177e4SLinus Torvalds  * This socket option is used to specify various notifications and
55701da177e4SLinus Torvalds  * ancillary data the user wishes to receive.
55711da177e4SLinus Torvalds  */
sctp_getsockopt_events(struct sock * sk,int len,char __user * optval,int __user * optlen)55721da177e4SLinus Torvalds static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval,
55731da177e4SLinus Torvalds 				  int __user *optlen)
55741da177e4SLinus Torvalds {
55752cc0eeb6SXin Long 	struct sctp_event_subscribe subscribe;
55762cc0eeb6SXin Long 	__u8 *sn_type = (__u8 *)&subscribe;
55772cc0eeb6SXin Long 	int i;
55782cc0eeb6SXin Long 
5579a4b8e71bSJiri Slaby 	if (len == 0)
55801da177e4SLinus Torvalds 		return -EINVAL;
5581acdd5985SThomas Graf 	if (len > sizeof(struct sctp_event_subscribe))
5582408f22e8SNeil Horman 		len = sizeof(struct sctp_event_subscribe);
5583408f22e8SNeil Horman 	if (put_user(len, optlen))
5584408f22e8SNeil Horman 		return -EFAULT;
55852cc0eeb6SXin Long 
55862cc0eeb6SXin Long 	for (i = 0; i < len; i++)
55872cc0eeb6SXin Long 		sn_type[i] = sctp_ulpevent_type_enabled(sctp_sk(sk)->subscribe,
55882cc0eeb6SXin Long 							SCTP_SN_TYPE_BASE + i);
55892cc0eeb6SXin Long 
55902cc0eeb6SXin Long 	if (copy_to_user(optval, &subscribe, len))
55911da177e4SLinus Torvalds 		return -EFAULT;
55922cc0eeb6SXin Long 
55931da177e4SLinus Torvalds 	return 0;
55941da177e4SLinus Torvalds }
55951da177e4SLinus Torvalds 
55961da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE)
55971da177e4SLinus Torvalds  *
55981da177e4SLinus Torvalds  * This socket option is applicable to the UDP-style socket only.  When
55991da177e4SLinus Torvalds  * set it will cause associations that are idle for more than the
56001da177e4SLinus Torvalds  * specified number of seconds to automatically close.  An association
56011da177e4SLinus Torvalds  * being idle is defined an association that has NOT sent or received
56021da177e4SLinus Torvalds  * user data.  The special value of '0' indicates that no automatic
56031da177e4SLinus Torvalds  * close of any associations should be performed.  The option expects an
56041da177e4SLinus Torvalds  * integer defining the number of seconds of idle time before an
56051da177e4SLinus Torvalds  * association is closed.
56061da177e4SLinus Torvalds  */
sctp_getsockopt_autoclose(struct sock * sk,int len,char __user * optval,int __user * optlen)56071da177e4SLinus Torvalds static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optval, int __user *optlen)
56081da177e4SLinus Torvalds {
56091da177e4SLinus Torvalds 	/* Applicable to UDP-style socket only */
56101da177e4SLinus Torvalds 	if (sctp_style(sk, TCP))
56111da177e4SLinus Torvalds 		return -EOPNOTSUPP;
5612408f22e8SNeil Horman 	if (len < sizeof(int))
56131da177e4SLinus Torvalds 		return -EINVAL;
5614408f22e8SNeil Horman 	len = sizeof(int);
5615408f22e8SNeil Horman 	if (put_user(len, optlen))
5616408f22e8SNeil Horman 		return -EFAULT;
5617b2ce04c2SDavid Windsor 	if (put_user(sctp_sk(sk)->autoclose, (int __user *)optval))
56181da177e4SLinus Torvalds 		return -EFAULT;
56191da177e4SLinus Torvalds 	return 0;
56201da177e4SLinus Torvalds }
56211da177e4SLinus Torvalds 
56221da177e4SLinus Torvalds /* Helper routine to branch off an association to a new socket.  */
sctp_do_peeloff(struct sock * sk,sctp_assoc_t id,struct socket ** sockp)56230343c554SBenjamin Poirier int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
56241da177e4SLinus Torvalds {
56250343c554SBenjamin Poirier 	struct sctp_association *asoc = sctp_id2assoc(sk, id);
5626299ee123SJason Gunthorpe 	struct sctp_sock *sp = sctp_sk(sk);
56271da177e4SLinus Torvalds 	struct socket *sock;
56281da177e4SLinus Torvalds 	int err = 0;
56291da177e4SLinus Torvalds 
5630df80cd9bSXin Long 	/* Do not peel off from one netns to another one. */
5631df80cd9bSXin Long 	if (!net_eq(current->nsproxy->net_ns, sock_net(sk)))
5632df80cd9bSXin Long 		return -EINVAL;
5633df80cd9bSXin Long 
56340343c554SBenjamin Poirier 	if (!asoc)
56350343c554SBenjamin Poirier 		return -EINVAL;
56360343c554SBenjamin Poirier 
56371da177e4SLinus Torvalds 	/* An association cannot be branched off from an already peeled-off
56381da177e4SLinus Torvalds 	 * socket, nor is this supported for tcp style sockets.
56391da177e4SLinus Torvalds 	 */
56401da177e4SLinus Torvalds 	if (!sctp_style(sk, UDP))
56411da177e4SLinus Torvalds 		return -EINVAL;
56421da177e4SLinus Torvalds 
56431da177e4SLinus Torvalds 	/* Create a new socket.  */
56441da177e4SLinus Torvalds 	err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
56451da177e4SLinus Torvalds 	if (err < 0)
56461da177e4SLinus Torvalds 		return err;
56471da177e4SLinus Torvalds 
5648914e1c8bSVlad Yasevich 	sctp_copy_sock(sock->sk, sk, asoc);
56494f444308SVlad Yasevich 
56504f444308SVlad Yasevich 	/* Make peeled-off sockets more like 1-1 accepted sockets.
5651b7e10c25SRichard Haines 	 * Set the daddr and initialize id to something more random and also
5652b7e10c25SRichard Haines 	 * copy over any ip options.
56534f444308SVlad Yasevich 	 */
56548467dda0SPetr Malat 	sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sock->sk);
5655b7e10c25SRichard Haines 	sp->pf->copy_ip_options(sk, sock->sk);
5656914e1c8bSVlad Yasevich 
5657914e1c8bSVlad Yasevich 	/* Populate the fields of the newsk from the oldsk and migrate the
5658914e1c8bSVlad Yasevich 	 * asoc to the newsk.
5659914e1c8bSVlad Yasevich 	 */
566089664c62SXin Long 	err = sctp_sock_migrate(sk, sock->sk, asoc,
566189664c62SXin Long 				SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
566289664c62SXin Long 	if (err) {
566389664c62SXin Long 		sock_release(sock);
566489664c62SXin Long 		sock = NULL;
566589664c62SXin Long 	}
56664f444308SVlad Yasevich 
56671da177e4SLinus Torvalds 	*sockp = sock;
56681da177e4SLinus Torvalds 
56691da177e4SLinus Torvalds 	return err;
56701da177e4SLinus Torvalds }
56710343c554SBenjamin Poirier EXPORT_SYMBOL(sctp_do_peeloff);
56721da177e4SLinus Torvalds 
sctp_getsockopt_peeloff_common(struct sock * sk,sctp_peeloff_arg_t * peeloff,struct file ** newfile,unsigned flags)56732cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *peeloff,
56742cb5c8e3SNeil Horman 					  struct file **newfile, unsigned flags)
56752cb5c8e3SNeil Horman {
56762cb5c8e3SNeil Horman 	struct socket *newsock;
56772cb5c8e3SNeil Horman 	int retval;
56782cb5c8e3SNeil Horman 
56792cb5c8e3SNeil Horman 	retval = sctp_do_peeloff(sk, peeloff->associd, &newsock);
56802cb5c8e3SNeil Horman 	if (retval < 0)
56812cb5c8e3SNeil Horman 		goto out;
56822cb5c8e3SNeil Horman 
56832cb5c8e3SNeil Horman 	/* Map the socket to an unused fd that can be returned to the user.  */
56842cb5c8e3SNeil Horman 	retval = get_unused_fd_flags(flags & SOCK_CLOEXEC);
56852cb5c8e3SNeil Horman 	if (retval < 0) {
56862cb5c8e3SNeil Horman 		sock_release(newsock);
56872cb5c8e3SNeil Horman 		goto out;
56882cb5c8e3SNeil Horman 	}
56892cb5c8e3SNeil Horman 
56902cb5c8e3SNeil Horman 	*newfile = sock_alloc_file(newsock, 0, NULL);
56912cb5c8e3SNeil Horman 	if (IS_ERR(*newfile)) {
56922cb5c8e3SNeil Horman 		put_unused_fd(retval);
56932cb5c8e3SNeil Horman 		retval = PTR_ERR(*newfile);
56942cb5c8e3SNeil Horman 		*newfile = NULL;
56952cb5c8e3SNeil Horman 		return retval;
56962cb5c8e3SNeil Horman 	}
56972cb5c8e3SNeil Horman 
56982cb5c8e3SNeil Horman 	pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk,
56992cb5c8e3SNeil Horman 		 retval);
57002cb5c8e3SNeil Horman 
57012cb5c8e3SNeil Horman 	peeloff->sd = retval;
57022cb5c8e3SNeil Horman 
57032cb5c8e3SNeil Horman 	if (flags & SOCK_NONBLOCK)
57042cb5c8e3SNeil Horman 		(*newfile)->f_flags |= O_NONBLOCK;
57052cb5c8e3SNeil Horman out:
57062cb5c8e3SNeil Horman 	return retval;
57072cb5c8e3SNeil Horman }
57082cb5c8e3SNeil Horman 
sctp_getsockopt_peeloff(struct sock * sk,int len,char __user * optval,int __user * optlen)57091da177e4SLinus Torvalds static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen)
57101da177e4SLinus Torvalds {
57111da177e4SLinus Torvalds 	sctp_peeloff_arg_t peeloff;
57122cb5c8e3SNeil Horman 	struct file *newfile = NULL;
57131da177e4SLinus Torvalds 	int retval = 0;
57141da177e4SLinus Torvalds 
5715408f22e8SNeil Horman 	if (len < sizeof(sctp_peeloff_arg_t))
57161da177e4SLinus Torvalds 		return -EINVAL;
5717408f22e8SNeil Horman 	len = sizeof(sctp_peeloff_arg_t);
57181da177e4SLinus Torvalds 	if (copy_from_user(&peeloff, optval, len))
57191da177e4SLinus Torvalds 		return -EFAULT;
57201da177e4SLinus Torvalds 
57212cb5c8e3SNeil Horman 	retval = sctp_getsockopt_peeloff_common(sk, &peeloff, &newfile, 0);
57221da177e4SLinus Torvalds 	if (retval < 0)
57231da177e4SLinus Torvalds 		goto out;
57241da177e4SLinus Torvalds 
57251da177e4SLinus Torvalds 	/* Return the fd mapped to the new socket.  */
572656b31d1cSAl Viro 	if (put_user(len, optlen)) {
572756b31d1cSAl Viro 		fput(newfile);
572856b31d1cSAl Viro 		put_unused_fd(retval);
5729408f22e8SNeil Horman 		return -EFAULT;
573056b31d1cSAl Viro 	}
57312cb5c8e3SNeil Horman 
57322cb5c8e3SNeil Horman 	if (copy_to_user(optval, &peeloff, len)) {
57332cb5c8e3SNeil Horman 		fput(newfile);
57342cb5c8e3SNeil Horman 		put_unused_fd(retval);
57352cb5c8e3SNeil Horman 		return -EFAULT;
57362cb5c8e3SNeil Horman 	}
57372cb5c8e3SNeil Horman 	fd_install(retval, newfile);
57382cb5c8e3SNeil Horman out:
57392cb5c8e3SNeil Horman 	return retval;
57402cb5c8e3SNeil Horman }
57412cb5c8e3SNeil Horman 
sctp_getsockopt_peeloff_flags(struct sock * sk,int len,char __user * optval,int __user * optlen)57422cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len,
57432cb5c8e3SNeil Horman 					 char __user *optval, int __user *optlen)
57442cb5c8e3SNeil Horman {
57452cb5c8e3SNeil Horman 	sctp_peeloff_flags_arg_t peeloff;
57462cb5c8e3SNeil Horman 	struct file *newfile = NULL;
57472cb5c8e3SNeil Horman 	int retval = 0;
57482cb5c8e3SNeil Horman 
57492cb5c8e3SNeil Horman 	if (len < sizeof(sctp_peeloff_flags_arg_t))
57502cb5c8e3SNeil Horman 		return -EINVAL;
57512cb5c8e3SNeil Horman 	len = sizeof(sctp_peeloff_flags_arg_t);
57522cb5c8e3SNeil Horman 	if (copy_from_user(&peeloff, optval, len))
57532cb5c8e3SNeil Horman 		return -EFAULT;
57542cb5c8e3SNeil Horman 
57552cb5c8e3SNeil Horman 	retval = sctp_getsockopt_peeloff_common(sk, &peeloff.p_arg,
57562cb5c8e3SNeil Horman 						&newfile, peeloff.flags);
57572cb5c8e3SNeil Horman 	if (retval < 0)
57582cb5c8e3SNeil Horman 		goto out;
57592cb5c8e3SNeil Horman 
57602cb5c8e3SNeil Horman 	/* Return the fd mapped to the new socket.  */
57612cb5c8e3SNeil Horman 	if (put_user(len, optlen)) {
57622cb5c8e3SNeil Horman 		fput(newfile);
57632cb5c8e3SNeil Horman 		put_unused_fd(retval);
57642cb5c8e3SNeil Horman 		return -EFAULT;
57652cb5c8e3SNeil Horman 	}
57662cb5c8e3SNeil Horman 
576756b31d1cSAl Viro 	if (copy_to_user(optval, &peeloff, len)) {
576856b31d1cSAl Viro 		fput(newfile);
576956b31d1cSAl Viro 		put_unused_fd(retval);
577056b31d1cSAl Viro 		return -EFAULT;
577156b31d1cSAl Viro 	}
577256b31d1cSAl Viro 	fd_install(retval, newfile);
57731da177e4SLinus Torvalds out:
57741da177e4SLinus Torvalds 	return retval;
57751da177e4SLinus Torvalds }
57761da177e4SLinus Torvalds 
57771da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS)
57781da177e4SLinus Torvalds  *
57791da177e4SLinus Torvalds  * Applications can enable or disable heartbeats for any peer address of
57801da177e4SLinus Torvalds  * an association, modify an address's heartbeat interval, force a
57811da177e4SLinus Torvalds  * heartbeat to be sent immediately, and adjust the address's maximum
57821da177e4SLinus Torvalds  * number of retransmissions sent before an address is considered
57831da177e4SLinus Torvalds  * unreachable.  The following structure is used to access and modify an
57841da177e4SLinus Torvalds  * address's parameters:
57851da177e4SLinus Torvalds  *
57861da177e4SLinus Torvalds  *  struct sctp_paddrparams {
57871da177e4SLinus Torvalds  *     sctp_assoc_t            spp_assoc_id;
57881da177e4SLinus Torvalds  *     struct sockaddr_storage spp_address;
57891da177e4SLinus Torvalds  *     uint32_t                spp_hbinterval;
57901da177e4SLinus Torvalds  *     uint16_t                spp_pathmaxrxt;
579152ccb8e9SFrank Filz  *     uint32_t                spp_pathmtu;
579252ccb8e9SFrank Filz  *     uint32_t                spp_sackdelay;
579352ccb8e9SFrank Filz  *     uint32_t                spp_flags;
57941da177e4SLinus Torvalds  * };
57951da177e4SLinus Torvalds  *
579652ccb8e9SFrank Filz  *   spp_assoc_id    - (one-to-many style socket) This is filled in the
579752ccb8e9SFrank Filz  *                     application, and identifies the association for
579852ccb8e9SFrank Filz  *                     this query.
57991da177e4SLinus Torvalds  *   spp_address     - This specifies which address is of interest.
58001da177e4SLinus Torvalds  *   spp_hbinterval  - This contains the value of the heartbeat interval,
580152ccb8e9SFrank Filz  *                     in milliseconds.  If a  value of zero
580252ccb8e9SFrank Filz  *                     is present in this field then no changes are to
580352ccb8e9SFrank Filz  *                     be made to this parameter.
58041da177e4SLinus Torvalds  *   spp_pathmaxrxt  - This contains the maximum number of
58051da177e4SLinus Torvalds  *                     retransmissions before this address shall be
580652ccb8e9SFrank Filz  *                     considered unreachable. If a  value of zero
580752ccb8e9SFrank Filz  *                     is present in this field then no changes are to
580852ccb8e9SFrank Filz  *                     be made to this parameter.
580952ccb8e9SFrank Filz  *   spp_pathmtu     - When Path MTU discovery is disabled the value
581052ccb8e9SFrank Filz  *                     specified here will be the "fixed" path mtu.
581152ccb8e9SFrank Filz  *                     Note that if the spp_address field is empty
581252ccb8e9SFrank Filz  *                     then all associations on this address will
581352ccb8e9SFrank Filz  *                     have this fixed path mtu set upon them.
581452ccb8e9SFrank Filz  *
581552ccb8e9SFrank Filz  *   spp_sackdelay   - When delayed sack is enabled, this value specifies
581652ccb8e9SFrank Filz  *                     the number of milliseconds that sacks will be delayed
581752ccb8e9SFrank Filz  *                     for. This value will apply to all addresses of an
581852ccb8e9SFrank Filz  *                     association if the spp_address field is empty. Note
581952ccb8e9SFrank Filz  *                     also, that if delayed sack is enabled and this
582052ccb8e9SFrank Filz  *                     value is set to 0, no change is made to the last
582152ccb8e9SFrank Filz  *                     recorded delayed sack timer value.
582252ccb8e9SFrank Filz  *
582352ccb8e9SFrank Filz  *   spp_flags       - These flags are used to control various features
582452ccb8e9SFrank Filz  *                     on an association. The flag field may contain
582552ccb8e9SFrank Filz  *                     zero or more of the following options.
582652ccb8e9SFrank Filz  *
582752ccb8e9SFrank Filz  *                     SPP_HB_ENABLE  - Enable heartbeats on the
582852ccb8e9SFrank Filz  *                     specified address. Note that if the address
582952ccb8e9SFrank Filz  *                     field is empty all addresses for the association
583052ccb8e9SFrank Filz  *                     have heartbeats enabled upon them.
583152ccb8e9SFrank Filz  *
583252ccb8e9SFrank Filz  *                     SPP_HB_DISABLE - Disable heartbeats on the
583352ccb8e9SFrank Filz  *                     speicifed address. Note that if the address
583452ccb8e9SFrank Filz  *                     field is empty all addresses for the association
583552ccb8e9SFrank Filz  *                     will have their heartbeats disabled. Note also
583652ccb8e9SFrank Filz  *                     that SPP_HB_ENABLE and SPP_HB_DISABLE are
583752ccb8e9SFrank Filz  *                     mutually exclusive, only one of these two should
583852ccb8e9SFrank Filz  *                     be specified. Enabling both fields will have
583952ccb8e9SFrank Filz  *                     undetermined results.
584052ccb8e9SFrank Filz  *
584152ccb8e9SFrank Filz  *                     SPP_HB_DEMAND - Request a user initiated heartbeat
584252ccb8e9SFrank Filz  *                     to be made immediately.
584352ccb8e9SFrank Filz  *
584452ccb8e9SFrank Filz  *                     SPP_PMTUD_ENABLE - This field will enable PMTU
584552ccb8e9SFrank Filz  *                     discovery upon the specified address. Note that
584652ccb8e9SFrank Filz  *                     if the address feild is empty then all addresses
584752ccb8e9SFrank Filz  *                     on the association are effected.
584852ccb8e9SFrank Filz  *
584952ccb8e9SFrank Filz  *                     SPP_PMTUD_DISABLE - This field will disable PMTU
585052ccb8e9SFrank Filz  *                     discovery upon the specified address. Note that
585152ccb8e9SFrank Filz  *                     if the address feild is empty then all addresses
585252ccb8e9SFrank Filz  *                     on the association are effected. Not also that
585352ccb8e9SFrank Filz  *                     SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually
585452ccb8e9SFrank Filz  *                     exclusive. Enabling both will have undetermined
585552ccb8e9SFrank Filz  *                     results.
585652ccb8e9SFrank Filz  *
585752ccb8e9SFrank Filz  *                     SPP_SACKDELAY_ENABLE - Setting this flag turns
585852ccb8e9SFrank Filz  *                     on delayed sack. The time specified in spp_sackdelay
585952ccb8e9SFrank Filz  *                     is used to specify the sack delay for this address. Note
586052ccb8e9SFrank Filz  *                     that if spp_address is empty then all addresses will
586152ccb8e9SFrank Filz  *                     enable delayed sack and take on the sack delay
586252ccb8e9SFrank Filz  *                     value specified in spp_sackdelay.
586352ccb8e9SFrank Filz  *                     SPP_SACKDELAY_DISABLE - Setting this flag turns
586452ccb8e9SFrank Filz  *                     off delayed sack. If the spp_address field is blank then
586552ccb8e9SFrank Filz  *                     delayed sack is disabled for the entire association. Note
586652ccb8e9SFrank Filz  *                     also that this field is mutually exclusive to
586752ccb8e9SFrank Filz  *                     SPP_SACKDELAY_ENABLE, setting both will have undefined
586852ccb8e9SFrank Filz  *                     results.
58690b0dce7aSXin Long  *
58700b0dce7aSXin Long  *                     SPP_IPV6_FLOWLABEL:  Setting this flag enables the
58710b0dce7aSXin Long  *                     setting of the IPV6 flow label value.  The value is
58720b0dce7aSXin Long  *                     contained in the spp_ipv6_flowlabel field.
58730b0dce7aSXin Long  *                     Upon retrieval, this flag will be set to indicate that
58740b0dce7aSXin Long  *                     the spp_ipv6_flowlabel field has a valid value returned.
58750b0dce7aSXin Long  *                     If a specific destination address is set (in the
58760b0dce7aSXin Long  *                     spp_address field), then the value returned is that of
58770b0dce7aSXin Long  *                     the address.  If just an association is specified (and
58780b0dce7aSXin Long  *                     no address), then the association's default flow label
58790b0dce7aSXin Long  *                     is returned.  If neither an association nor a destination
58800b0dce7aSXin Long  *                     is specified, then the socket's default flow label is
58810b0dce7aSXin Long  *                     returned.  For non-IPv6 sockets, this flag will be left
58820b0dce7aSXin Long  *                     cleared.
58830b0dce7aSXin Long  *
58840b0dce7aSXin Long  *                     SPP_DSCP:  Setting this flag enables the setting of the
58850b0dce7aSXin Long  *                     Differentiated Services Code Point (DSCP) value
58860b0dce7aSXin Long  *                     associated with either the association or a specific
58870b0dce7aSXin Long  *                     address.  The value is obtained in the spp_dscp field.
58880b0dce7aSXin Long  *                     Upon retrieval, this flag will be set to indicate that
58890b0dce7aSXin Long  *                     the spp_dscp field has a valid value returned.  If a
58900b0dce7aSXin Long  *                     specific destination address is set when called (in the
58910b0dce7aSXin Long  *                     spp_address field), then that specific destination
58920b0dce7aSXin Long  *                     address's DSCP value is returned.  If just an association
58930b0dce7aSXin Long  *                     is specified, then the association's default DSCP is
58940b0dce7aSXin Long  *                     returned.  If neither an association nor a destination is
58950b0dce7aSXin Long  *                     specified, then the socket's default DSCP is returned.
58960b0dce7aSXin Long  *
58970b0dce7aSXin Long  *   spp_ipv6_flowlabel
58980b0dce7aSXin Long  *                   - This field is used in conjunction with the
58990b0dce7aSXin Long  *                     SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label.
59000b0dce7aSXin Long  *                     The 20 least significant bits are used for the flow
59010b0dce7aSXin Long  *                     label.  This setting has precedence over any IPv6-layer
59020b0dce7aSXin Long  *                     setting.
59030b0dce7aSXin Long  *
59040b0dce7aSXin Long  *   spp_dscp        - This field is used in conjunction with the SPP_DSCP flag
59050b0dce7aSXin Long  *                     and contains the DSCP.  The 6 most significant bits are
59060b0dce7aSXin Long  *                     used for the DSCP.  This setting has precedence over any
59070b0dce7aSXin Long  *                     IPv4- or IPv6- layer setting.
59081da177e4SLinus Torvalds  */
sctp_getsockopt_peer_addr_params(struct sock * sk,int len,char __user * optval,int __user * optlen)59091da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
59101da177e4SLinus Torvalds 					    char __user *optval, int __user *optlen)
59111da177e4SLinus Torvalds {
59121da177e4SLinus Torvalds 	struct sctp_paddrparams  params;
591352ccb8e9SFrank Filz 	struct sctp_transport   *trans = NULL;
591452ccb8e9SFrank Filz 	struct sctp_association *asoc = NULL;
591552ccb8e9SFrank Filz 	struct sctp_sock        *sp = sctp_sk(sk);
59161da177e4SLinus Torvalds 
59170b0dce7aSXin Long 	if (len >= sizeof(params))
59180b0dce7aSXin Long 		len = sizeof(params);
59190b0dce7aSXin Long 	else if (len >= ALIGN(offsetof(struct sctp_paddrparams,
59200b0dce7aSXin Long 				       spp_ipv6_flowlabel), 4))
59210b0dce7aSXin Long 		len = ALIGN(offsetof(struct sctp_paddrparams,
59220b0dce7aSXin Long 				     spp_ipv6_flowlabel), 4);
59230b0dce7aSXin Long 	else
59241da177e4SLinus Torvalds 		return -EINVAL;
59250b0dce7aSXin Long 
59261da177e4SLinus Torvalds 	if (copy_from_user(&params, optval, len))
59271da177e4SLinus Torvalds 		return -EFAULT;
59281da177e4SLinus Torvalds 
592952ccb8e9SFrank Filz 	/* If an address other than INADDR_ANY is specified, and
593052ccb8e9SFrank Filz 	 * no transport is found, then the request is invalid.
59311da177e4SLinus Torvalds 	 */
593252cae8f0SVlad Yasevich 	if (!sctp_is_any(sk, (union sctp_addr *)&params.spp_address)) {
59331da177e4SLinus Torvalds 		trans = sctp_addr_id2transport(sk, &params.spp_address,
59341da177e4SLinus Torvalds 					       params.spp_assoc_id);
593552ccb8e9SFrank Filz 		if (!trans) {
5936bb33381dSDaniel Borkmann 			pr_debug("%s: failed no transport\n", __func__);
59371da177e4SLinus Torvalds 			return -EINVAL;
593852ccb8e9SFrank Filz 		}
593952ccb8e9SFrank Filz 	}
59401da177e4SLinus Torvalds 
5941b99e5e02SXin Long 	/* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the
5942b99e5e02SXin Long 	 * socket is a one to many style socket, and an association
5943b99e5e02SXin Long 	 * was not found, then the id was invalid.
59441da177e4SLinus Torvalds 	 */
594552ccb8e9SFrank Filz 	asoc = sctp_id2assoc(sk, params.spp_assoc_id);
5946b99e5e02SXin Long 	if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC &&
5947b99e5e02SXin Long 	    sctp_style(sk, UDP)) {
5948bb33381dSDaniel Borkmann 		pr_debug("%s: failed no association\n", __func__);
594952ccb8e9SFrank Filz 		return -EINVAL;
595052ccb8e9SFrank Filz 	}
59511da177e4SLinus Torvalds 
595252ccb8e9SFrank Filz 	if (trans) {
595352ccb8e9SFrank Filz 		/* Fetch transport values. */
595452ccb8e9SFrank Filz 		params.spp_hbinterval = jiffies_to_msecs(trans->hbinterval);
595552ccb8e9SFrank Filz 		params.spp_pathmtu    = trans->pathmtu;
595652ccb8e9SFrank Filz 		params.spp_pathmaxrxt = trans->pathmaxrxt;
595752ccb8e9SFrank Filz 		params.spp_sackdelay  = jiffies_to_msecs(trans->sackdelay);
59581da177e4SLinus Torvalds 
595952ccb8e9SFrank Filz 		/*draft-11 doesn't say what to return in spp_flags*/
596052ccb8e9SFrank Filz 		params.spp_flags      = trans->param_flags;
59610b0dce7aSXin Long 		if (trans->flowlabel & SCTP_FLOWLABEL_SET_MASK) {
59620b0dce7aSXin Long 			params.spp_ipv6_flowlabel = trans->flowlabel &
59630b0dce7aSXin Long 						    SCTP_FLOWLABEL_VAL_MASK;
59640b0dce7aSXin Long 			params.spp_flags |= SPP_IPV6_FLOWLABEL;
59650b0dce7aSXin Long 		}
59660b0dce7aSXin Long 		if (trans->dscp & SCTP_DSCP_SET_MASK) {
59670b0dce7aSXin Long 			params.spp_dscp	= trans->dscp & SCTP_DSCP_VAL_MASK;
59680b0dce7aSXin Long 			params.spp_flags |= SPP_DSCP;
59690b0dce7aSXin Long 		}
597052ccb8e9SFrank Filz 	} else if (asoc) {
597152ccb8e9SFrank Filz 		/* Fetch association values. */
597252ccb8e9SFrank Filz 		params.spp_hbinterval = jiffies_to_msecs(asoc->hbinterval);
597352ccb8e9SFrank Filz 		params.spp_pathmtu    = asoc->pathmtu;
597452ccb8e9SFrank Filz 		params.spp_pathmaxrxt = asoc->pathmaxrxt;
597552ccb8e9SFrank Filz 		params.spp_sackdelay  = jiffies_to_msecs(asoc->sackdelay);
597652ccb8e9SFrank Filz 
597752ccb8e9SFrank Filz 		/*draft-11 doesn't say what to return in spp_flags*/
597852ccb8e9SFrank Filz 		params.spp_flags      = asoc->param_flags;
59790b0dce7aSXin Long 		if (asoc->flowlabel & SCTP_FLOWLABEL_SET_MASK) {
59800b0dce7aSXin Long 			params.spp_ipv6_flowlabel = asoc->flowlabel &
59810b0dce7aSXin Long 						    SCTP_FLOWLABEL_VAL_MASK;
59820b0dce7aSXin Long 			params.spp_flags |= SPP_IPV6_FLOWLABEL;
59830b0dce7aSXin Long 		}
59840b0dce7aSXin Long 		if (asoc->dscp & SCTP_DSCP_SET_MASK) {
59850b0dce7aSXin Long 			params.spp_dscp	= asoc->dscp & SCTP_DSCP_VAL_MASK;
59860b0dce7aSXin Long 			params.spp_flags |= SPP_DSCP;
59870b0dce7aSXin Long 		}
598852ccb8e9SFrank Filz 	} else {
598952ccb8e9SFrank Filz 		/* Fetch socket values. */
599052ccb8e9SFrank Filz 		params.spp_hbinterval = sp->hbinterval;
599152ccb8e9SFrank Filz 		params.spp_pathmtu    = sp->pathmtu;
599252ccb8e9SFrank Filz 		params.spp_sackdelay  = sp->sackdelay;
599352ccb8e9SFrank Filz 		params.spp_pathmaxrxt = sp->pathmaxrxt;
599452ccb8e9SFrank Filz 
599552ccb8e9SFrank Filz 		/*draft-11 doesn't say what to return in spp_flags*/
599652ccb8e9SFrank Filz 		params.spp_flags      = sp->param_flags;
59970b0dce7aSXin Long 		if (sp->flowlabel & SCTP_FLOWLABEL_SET_MASK) {
59980b0dce7aSXin Long 			params.spp_ipv6_flowlabel = sp->flowlabel &
59990b0dce7aSXin Long 						    SCTP_FLOWLABEL_VAL_MASK;
60000b0dce7aSXin Long 			params.spp_flags |= SPP_IPV6_FLOWLABEL;
60010b0dce7aSXin Long 		}
60020b0dce7aSXin Long 		if (sp->dscp & SCTP_DSCP_SET_MASK) {
60030b0dce7aSXin Long 			params.spp_dscp	= sp->dscp & SCTP_DSCP_VAL_MASK;
60040b0dce7aSXin Long 			params.spp_flags |= SPP_DSCP;
60050b0dce7aSXin Long 		}
600652ccb8e9SFrank Filz 	}
600752ccb8e9SFrank Filz 
60081da177e4SLinus Torvalds 	if (copy_to_user(optval, &params, len))
60091da177e4SLinus Torvalds 		return -EFAULT;
60101da177e4SLinus Torvalds 
60111da177e4SLinus Torvalds 	if (put_user(len, optlen))
60121da177e4SLinus Torvalds 		return -EFAULT;
60131da177e4SLinus Torvalds 
60141da177e4SLinus Torvalds 	return 0;
60151da177e4SLinus Torvalds }
60161da177e4SLinus Torvalds 
6017d364d927SWei Yongjun /*
6018d364d927SWei Yongjun  * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
60197708610bSFrank Filz  *
6020d364d927SWei Yongjun  * This option will effect the way delayed acks are performed.  This
6021d364d927SWei Yongjun  * option allows you to get or set the delayed ack time, in
6022d364d927SWei Yongjun  * milliseconds.  It also allows changing the delayed ack frequency.
6023d364d927SWei Yongjun  * Changing the frequency to 1 disables the delayed sack algorithm.  If
6024d364d927SWei Yongjun  * the assoc_id is 0, then this sets or gets the endpoints default
6025d364d927SWei Yongjun  * values.  If the assoc_id field is non-zero, then the set or get
6026d364d927SWei Yongjun  * effects the specified association for the one to many model (the
6027d364d927SWei Yongjun  * assoc_id field is ignored by the one to one model).  Note that if
6028d364d927SWei Yongjun  * sack_delay or sack_freq are 0 when setting this option, then the
6029d364d927SWei Yongjun  * current values will remain unchanged.
60307708610bSFrank Filz  *
6031d364d927SWei Yongjun  * struct sctp_sack_info {
6032d364d927SWei Yongjun  *     sctp_assoc_t            sack_assoc_id;
6033d364d927SWei Yongjun  *     uint32_t                sack_delay;
6034d364d927SWei Yongjun  *     uint32_t                sack_freq;
60357708610bSFrank Filz  * };
60367708610bSFrank Filz  *
6037d364d927SWei Yongjun  * sack_assoc_id -  This parameter, indicates which association the user
6038d364d927SWei Yongjun  *    is performing an action upon.  Note that if this field's value is
6039d364d927SWei Yongjun  *    zero then the endpoints default value is changed (effecting future
60407708610bSFrank Filz  *    associations only).
60417708610bSFrank Filz  *
6042d364d927SWei Yongjun  * sack_delay -  This parameter contains the number of milliseconds that
6043d364d927SWei Yongjun  *    the user is requesting the delayed ACK timer be set to.  Note that
6044d364d927SWei Yongjun  *    this value is defined in the standard to be between 200 and 500
6045d364d927SWei Yongjun  *    milliseconds.
60467708610bSFrank Filz  *
6047d364d927SWei Yongjun  * sack_freq -  This parameter contains the number of packets that must
6048d364d927SWei Yongjun  *    be received before a sack is sent without waiting for the delay
6049d364d927SWei Yongjun  *    timer to expire.  The default value for this is 2, setting this
6050d364d927SWei Yongjun  *    value to 1 will disable the delayed sack algorithm.
60517708610bSFrank Filz  */
sctp_getsockopt_delayed_ack(struct sock * sk,int len,char __user * optval,int __user * optlen)6052d364d927SWei Yongjun static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
60537708610bSFrank Filz 					    char __user *optval,
60547708610bSFrank Filz 					    int __user *optlen)
60557708610bSFrank Filz {
6056d364d927SWei Yongjun 	struct sctp_sack_info    params;
60577708610bSFrank Filz 	struct sctp_association *asoc = NULL;
60587708610bSFrank Filz 	struct sctp_sock        *sp = sctp_sk(sk);
60597708610bSFrank Filz 
6060d364d927SWei Yongjun 	if (len >= sizeof(struct sctp_sack_info)) {
6061d364d927SWei Yongjun 		len = sizeof(struct sctp_sack_info);
6062408f22e8SNeil Horman 
60637708610bSFrank Filz 		if (copy_from_user(&params, optval, len))
60647708610bSFrank Filz 			return -EFAULT;
6065d364d927SWei Yongjun 	} else if (len == sizeof(struct sctp_assoc_value)) {
606694f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
6067f916ec96SNeil Horman 				    "%s (pid %d) "
606894f65193SNeil Horman 				    "Use of struct sctp_assoc_value in delayed_ack socket option.\n"
6069f916ec96SNeil Horman 				    "Use struct sctp_sack_info instead\n",
6070f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
6071d364d927SWei Yongjun 		if (copy_from_user(&params, optval, len))
6072d364d927SWei Yongjun 			return -EFAULT;
6073d364d927SWei Yongjun 	} else
6074d364d927SWei Yongjun 		return -EINVAL;
60757708610bSFrank Filz 
60769c5829e1SXin Long 	/* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the
60779c5829e1SXin Long 	 * socket is a one to many style socket, and an association
60789c5829e1SXin Long 	 * was not found, then the id was invalid.
60797708610bSFrank Filz 	 */
6080d364d927SWei Yongjun 	asoc = sctp_id2assoc(sk, params.sack_assoc_id);
60819c5829e1SXin Long 	if (!asoc && params.sack_assoc_id != SCTP_FUTURE_ASSOC &&
60829c5829e1SXin Long 	    sctp_style(sk, UDP))
60837708610bSFrank Filz 		return -EINVAL;
60847708610bSFrank Filz 
60857708610bSFrank Filz 	if (asoc) {
60867708610bSFrank Filz 		/* Fetch association values. */
6087d364d927SWei Yongjun 		if (asoc->param_flags & SPP_SACKDELAY_ENABLE) {
60889c5829e1SXin Long 			params.sack_delay = jiffies_to_msecs(asoc->sackdelay);
6089d364d927SWei Yongjun 			params.sack_freq = asoc->sackfreq;
6090d364d927SWei Yongjun 
6091d364d927SWei Yongjun 		} else {
6092d364d927SWei Yongjun 			params.sack_delay = 0;
6093d364d927SWei Yongjun 			params.sack_freq = 1;
6094d364d927SWei Yongjun 		}
60957708610bSFrank Filz 	} else {
60967708610bSFrank Filz 		/* Fetch socket values. */
6097d364d927SWei Yongjun 		if (sp->param_flags & SPP_SACKDELAY_ENABLE) {
6098d364d927SWei Yongjun 			params.sack_delay  = sp->sackdelay;
6099d364d927SWei Yongjun 			params.sack_freq = sp->sackfreq;
6100d364d927SWei Yongjun 		} else {
6101d364d927SWei Yongjun 			params.sack_delay  = 0;
6102d364d927SWei Yongjun 			params.sack_freq = 1;
6103d364d927SWei Yongjun 		}
61047708610bSFrank Filz 	}
61057708610bSFrank Filz 
61067708610bSFrank Filz 	if (copy_to_user(optval, &params, len))
61077708610bSFrank Filz 		return -EFAULT;
61087708610bSFrank Filz 
61097708610bSFrank Filz 	if (put_user(len, optlen))
61107708610bSFrank Filz 		return -EFAULT;
61117708610bSFrank Filz 
61127708610bSFrank Filz 	return 0;
61137708610bSFrank Filz }
61147708610bSFrank Filz 
61151da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG)
61161da177e4SLinus Torvalds  *
61171da177e4SLinus Torvalds  * Applications can specify protocol parameters for the default association
61181da177e4SLinus Torvalds  * initialization.  The option name argument to setsockopt() and getsockopt()
61191da177e4SLinus Torvalds  * is SCTP_INITMSG.
61201da177e4SLinus Torvalds  *
61211da177e4SLinus Torvalds  * Setting initialization parameters is effective only on an unconnected
61221da177e4SLinus Torvalds  * socket (for UDP-style sockets only future associations are effected
61231da177e4SLinus Torvalds  * by the change).  With TCP-style sockets, this option is inherited by
61241da177e4SLinus Torvalds  * sockets derived from a listener socket.
61251da177e4SLinus Torvalds  */
sctp_getsockopt_initmsg(struct sock * sk,int len,char __user * optval,int __user * optlen)61261da177e4SLinus Torvalds static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen)
61271da177e4SLinus Torvalds {
6128408f22e8SNeil Horman 	if (len < sizeof(struct sctp_initmsg))
61291da177e4SLinus Torvalds 		return -EINVAL;
6130408f22e8SNeil Horman 	len = sizeof(struct sctp_initmsg);
6131408f22e8SNeil Horman 	if (put_user(len, optlen))
6132408f22e8SNeil Horman 		return -EFAULT;
61331da177e4SLinus Torvalds 	if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len))
61341da177e4SLinus Torvalds 		return -EFAULT;
61351da177e4SLinus Torvalds 	return 0;
61361da177e4SLinus Torvalds }
61371da177e4SLinus Torvalds 
61381da177e4SLinus Torvalds 
sctp_getsockopt_peer_addrs(struct sock * sk,int len,char __user * optval,int __user * optlen)61395fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
61405fe467eeSIvan Skytte Jørgensen 				      char __user *optval, int __user *optlen)
61415fe467eeSIvan Skytte Jørgensen {
61425fe467eeSIvan Skytte Jørgensen 	struct sctp_association *asoc;
61435fe467eeSIvan Skytte Jørgensen 	int cnt = 0;
61445fe467eeSIvan Skytte Jørgensen 	struct sctp_getaddrs getaddrs;
61455fe467eeSIvan Skytte Jørgensen 	struct sctp_transport *from;
61465fe467eeSIvan Skytte Jørgensen 	void __user *to;
61475fe467eeSIvan Skytte Jørgensen 	union sctp_addr temp;
61485fe467eeSIvan Skytte Jørgensen 	struct sctp_sock *sp = sctp_sk(sk);
61495fe467eeSIvan Skytte Jørgensen 	int addrlen;
61505fe467eeSIvan Skytte Jørgensen 	size_t space_left;
61515fe467eeSIvan Skytte Jørgensen 	int bytes_copied;
61525fe467eeSIvan Skytte Jørgensen 
61535fe467eeSIvan Skytte Jørgensen 	if (len < sizeof(struct sctp_getaddrs))
61545fe467eeSIvan Skytte Jørgensen 		return -EINVAL;
61555fe467eeSIvan Skytte Jørgensen 
61565fe467eeSIvan Skytte Jørgensen 	if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
61575fe467eeSIvan Skytte Jørgensen 		return -EFAULT;
61585fe467eeSIvan Skytte Jørgensen 
61595fe467eeSIvan Skytte Jørgensen 	/* For UDP-style sockets, id specifies the association to query.  */
61605fe467eeSIvan Skytte Jørgensen 	asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
61615fe467eeSIvan Skytte Jørgensen 	if (!asoc)
61625fe467eeSIvan Skytte Jørgensen 		return -EINVAL;
61635fe467eeSIvan Skytte Jørgensen 
61645fe467eeSIvan Skytte Jørgensen 	to = optval + offsetof(struct sctp_getaddrs, addrs);
6165186e2343SNeil Horman 	space_left = len - offsetof(struct sctp_getaddrs, addrs);
61665fe467eeSIvan Skytte Jørgensen 
61679dbc15f0SRobert P. J. Day 	list_for_each_entry(from, &asoc->peer.transport_addr_list,
61689dbc15f0SRobert P. J. Day 				transports) {
6169b3f5b3b6SAl Viro 		memcpy(&temp, &from->ipaddr, sizeof(temp));
6170299ee123SJason Gunthorpe 		addrlen = sctp_get_pf_specific(sk->sk_family)
6171299ee123SJason Gunthorpe 			      ->addr_to_user(sp, &temp);
61725fe467eeSIvan Skytte Jørgensen 		if (space_left < addrlen)
61735fe467eeSIvan Skytte Jørgensen 			return -ENOMEM;
61745fe467eeSIvan Skytte Jørgensen 		if (copy_to_user(to, &temp, addrlen))
61755fe467eeSIvan Skytte Jørgensen 			return -EFAULT;
61765fe467eeSIvan Skytte Jørgensen 		to += addrlen;
61775fe467eeSIvan Skytte Jørgensen 		cnt++;
61785fe467eeSIvan Skytte Jørgensen 		space_left -= addrlen;
61795fe467eeSIvan Skytte Jørgensen 	}
61805fe467eeSIvan Skytte Jørgensen 
61815fe467eeSIvan Skytte Jørgensen 	if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num))
61825fe467eeSIvan Skytte Jørgensen 		return -EFAULT;
61835fe467eeSIvan Skytte Jørgensen 	bytes_copied = ((char __user *)to) - optval;
61845fe467eeSIvan Skytte Jørgensen 	if (put_user(bytes_copied, optlen))
61855fe467eeSIvan Skytte Jørgensen 		return -EFAULT;
61865fe467eeSIvan Skytte Jørgensen 
61875fe467eeSIvan Skytte Jørgensen 	return 0;
61885fe467eeSIvan Skytte Jørgensen }
61895fe467eeSIvan Skytte Jørgensen 
sctp_copy_laddrs(struct sock * sk,__u16 port,void * to,size_t space_left,int * bytes_copied)6190aad97f38SVlad Yasevich static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
6191aad97f38SVlad Yasevich 			    size_t space_left, int *bytes_copied)
61925fe467eeSIvan Skytte Jørgensen {
61935fe467eeSIvan Skytte Jørgensen 	struct sctp_sockaddr_entry *addr;
61945fe467eeSIvan Skytte Jørgensen 	union sctp_addr temp;
61955fe467eeSIvan Skytte Jørgensen 	int cnt = 0;
61965fe467eeSIvan Skytte Jørgensen 	int addrlen;
61974db67e80SEric W. Biederman 	struct net *net = sock_net(sk);
61985fe467eeSIvan Skytte Jørgensen 
619929303547SVlad Yasevich 	rcu_read_lock();
62004db67e80SEric W. Biederman 	list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) {
620129303547SVlad Yasevich 		if (!addr->valid)
620229303547SVlad Yasevich 			continue;
620329303547SVlad Yasevich 
62045fe467eeSIvan Skytte Jørgensen 		if ((PF_INET == sk->sk_family) &&
62056244be4eSAl Viro 		    (AF_INET6 == addr->a.sa.sa_family))
62065fe467eeSIvan Skytte Jørgensen 			continue;
62077dab83deSVlad Yasevich 		if ((PF_INET6 == sk->sk_family) &&
62087dab83deSVlad Yasevich 		    inet_v6_ipv6only(sk) &&
62097dab83deSVlad Yasevich 		    (AF_INET == addr->a.sa.sa_family))
62107dab83deSVlad Yasevich 			continue;
62116244be4eSAl Viro 		memcpy(&temp, &addr->a, sizeof(temp));
6212b46ae36dSVlad Yasevich 		if (!temp.v4.sin_port)
6213b46ae36dSVlad Yasevich 			temp.v4.sin_port = htons(port);
6214b46ae36dSVlad Yasevich 
6215299ee123SJason Gunthorpe 		addrlen = sctp_get_pf_specific(sk->sk_family)
6216299ee123SJason Gunthorpe 			      ->addr_to_user(sctp_sk(sk), &temp);
6217299ee123SJason Gunthorpe 
621829303547SVlad Yasevich 		if (space_left < addrlen) {
621929303547SVlad Yasevich 			cnt =  -ENOMEM;
622029303547SVlad Yasevich 			break;
622129303547SVlad Yasevich 		}
6222aad97f38SVlad Yasevich 		memcpy(to, &temp, addrlen);
622329c7cf96SSridhar Samudrala 
6224aad97f38SVlad Yasevich 		to += addrlen;
62255fe467eeSIvan Skytte Jørgensen 		cnt++;
62265fe467eeSIvan Skytte Jørgensen 		space_left -= addrlen;
62273663c306SVlad Yasevich 		*bytes_copied += addrlen;
62285fe467eeSIvan Skytte Jørgensen 	}
622929303547SVlad Yasevich 	rcu_read_unlock();
62305fe467eeSIvan Skytte Jørgensen 
62315fe467eeSIvan Skytte Jørgensen 	return cnt;
62325fe467eeSIvan Skytte Jørgensen }
62335fe467eeSIvan Skytte Jørgensen 
62341da177e4SLinus Torvalds 
sctp_getsockopt_local_addrs(struct sock * sk,int len,char __user * optval,int __user * optlen)62355fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
62365fe467eeSIvan Skytte Jørgensen 				       char __user *optval, int __user *optlen)
62375fe467eeSIvan Skytte Jørgensen {
62385fe467eeSIvan Skytte Jørgensen 	struct sctp_bind_addr *bp;
62395fe467eeSIvan Skytte Jørgensen 	struct sctp_association *asoc;
62405fe467eeSIvan Skytte Jørgensen 	int cnt = 0;
62415fe467eeSIvan Skytte Jørgensen 	struct sctp_getaddrs getaddrs;
62425fe467eeSIvan Skytte Jørgensen 	struct sctp_sockaddr_entry *addr;
62435fe467eeSIvan Skytte Jørgensen 	void __user *to;
62445fe467eeSIvan Skytte Jørgensen 	union sctp_addr temp;
62455fe467eeSIvan Skytte Jørgensen 	struct sctp_sock *sp = sctp_sk(sk);
62465fe467eeSIvan Skytte Jørgensen 	int addrlen;
62475fe467eeSIvan Skytte Jørgensen 	int err = 0;
62485fe467eeSIvan Skytte Jørgensen 	size_t space_left;
6249aad97f38SVlad Yasevich 	int bytes_copied = 0;
6250aad97f38SVlad Yasevich 	void *addrs;
625170b57b81SVlad Yasevich 	void *buf;
62525fe467eeSIvan Skytte Jørgensen 
6253408f22e8SNeil Horman 	if (len < sizeof(struct sctp_getaddrs))
62545fe467eeSIvan Skytte Jørgensen 		return -EINVAL;
62555fe467eeSIvan Skytte Jørgensen 
62565fe467eeSIvan Skytte Jørgensen 	if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
62575fe467eeSIvan Skytte Jørgensen 		return -EFAULT;
62585fe467eeSIvan Skytte Jørgensen 
62595fe467eeSIvan Skytte Jørgensen 	/*
62605fe467eeSIvan Skytte Jørgensen 	 *  For UDP-style sockets, id specifies the association to query.
62615fe467eeSIvan Skytte Jørgensen 	 *  If the id field is set to the value '0' then the locally bound
62625fe467eeSIvan Skytte Jørgensen 	 *  addresses are returned without regard to any particular
62635fe467eeSIvan Skytte Jørgensen 	 *  association.
62645fe467eeSIvan Skytte Jørgensen 	 */
62655fe467eeSIvan Skytte Jørgensen 	if (0 == getaddrs.assoc_id) {
62665fe467eeSIvan Skytte Jørgensen 		bp = &sctp_sk(sk)->ep->base.bind_addr;
62675fe467eeSIvan Skytte Jørgensen 	} else {
62685fe467eeSIvan Skytte Jørgensen 		asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
62695fe467eeSIvan Skytte Jørgensen 		if (!asoc)
62705fe467eeSIvan Skytte Jørgensen 			return -EINVAL;
62715fe467eeSIvan Skytte Jørgensen 		bp = &asoc->base.bind_addr;
62725fe467eeSIvan Skytte Jørgensen 	}
62735fe467eeSIvan Skytte Jørgensen 
62745fe467eeSIvan Skytte Jørgensen 	to = optval + offsetof(struct sctp_getaddrs, addrs);
6275186e2343SNeil Horman 	space_left = len - offsetof(struct sctp_getaddrs, addrs);
6276186e2343SNeil Horman 
6277cacc0621SMarcelo Ricardo Leitner 	addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN);
6278aad97f38SVlad Yasevich 	if (!addrs)
6279aad97f38SVlad Yasevich 		return -ENOMEM;
62805fe467eeSIvan Skytte Jørgensen 
62815fe467eeSIvan Skytte Jørgensen 	/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
62825fe467eeSIvan Skytte Jørgensen 	 * addresses from the global local address list.
62835fe467eeSIvan Skytte Jørgensen 	 */
62845fe467eeSIvan Skytte Jørgensen 	if (sctp_list_single_entry(&bp->address_list)) {
62855fe467eeSIvan Skytte Jørgensen 		addr = list_entry(bp->address_list.next,
62865fe467eeSIvan Skytte Jørgensen 				  struct sctp_sockaddr_entry, list);
628752cae8f0SVlad Yasevich 		if (sctp_is_any(sk, &addr->a)) {
6288aad97f38SVlad Yasevich 			cnt = sctp_copy_laddrs(sk, bp->port, addrs,
6289aad97f38SVlad Yasevich 						space_left, &bytes_copied);
62905fe467eeSIvan Skytte Jørgensen 			if (cnt < 0) {
62915fe467eeSIvan Skytte Jørgensen 				err = cnt;
6292559cf710SVlad Yasevich 				goto out;
62935fe467eeSIvan Skytte Jørgensen 			}
62945fe467eeSIvan Skytte Jørgensen 			goto copy_getaddrs;
62955fe467eeSIvan Skytte Jørgensen 		}
62965fe467eeSIvan Skytte Jørgensen 	}
62975fe467eeSIvan Skytte Jørgensen 
629870b57b81SVlad Yasevich 	buf = addrs;
6299559cf710SVlad Yasevich 	/* Protection on the bound address list is not needed since
6300559cf710SVlad Yasevich 	 * in the socket option context we hold a socket lock and
6301559cf710SVlad Yasevich 	 * thus the bound address list can't change.
6302559cf710SVlad Yasevich 	 */
6303559cf710SVlad Yasevich 	list_for_each_entry(addr, &bp->address_list, list) {
63046244be4eSAl Viro 		memcpy(&temp, &addr->a, sizeof(temp));
6305299ee123SJason Gunthorpe 		addrlen = sctp_get_pf_specific(sk->sk_family)
6306299ee123SJason Gunthorpe 			      ->addr_to_user(sp, &temp);
6307aad97f38SVlad Yasevich 		if (space_left < addrlen) {
6308aad97f38SVlad Yasevich 			err =  -ENOMEM; /*fixme: right error?*/
6309559cf710SVlad Yasevich 			goto out;
63105fe467eeSIvan Skytte Jørgensen 		}
631170b57b81SVlad Yasevich 		memcpy(buf, &temp, addrlen);
631270b57b81SVlad Yasevich 		buf += addrlen;
6313aad97f38SVlad Yasevich 		bytes_copied += addrlen;
63145fe467eeSIvan Skytte Jørgensen 		cnt++;
63155fe467eeSIvan Skytte Jørgensen 		space_left -= addrlen;
63165fe467eeSIvan Skytte Jørgensen 	}
63175fe467eeSIvan Skytte Jørgensen 
63185fe467eeSIvan Skytte Jørgensen copy_getaddrs:
6319aad97f38SVlad Yasevich 	if (copy_to_user(to, addrs, bytes_copied)) {
6320aad97f38SVlad Yasevich 		err = -EFAULT;
6321d6f9fdafSSebastian Siewior 		goto out;
6322aad97f38SVlad Yasevich 	}
6323fe979ac1SVlad Yasevich 	if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) {
6324fe979ac1SVlad Yasevich 		err = -EFAULT;
6325d6f9fdafSSebastian Siewior 		goto out;
6326fe979ac1SVlad Yasevich 	}
6327c76f97c9SMarcelo Ricardo Leitner 	/* XXX: We should have accounted for sizeof(struct sctp_getaddrs) too,
6328c76f97c9SMarcelo Ricardo Leitner 	 * but we can't change it anymore.
6329c76f97c9SMarcelo Ricardo Leitner 	 */
63305fe467eeSIvan Skytte Jørgensen 	if (put_user(bytes_copied, optlen))
6331fe979ac1SVlad Yasevich 		err = -EFAULT;
6332d6f9fdafSSebastian Siewior out:
6333aad97f38SVlad Yasevich 	kfree(addrs);
63345fe467eeSIvan Skytte Jørgensen 	return err;
63355fe467eeSIvan Skytte Jørgensen }
63365fe467eeSIvan Skytte Jørgensen 
63371da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
63381da177e4SLinus Torvalds  *
63391da177e4SLinus Torvalds  * Requests that the local SCTP stack use the enclosed peer address as
63401da177e4SLinus Torvalds  * the association primary.  The enclosed address must be one of the
63411da177e4SLinus Torvalds  * association peer's addresses.
63421da177e4SLinus Torvalds  */
sctp_getsockopt_primary_addr(struct sock * sk,int len,char __user * optval,int __user * optlen)63431da177e4SLinus Torvalds static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
63441da177e4SLinus Torvalds 					char __user *optval, int __user *optlen)
63451da177e4SLinus Torvalds {
63461da177e4SLinus Torvalds 	struct sctp_prim prim;
63471da177e4SLinus Torvalds 	struct sctp_association *asoc;
63481da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
63491da177e4SLinus Torvalds 
6350408f22e8SNeil Horman 	if (len < sizeof(struct sctp_prim))
63511da177e4SLinus Torvalds 		return -EINVAL;
63521da177e4SLinus Torvalds 
6353408f22e8SNeil Horman 	len = sizeof(struct sctp_prim);
6354408f22e8SNeil Horman 
6355408f22e8SNeil Horman 	if (copy_from_user(&prim, optval, len))
63561da177e4SLinus Torvalds 		return -EFAULT;
63571da177e4SLinus Torvalds 
63581da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, prim.ssp_assoc_id);
63591da177e4SLinus Torvalds 	if (!asoc)
63601da177e4SLinus Torvalds 		return -EINVAL;
63611da177e4SLinus Torvalds 
63621da177e4SLinus Torvalds 	if (!asoc->peer.primary_path)
63631da177e4SLinus Torvalds 		return -ENOTCONN;
63641da177e4SLinus Torvalds 
63658cec6b80SAl Viro 	memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr,
63668cec6b80SAl Viro 		asoc->peer.primary_path->af_specific->sockaddr_len);
63671da177e4SLinus Torvalds 
6368299ee123SJason Gunthorpe 	sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp,
63691da177e4SLinus Torvalds 			(union sctp_addr *)&prim.ssp_addr);
63701da177e4SLinus Torvalds 
6371408f22e8SNeil Horman 	if (put_user(len, optlen))
6372408f22e8SNeil Horman 		return -EFAULT;
6373408f22e8SNeil Horman 	if (copy_to_user(optval, &prim, len))
63741da177e4SLinus Torvalds 		return -EFAULT;
63751da177e4SLinus Torvalds 
63761da177e4SLinus Torvalds 	return 0;
63771da177e4SLinus Torvalds }
63781da177e4SLinus Torvalds 
63791da177e4SLinus Torvalds /*
63800f3fffd8SIvan Skytte Jorgensen  * 7.1.11  Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER)
63811da177e4SLinus Torvalds  *
63820f3fffd8SIvan Skytte Jorgensen  * Requests that the local endpoint set the specified Adaptation Layer
63831da177e4SLinus Torvalds  * Indication parameter for all future INIT and INIT-ACK exchanges.
63841da177e4SLinus Torvalds  */
sctp_getsockopt_adaptation_layer(struct sock * sk,int len,char __user * optval,int __user * optlen)63850f3fffd8SIvan Skytte Jorgensen static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
63861da177e4SLinus Torvalds 				  char __user *optval, int __user *optlen)
63871da177e4SLinus Torvalds {
63880f3fffd8SIvan Skytte Jorgensen 	struct sctp_setadaptation adaptation;
63891da177e4SLinus Torvalds 
6390408f22e8SNeil Horman 	if (len < sizeof(struct sctp_setadaptation))
63911da177e4SLinus Torvalds 		return -EINVAL;
63921da177e4SLinus Torvalds 
6393408f22e8SNeil Horman 	len = sizeof(struct sctp_setadaptation);
6394408f22e8SNeil Horman 
63950f3fffd8SIvan Skytte Jorgensen 	adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind;
6396408f22e8SNeil Horman 
6397408f22e8SNeil Horman 	if (put_user(len, optlen))
6398408f22e8SNeil Horman 		return -EFAULT;
63990f3fffd8SIvan Skytte Jorgensen 	if (copy_to_user(optval, &adaptation, len))
64001da177e4SLinus Torvalds 		return -EFAULT;
6401a1ab3582SIvan Skytte Jorgensen 
64021da177e4SLinus Torvalds 	return 0;
64031da177e4SLinus Torvalds }
64041da177e4SLinus Torvalds 
64051da177e4SLinus Torvalds /*
64061da177e4SLinus Torvalds  *
64071da177e4SLinus Torvalds  * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM)
64081da177e4SLinus Torvalds  *
64091da177e4SLinus Torvalds  *   Applications that wish to use the sendto() system call may wish to
64101da177e4SLinus Torvalds  *   specify a default set of parameters that would normally be supplied
64111da177e4SLinus Torvalds  *   through the inclusion of ancillary data.  This socket option allows
64121da177e4SLinus Torvalds  *   such an application to set the default sctp_sndrcvinfo structure.
64131da177e4SLinus Torvalds 
64141da177e4SLinus Torvalds 
64151da177e4SLinus Torvalds  *   The application that wishes to use this socket option simply passes
64161da177e4SLinus Torvalds  *   in to this call the sctp_sndrcvinfo structure defined in Section
64171da177e4SLinus Torvalds  *   5.2.2) The input parameters accepted by this call include
64181da177e4SLinus Torvalds  *   sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
64191da177e4SLinus Torvalds  *   sinfo_timetolive.  The user must provide the sinfo_assoc_id field in
64201da177e4SLinus Torvalds  *   to this call if the caller is using the UDP model.
64211da177e4SLinus Torvalds  *
64221da177e4SLinus Torvalds  *   For getsockopt, it get the default sctp_sndrcvinfo structure.
64231da177e4SLinus Torvalds  */
sctp_getsockopt_default_send_param(struct sock * sk,int len,char __user * optval,int __user * optlen)64241da177e4SLinus Torvalds static int sctp_getsockopt_default_send_param(struct sock *sk,
64251da177e4SLinus Torvalds 					int len, char __user *optval,
64261da177e4SLinus Torvalds 					int __user *optlen)
64271da177e4SLinus Torvalds {
64281da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
64296b3fd5f3SGeir Ola Vaagland 	struct sctp_association *asoc;
64306b3fd5f3SGeir Ola Vaagland 	struct sctp_sndrcvinfo info;
64311da177e4SLinus Torvalds 
64326b3fd5f3SGeir Ola Vaagland 	if (len < sizeof(info))
64331da177e4SLinus Torvalds 		return -EINVAL;
6434408f22e8SNeil Horman 
64356b3fd5f3SGeir Ola Vaagland 	len = sizeof(info);
6436408f22e8SNeil Horman 
6437408f22e8SNeil Horman 	if (copy_from_user(&info, optval, len))
64381da177e4SLinus Torvalds 		return -EFAULT;
64391da177e4SLinus Torvalds 
64401da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
6441707e45b3SXin Long 	if (!asoc && info.sinfo_assoc_id != SCTP_FUTURE_ASSOC &&
6442707e45b3SXin Long 	    sctp_style(sk, UDP))
64431da177e4SLinus Torvalds 		return -EINVAL;
6444707e45b3SXin Long 
64451da177e4SLinus Torvalds 	if (asoc) {
64461da177e4SLinus Torvalds 		info.sinfo_stream = asoc->default_stream;
64471da177e4SLinus Torvalds 		info.sinfo_flags = asoc->default_flags;
64481da177e4SLinus Torvalds 		info.sinfo_ppid = asoc->default_ppid;
64491da177e4SLinus Torvalds 		info.sinfo_context = asoc->default_context;
64501da177e4SLinus Torvalds 		info.sinfo_timetolive = asoc->default_timetolive;
64511da177e4SLinus Torvalds 	} else {
64521da177e4SLinus Torvalds 		info.sinfo_stream = sp->default_stream;
64531da177e4SLinus Torvalds 		info.sinfo_flags = sp->default_flags;
64541da177e4SLinus Torvalds 		info.sinfo_ppid = sp->default_ppid;
64551da177e4SLinus Torvalds 		info.sinfo_context = sp->default_context;
64561da177e4SLinus Torvalds 		info.sinfo_timetolive = sp->default_timetolive;
64571da177e4SLinus Torvalds 	}
64581da177e4SLinus Torvalds 
6459408f22e8SNeil Horman 	if (put_user(len, optlen))
6460408f22e8SNeil Horman 		return -EFAULT;
6461408f22e8SNeil Horman 	if (copy_to_user(optval, &info, len))
64621da177e4SLinus Torvalds 		return -EFAULT;
64631da177e4SLinus Torvalds 
64641da177e4SLinus Torvalds 	return 0;
64651da177e4SLinus Torvalds }
64661da177e4SLinus Torvalds 
64676b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters
64686b3fd5f3SGeir Ola Vaagland  * (SCTP_DEFAULT_SNDINFO)
64696b3fd5f3SGeir Ola Vaagland  */
sctp_getsockopt_default_sndinfo(struct sock * sk,int len,char __user * optval,int __user * optlen)64706b3fd5f3SGeir Ola Vaagland static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len,
64716b3fd5f3SGeir Ola Vaagland 					   char __user *optval,
64726b3fd5f3SGeir Ola Vaagland 					   int __user *optlen)
64736b3fd5f3SGeir Ola Vaagland {
64746b3fd5f3SGeir Ola Vaagland 	struct sctp_sock *sp = sctp_sk(sk);
64756b3fd5f3SGeir Ola Vaagland 	struct sctp_association *asoc;
64766b3fd5f3SGeir Ola Vaagland 	struct sctp_sndinfo info;
64776b3fd5f3SGeir Ola Vaagland 
64786b3fd5f3SGeir Ola Vaagland 	if (len < sizeof(info))
64796b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
64806b3fd5f3SGeir Ola Vaagland 
64816b3fd5f3SGeir Ola Vaagland 	len = sizeof(info);
64826b3fd5f3SGeir Ola Vaagland 
64836b3fd5f3SGeir Ola Vaagland 	if (copy_from_user(&info, optval, len))
64846b3fd5f3SGeir Ola Vaagland 		return -EFAULT;
64856b3fd5f3SGeir Ola Vaagland 
64866b3fd5f3SGeir Ola Vaagland 	asoc = sctp_id2assoc(sk, info.snd_assoc_id);
648792fc3bd9SXin Long 	if (!asoc && info.snd_assoc_id != SCTP_FUTURE_ASSOC &&
648892fc3bd9SXin Long 	    sctp_style(sk, UDP))
64896b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
649092fc3bd9SXin Long 
64916b3fd5f3SGeir Ola Vaagland 	if (asoc) {
64926b3fd5f3SGeir Ola Vaagland 		info.snd_sid = asoc->default_stream;
64936b3fd5f3SGeir Ola Vaagland 		info.snd_flags = asoc->default_flags;
64946b3fd5f3SGeir Ola Vaagland 		info.snd_ppid = asoc->default_ppid;
64956b3fd5f3SGeir Ola Vaagland 		info.snd_context = asoc->default_context;
64966b3fd5f3SGeir Ola Vaagland 	} else {
64976b3fd5f3SGeir Ola Vaagland 		info.snd_sid = sp->default_stream;
64986b3fd5f3SGeir Ola Vaagland 		info.snd_flags = sp->default_flags;
64996b3fd5f3SGeir Ola Vaagland 		info.snd_ppid = sp->default_ppid;
65006b3fd5f3SGeir Ola Vaagland 		info.snd_context = sp->default_context;
65016b3fd5f3SGeir Ola Vaagland 	}
65026b3fd5f3SGeir Ola Vaagland 
65036b3fd5f3SGeir Ola Vaagland 	if (put_user(len, optlen))
65046b3fd5f3SGeir Ola Vaagland 		return -EFAULT;
65056b3fd5f3SGeir Ola Vaagland 	if (copy_to_user(optval, &info, len))
65066b3fd5f3SGeir Ola Vaagland 		return -EFAULT;
65076b3fd5f3SGeir Ola Vaagland 
65086b3fd5f3SGeir Ola Vaagland 	return 0;
65096b3fd5f3SGeir Ola Vaagland }
65106b3fd5f3SGeir Ola Vaagland 
65111da177e4SLinus Torvalds /*
65121da177e4SLinus Torvalds  *
65131da177e4SLinus Torvalds  * 7.1.5 SCTP_NODELAY
65141da177e4SLinus Torvalds  *
65151da177e4SLinus Torvalds  * Turn on/off any Nagle-like algorithm.  This means that packets are
65161da177e4SLinus Torvalds  * generally sent as soon as possible and no unnecessary delays are
65171da177e4SLinus Torvalds  * introduced, at the cost of more packets in the network.  Expects an
65181da177e4SLinus Torvalds  * integer boolean flag.
65191da177e4SLinus Torvalds  */
65201da177e4SLinus Torvalds 
sctp_getsockopt_nodelay(struct sock * sk,int len,char __user * optval,int __user * optlen)65211da177e4SLinus Torvalds static int sctp_getsockopt_nodelay(struct sock *sk, int len,
65221da177e4SLinus Torvalds 				   char __user *optval, int __user *optlen)
65231da177e4SLinus Torvalds {
65241da177e4SLinus Torvalds 	int val;
65251da177e4SLinus Torvalds 
65261da177e4SLinus Torvalds 	if (len < sizeof(int))
65271da177e4SLinus Torvalds 		return -EINVAL;
65281da177e4SLinus Torvalds 
65291da177e4SLinus Torvalds 	len = sizeof(int);
65301da177e4SLinus Torvalds 	val = (sctp_sk(sk)->nodelay == 1);
65311da177e4SLinus Torvalds 	if (put_user(len, optlen))
65321da177e4SLinus Torvalds 		return -EFAULT;
65331da177e4SLinus Torvalds 	if (copy_to_user(optval, &val, len))
65341da177e4SLinus Torvalds 		return -EFAULT;
65351da177e4SLinus Torvalds 	return 0;
65361da177e4SLinus Torvalds }
65371da177e4SLinus Torvalds 
65381da177e4SLinus Torvalds /*
65391da177e4SLinus Torvalds  *
65401da177e4SLinus Torvalds  * 7.1.1 SCTP_RTOINFO
65411da177e4SLinus Torvalds  *
65421da177e4SLinus Torvalds  * The protocol parameters used to initialize and bound retransmission
65431da177e4SLinus Torvalds  * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access
65441da177e4SLinus Torvalds  * and modify these parameters.
65451da177e4SLinus Torvalds  * All parameters are time values, in milliseconds.  A value of 0, when
65461da177e4SLinus Torvalds  * modifying the parameters, indicates that the current value should not
65471da177e4SLinus Torvalds  * be changed.
65481da177e4SLinus Torvalds  *
65491da177e4SLinus Torvalds  */
sctp_getsockopt_rtoinfo(struct sock * sk,int len,char __user * optval,int __user * optlen)65501da177e4SLinus Torvalds static int sctp_getsockopt_rtoinfo(struct sock *sk, int len,
65511da177e4SLinus Torvalds 				char __user *optval,
65521da177e4SLinus Torvalds 				int __user *optlen) {
65531da177e4SLinus Torvalds 	struct sctp_rtoinfo rtoinfo;
65541da177e4SLinus Torvalds 	struct sctp_association *asoc;
65551da177e4SLinus Torvalds 
6556408f22e8SNeil Horman 	if (len < sizeof (struct sctp_rtoinfo))
65571da177e4SLinus Torvalds 		return -EINVAL;
65581da177e4SLinus Torvalds 
6559408f22e8SNeil Horman 	len = sizeof(struct sctp_rtoinfo);
6560408f22e8SNeil Horman 
6561408f22e8SNeil Horman 	if (copy_from_user(&rtoinfo, optval, len))
65621da177e4SLinus Torvalds 		return -EFAULT;
65631da177e4SLinus Torvalds 
65641da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id);
65651da177e4SLinus Torvalds 
65667adb5ed5SXin Long 	if (!asoc && rtoinfo.srto_assoc_id != SCTP_FUTURE_ASSOC &&
65677adb5ed5SXin Long 	    sctp_style(sk, UDP))
65681da177e4SLinus Torvalds 		return -EINVAL;
65691da177e4SLinus Torvalds 
65701da177e4SLinus Torvalds 	/* Values corresponding to the specific association. */
65711da177e4SLinus Torvalds 	if (asoc) {
65721da177e4SLinus Torvalds 		rtoinfo.srto_initial = jiffies_to_msecs(asoc->rto_initial);
65731da177e4SLinus Torvalds 		rtoinfo.srto_max = jiffies_to_msecs(asoc->rto_max);
65741da177e4SLinus Torvalds 		rtoinfo.srto_min = jiffies_to_msecs(asoc->rto_min);
65751da177e4SLinus Torvalds 	} else {
65761da177e4SLinus Torvalds 		/* Values corresponding to the endpoint. */
65771da177e4SLinus Torvalds 		struct sctp_sock *sp = sctp_sk(sk);
65781da177e4SLinus Torvalds 
65791da177e4SLinus Torvalds 		rtoinfo.srto_initial = sp->rtoinfo.srto_initial;
65801da177e4SLinus Torvalds 		rtoinfo.srto_max = sp->rtoinfo.srto_max;
65811da177e4SLinus Torvalds 		rtoinfo.srto_min = sp->rtoinfo.srto_min;
65821da177e4SLinus Torvalds 	}
65831da177e4SLinus Torvalds 
65841da177e4SLinus Torvalds 	if (put_user(len, optlen))
65851da177e4SLinus Torvalds 		return -EFAULT;
65861da177e4SLinus Torvalds 
65871da177e4SLinus Torvalds 	if (copy_to_user(optval, &rtoinfo, len))
65881da177e4SLinus Torvalds 		return -EFAULT;
65891da177e4SLinus Torvalds 
65901da177e4SLinus Torvalds 	return 0;
65911da177e4SLinus Torvalds }
65921da177e4SLinus Torvalds 
65931da177e4SLinus Torvalds /*
65941da177e4SLinus Torvalds  *
65951da177e4SLinus Torvalds  * 7.1.2 SCTP_ASSOCINFO
65961da177e4SLinus Torvalds  *
659759c51591SMichael Opdenacker  * This option is used to tune the maximum retransmission attempts
65981da177e4SLinus Torvalds  * of the association.
65991da177e4SLinus Torvalds  * Returns an error if the new association retransmission value is
66001da177e4SLinus Torvalds  * greater than the sum of the retransmission value  of the peer.
66011da177e4SLinus Torvalds  * See [SCTP] for more information.
66021da177e4SLinus Torvalds  *
66031da177e4SLinus Torvalds  */
sctp_getsockopt_associnfo(struct sock * sk,int len,char __user * optval,int __user * optlen)66041da177e4SLinus Torvalds static int sctp_getsockopt_associnfo(struct sock *sk, int len,
66051da177e4SLinus Torvalds 				     char __user *optval,
66061da177e4SLinus Torvalds 				     int __user *optlen)
66071da177e4SLinus Torvalds {
66081da177e4SLinus Torvalds 
66091da177e4SLinus Torvalds 	struct sctp_assocparams assocparams;
66101da177e4SLinus Torvalds 	struct sctp_association *asoc;
66111da177e4SLinus Torvalds 	struct list_head *pos;
66121da177e4SLinus Torvalds 	int cnt = 0;
66131da177e4SLinus Torvalds 
6614408f22e8SNeil Horman 	if (len < sizeof (struct sctp_assocparams))
66151da177e4SLinus Torvalds 		return -EINVAL;
66161da177e4SLinus Torvalds 
6617408f22e8SNeil Horman 	len = sizeof(struct sctp_assocparams);
6618408f22e8SNeil Horman 
6619408f22e8SNeil Horman 	if (copy_from_user(&assocparams, optval, len))
66201da177e4SLinus Torvalds 		return -EFAULT;
66211da177e4SLinus Torvalds 
66221da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id);
66231da177e4SLinus Torvalds 
66248889394dSXin Long 	if (!asoc && assocparams.sasoc_assoc_id != SCTP_FUTURE_ASSOC &&
66258889394dSXin Long 	    sctp_style(sk, UDP))
66261da177e4SLinus Torvalds 		return -EINVAL;
66271da177e4SLinus Torvalds 
66281da177e4SLinus Torvalds 	/* Values correspoinding to the specific association */
662917337216SVladislav Yasevich 	if (asoc) {
66301da177e4SLinus Torvalds 		assocparams.sasoc_asocmaxrxt = asoc->max_retrans;
66311da177e4SLinus Torvalds 		assocparams.sasoc_peer_rwnd = asoc->peer.rwnd;
66321da177e4SLinus Torvalds 		assocparams.sasoc_local_rwnd = asoc->a_rwnd;
663352db882fSDaniel Borkmann 		assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life);
66341da177e4SLinus Torvalds 
66351da177e4SLinus Torvalds 		list_for_each(pos, &asoc->peer.transport_addr_list) {
66361da177e4SLinus Torvalds 			cnt++;
66371da177e4SLinus Torvalds 		}
66381da177e4SLinus Torvalds 
66391da177e4SLinus Torvalds 		assocparams.sasoc_number_peer_destinations = cnt;
66401da177e4SLinus Torvalds 	} else {
66411da177e4SLinus Torvalds 		/* Values corresponding to the endpoint */
66421da177e4SLinus Torvalds 		struct sctp_sock *sp = sctp_sk(sk);
66431da177e4SLinus Torvalds 
66441da177e4SLinus Torvalds 		assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt;
66451da177e4SLinus Torvalds 		assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd;
66461da177e4SLinus Torvalds 		assocparams.sasoc_local_rwnd = sp->assocparams.sasoc_local_rwnd;
66471da177e4SLinus Torvalds 		assocparams.sasoc_cookie_life =
66481da177e4SLinus Torvalds 					sp->assocparams.sasoc_cookie_life;
66491da177e4SLinus Torvalds 		assocparams.sasoc_number_peer_destinations =
66501da177e4SLinus Torvalds 					sp->assocparams.
66511da177e4SLinus Torvalds 					sasoc_number_peer_destinations;
66521da177e4SLinus Torvalds 	}
66531da177e4SLinus Torvalds 
66541da177e4SLinus Torvalds 	if (put_user(len, optlen))
66551da177e4SLinus Torvalds 		return -EFAULT;
66561da177e4SLinus Torvalds 
66571da177e4SLinus Torvalds 	if (copy_to_user(optval, &assocparams, len))
66581da177e4SLinus Torvalds 		return -EFAULT;
66591da177e4SLinus Torvalds 
66601da177e4SLinus Torvalds 	return 0;
66611da177e4SLinus Torvalds }
66621da177e4SLinus Torvalds 
66631da177e4SLinus Torvalds /*
66641da177e4SLinus Torvalds  * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
66651da177e4SLinus Torvalds  *
66661da177e4SLinus Torvalds  * This socket option is a boolean flag which turns on or off mapped V4
66671da177e4SLinus Torvalds  * addresses.  If this option is turned on and the socket is type
66681da177e4SLinus Torvalds  * PF_INET6, then IPv4 addresses will be mapped to V6 representation.
66691da177e4SLinus Torvalds  * If this option is turned off, then no mapping will be done of V4
66701da177e4SLinus Torvalds  * addresses and a user will receive both PF_INET6 and PF_INET type
66711da177e4SLinus Torvalds  * addresses on the socket.
66721da177e4SLinus Torvalds  */
sctp_getsockopt_mappedv4(struct sock * sk,int len,char __user * optval,int __user * optlen)66731da177e4SLinus Torvalds static int sctp_getsockopt_mappedv4(struct sock *sk, int len,
66741da177e4SLinus Torvalds 				    char __user *optval, int __user *optlen)
66751da177e4SLinus Torvalds {
66761da177e4SLinus Torvalds 	int val;
66771da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
66781da177e4SLinus Torvalds 
66791da177e4SLinus Torvalds 	if (len < sizeof(int))
66801da177e4SLinus Torvalds 		return -EINVAL;
66811da177e4SLinus Torvalds 
66821da177e4SLinus Torvalds 	len = sizeof(int);
66831da177e4SLinus Torvalds 	val = sp->v4mapped;
66841da177e4SLinus Torvalds 	if (put_user(len, optlen))
66851da177e4SLinus Torvalds 		return -EFAULT;
66861da177e4SLinus Torvalds 	if (copy_to_user(optval, &val, len))
66871da177e4SLinus Torvalds 		return -EFAULT;
66881da177e4SLinus Torvalds 
66891da177e4SLinus Torvalds 	return 0;
66901da177e4SLinus Torvalds }
66911da177e4SLinus Torvalds 
66921da177e4SLinus Torvalds /*
66936ab792f5SIvan Skytte Jorgensen  * 7.1.29.  Set or Get the default context (SCTP_CONTEXT)
66946ab792f5SIvan Skytte Jorgensen  * (chapter and verse is quoted at sctp_setsockopt_context())
66956ab792f5SIvan Skytte Jorgensen  */
sctp_getsockopt_context(struct sock * sk,int len,char __user * optval,int __user * optlen)66966ab792f5SIvan Skytte Jorgensen static int sctp_getsockopt_context(struct sock *sk, int len,
66976ab792f5SIvan Skytte Jorgensen 				   char __user *optval, int __user *optlen)
66986ab792f5SIvan Skytte Jorgensen {
66996ab792f5SIvan Skytte Jorgensen 	struct sctp_assoc_value params;
67006ab792f5SIvan Skytte Jorgensen 	struct sctp_association *asoc;
67016ab792f5SIvan Skytte Jorgensen 
6702408f22e8SNeil Horman 	if (len < sizeof(struct sctp_assoc_value))
67036ab792f5SIvan Skytte Jorgensen 		return -EINVAL;
67046ab792f5SIvan Skytte Jorgensen 
6705408f22e8SNeil Horman 	len = sizeof(struct sctp_assoc_value);
6706408f22e8SNeil Horman 
67076ab792f5SIvan Skytte Jorgensen 	if (copy_from_user(&params, optval, len))
67086ab792f5SIvan Skytte Jorgensen 		return -EFAULT;
67096ab792f5SIvan Skytte Jorgensen 
67106ab792f5SIvan Skytte Jorgensen 	asoc = sctp_id2assoc(sk, params.assoc_id);
671149b037acSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
671249b037acSXin Long 	    sctp_style(sk, UDP))
67136ab792f5SIvan Skytte Jorgensen 		return -EINVAL;
671449b037acSXin Long 
671549b037acSXin Long 	params.assoc_value = asoc ? asoc->default_rcv_context
671649b037acSXin Long 				  : sctp_sk(sk)->default_rcv_context;
67176ab792f5SIvan Skytte Jorgensen 
67186ab792f5SIvan Skytte Jorgensen 	if (put_user(len, optlen))
67196ab792f5SIvan Skytte Jorgensen 		return -EFAULT;
67206ab792f5SIvan Skytte Jorgensen 	if (copy_to_user(optval, &params, len))
67216ab792f5SIvan Skytte Jorgensen 		return -EFAULT;
67226ab792f5SIvan Skytte Jorgensen 
67236ab792f5SIvan Skytte Jorgensen 	return 0;
67246ab792f5SIvan Skytte Jorgensen }
67256ab792f5SIvan Skytte Jorgensen 
67266ab792f5SIvan Skytte Jorgensen /*
6727e89c2095SWei Yongjun  * 8.1.16.  Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
6728e89c2095SWei Yongjun  * This option will get or set the maximum size to put in any outgoing
6729e89c2095SWei Yongjun  * SCTP DATA chunk.  If a message is larger than this size it will be
67301da177e4SLinus Torvalds  * fragmented by SCTP into the specified size.  Note that the underlying
67311da177e4SLinus Torvalds  * SCTP implementation may fragment into smaller sized chunks when the
67321da177e4SLinus Torvalds  * PMTU of the underlying association is smaller than the value set by
6733e89c2095SWei Yongjun  * the user.  The default value for this option is '0' which indicates
6734e89c2095SWei Yongjun  * the user is NOT limiting fragmentation and only the PMTU will effect
6735e89c2095SWei Yongjun  * SCTP's choice of DATA chunk size.  Note also that values set larger
6736e89c2095SWei Yongjun  * than the maximum size of an IP datagram will effectively let SCTP
6737e89c2095SWei Yongjun  * control fragmentation (i.e. the same as setting this option to 0).
6738e89c2095SWei Yongjun  *
6739e89c2095SWei Yongjun  * The following structure is used to access and modify this parameter:
6740e89c2095SWei Yongjun  *
6741e89c2095SWei Yongjun  * struct sctp_assoc_value {
6742e89c2095SWei Yongjun  *   sctp_assoc_t assoc_id;
6743e89c2095SWei Yongjun  *   uint32_t assoc_value;
6744e89c2095SWei Yongjun  * };
6745e89c2095SWei Yongjun  *
6746e89c2095SWei Yongjun  * assoc_id:  This parameter is ignored for one-to-one style sockets.
6747e89c2095SWei Yongjun  *    For one-to-many style sockets this parameter indicates which
6748e89c2095SWei Yongjun  *    association the user is performing an action upon.  Note that if
6749e89c2095SWei Yongjun  *    this field's value is zero then the endpoints default value is
6750e89c2095SWei Yongjun  *    changed (effecting future associations only).
6751e89c2095SWei Yongjun  * assoc_value:  This parameter specifies the maximum size in bytes.
67521da177e4SLinus Torvalds  */
sctp_getsockopt_maxseg(struct sock * sk,int len,char __user * optval,int __user * optlen)67531da177e4SLinus Torvalds static int sctp_getsockopt_maxseg(struct sock *sk, int len,
67541da177e4SLinus Torvalds 				  char __user *optval, int __user *optlen)
67551da177e4SLinus Torvalds {
6756e89c2095SWei Yongjun 	struct sctp_assoc_value params;
6757e89c2095SWei Yongjun 	struct sctp_association *asoc;
67581da177e4SLinus Torvalds 
6759e89c2095SWei Yongjun 	if (len == sizeof(int)) {
676094f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
6761f916ec96SNeil Horman 				    "%s (pid %d) "
676294f65193SNeil Horman 				    "Use of int in maxseg socket option.\n"
6763f916ec96SNeil Horman 				    "Use struct sctp_assoc_value instead\n",
6764f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
67656fd769beSXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
6766e89c2095SWei Yongjun 	} else if (len >= sizeof(struct sctp_assoc_value)) {
6767e89c2095SWei Yongjun 		len = sizeof(struct sctp_assoc_value);
6768c76f97c9SMarcelo Ricardo Leitner 		if (copy_from_user(&params, optval, len))
6769e89c2095SWei Yongjun 			return -EFAULT;
6770e89c2095SWei Yongjun 	} else
67711da177e4SLinus Torvalds 		return -EINVAL;
67721da177e4SLinus Torvalds 
6773e89c2095SWei Yongjun 	asoc = sctp_id2assoc(sk, params.assoc_id);
67746fd769beSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
67756fd769beSXin Long 	    sctp_style(sk, UDP))
6776e89c2095SWei Yongjun 		return -EINVAL;
67771da177e4SLinus Torvalds 
6778e89c2095SWei Yongjun 	if (asoc)
6779e89c2095SWei Yongjun 		params.assoc_value = asoc->frag_point;
6780e89c2095SWei Yongjun 	else
6781e89c2095SWei Yongjun 		params.assoc_value = sctp_sk(sk)->user_frag;
6782e89c2095SWei Yongjun 
67831da177e4SLinus Torvalds 	if (put_user(len, optlen))
67841da177e4SLinus Torvalds 		return -EFAULT;
6785e89c2095SWei Yongjun 	if (len == sizeof(int)) {
6786e89c2095SWei Yongjun 		if (copy_to_user(optval, &params.assoc_value, len))
67871da177e4SLinus Torvalds 			return -EFAULT;
6788e89c2095SWei Yongjun 	} else {
6789e89c2095SWei Yongjun 		if (copy_to_user(optval, &params, len))
6790e89c2095SWei Yongjun 			return -EFAULT;
6791e89c2095SWei Yongjun 	}
67921da177e4SLinus Torvalds 
67931da177e4SLinus Torvalds 	return 0;
67941da177e4SLinus Torvalds }
67951da177e4SLinus Torvalds 
6796b6e1331fSVlad Yasevich /*
6797b6e1331fSVlad Yasevich  * 7.1.24.  Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE)
6798b6e1331fSVlad Yasevich  * (chapter and verse is quoted at sctp_setsockopt_fragment_interleave())
6799b6e1331fSVlad Yasevich  */
sctp_getsockopt_fragment_interleave(struct sock * sk,int len,char __user * optval,int __user * optlen)6800b6e1331fSVlad Yasevich static int sctp_getsockopt_fragment_interleave(struct sock *sk, int len,
6801b6e1331fSVlad Yasevich 					       char __user *optval, int __user *optlen)
6802b6e1331fSVlad Yasevich {
6803b6e1331fSVlad Yasevich 	int val;
6804b6e1331fSVlad Yasevich 
6805b6e1331fSVlad Yasevich 	if (len < sizeof(int))
6806b6e1331fSVlad Yasevich 		return -EINVAL;
6807b6e1331fSVlad Yasevich 
6808b6e1331fSVlad Yasevich 	len = sizeof(int);
6809b6e1331fSVlad Yasevich 
6810b6e1331fSVlad Yasevich 	val = sctp_sk(sk)->frag_interleave;
6811b6e1331fSVlad Yasevich 	if (put_user(len, optlen))
6812b6e1331fSVlad Yasevich 		return -EFAULT;
6813b6e1331fSVlad Yasevich 	if (copy_to_user(optval, &val, len))
6814b6e1331fSVlad Yasevich 		return -EFAULT;
6815b6e1331fSVlad Yasevich 
6816b6e1331fSVlad Yasevich 	return 0;
6817b6e1331fSVlad Yasevich }
6818b6e1331fSVlad Yasevich 
6819d49d91d7SVlad Yasevich /*
6820d49d91d7SVlad Yasevich  * 7.1.25.  Set or Get the sctp partial delivery point
6821d49d91d7SVlad Yasevich  * (chapter and verse is quoted at sctp_setsockopt_partial_delivery_point())
6822d49d91d7SVlad Yasevich  */
sctp_getsockopt_partial_delivery_point(struct sock * sk,int len,char __user * optval,int __user * optlen)6823d49d91d7SVlad Yasevich static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len,
6824d49d91d7SVlad Yasevich 						  char __user *optval,
6825d49d91d7SVlad Yasevich 						  int __user *optlen)
6826d49d91d7SVlad Yasevich {
6827d49d91d7SVlad Yasevich 	u32 val;
6828d49d91d7SVlad Yasevich 
6829d49d91d7SVlad Yasevich 	if (len < sizeof(u32))
6830d49d91d7SVlad Yasevich 		return -EINVAL;
6831d49d91d7SVlad Yasevich 
6832d49d91d7SVlad Yasevich 	len = sizeof(u32);
6833d49d91d7SVlad Yasevich 
6834d49d91d7SVlad Yasevich 	val = sctp_sk(sk)->pd_point;
6835d49d91d7SVlad Yasevich 	if (put_user(len, optlen))
6836d49d91d7SVlad Yasevich 		return -EFAULT;
6837d49d91d7SVlad Yasevich 	if (copy_to_user(optval, &val, len))
6838d49d91d7SVlad Yasevich 		return -EFAULT;
6839d49d91d7SVlad Yasevich 
68407d743b7eSWei Yongjun 	return 0;
6841d49d91d7SVlad Yasevich }
6842d49d91d7SVlad Yasevich 
684370331571SVlad Yasevich /*
684470331571SVlad Yasevich  * 7.1.28.  Set or Get the maximum burst (SCTP_MAX_BURST)
684570331571SVlad Yasevich  * (chapter and verse is quoted at sctp_setsockopt_maxburst())
684670331571SVlad Yasevich  */
sctp_getsockopt_maxburst(struct sock * sk,int len,char __user * optval,int __user * optlen)684770331571SVlad Yasevich static int sctp_getsockopt_maxburst(struct sock *sk, int len,
684870331571SVlad Yasevich 				    char __user *optval,
684970331571SVlad Yasevich 				    int __user *optlen)
685070331571SVlad Yasevich {
6851219b99a9SNeil Horman 	struct sctp_assoc_value params;
6852219b99a9SNeil Horman 	struct sctp_association *asoc;
685370331571SVlad Yasevich 
6854219b99a9SNeil Horman 	if (len == sizeof(int)) {
685594f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
6856f916ec96SNeil Horman 				    "%s (pid %d) "
685794f65193SNeil Horman 				    "Use of int in max_burst socket option.\n"
6858f916ec96SNeil Horman 				    "Use struct sctp_assoc_value instead\n",
6859f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
6860e0651a0dSXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
6861c6db93a5SWei Yongjun 	} else if (len >= sizeof(struct sctp_assoc_value)) {
6862c6db93a5SWei Yongjun 		len = sizeof(struct sctp_assoc_value);
6863219b99a9SNeil Horman 		if (copy_from_user(&params, optval, len))
686470331571SVlad Yasevich 			return -EFAULT;
6865219b99a9SNeil Horman 	} else
6866219b99a9SNeil Horman 		return -EINVAL;
686770331571SVlad Yasevich 
6868219b99a9SNeil Horman 	asoc = sctp_id2assoc(sk, params.assoc_id);
6869e0651a0dSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
6870e0651a0dSXin Long 	    sctp_style(sk, UDP))
6871219b99a9SNeil Horman 		return -EINVAL;
6872e0651a0dSXin Long 
6873e0651a0dSXin Long 	params.assoc_value = asoc ? asoc->max_burst : sctp_sk(sk)->max_burst;
6874219b99a9SNeil Horman 
6875219b99a9SNeil Horman 	if (len == sizeof(int)) {
6876219b99a9SNeil Horman 		if (copy_to_user(optval, &params.assoc_value, len))
6877219b99a9SNeil Horman 			return -EFAULT;
6878219b99a9SNeil Horman 	} else {
6879219b99a9SNeil Horman 		if (copy_to_user(optval, &params, len))
6880219b99a9SNeil Horman 			return -EFAULT;
6881219b99a9SNeil Horman 	}
6882219b99a9SNeil Horman 
6883219b99a9SNeil Horman 	return 0;
6884219b99a9SNeil Horman 
688570331571SVlad Yasevich }
688670331571SVlad Yasevich 
sctp_getsockopt_hmac_ident(struct sock * sk,int len,char __user * optval,int __user * optlen)688765b07e5dSVlad Yasevich static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
688865b07e5dSVlad Yasevich 				    char __user *optval, int __user *optlen)
688965b07e5dSVlad Yasevich {
6890b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
68915e739d17SVlad Yasevich 	struct sctp_hmacalgo  __user *p = (void __user *)optval;
689265b07e5dSVlad Yasevich 	struct sctp_hmac_algo_param *hmacs;
68935e739d17SVlad Yasevich 	__u16 data_len = 0;
68945e739d17SVlad Yasevich 	u32 num_idents;
68957a84bd46SXin Long 	int i;
68965e739d17SVlad Yasevich 
6897b14878ccSVlad Yasevich 	if (!ep->auth_enable)
68985e739d17SVlad Yasevich 		return -EACCES;
689965b07e5dSVlad Yasevich 
6900b14878ccSVlad Yasevich 	hmacs = ep->auth_hmacs_list;
69013c918704SXin Long 	data_len = ntohs(hmacs->param_hdr.length) -
69023c918704SXin Long 		   sizeof(struct sctp_paramhdr);
690365b07e5dSVlad Yasevich 
69045e739d17SVlad Yasevich 	if (len < sizeof(struct sctp_hmacalgo) + data_len)
690565b07e5dSVlad Yasevich 		return -EINVAL;
69065e739d17SVlad Yasevich 
69075e739d17SVlad Yasevich 	len = sizeof(struct sctp_hmacalgo) + data_len;
69085e739d17SVlad Yasevich 	num_idents = data_len / sizeof(u16);
69095e739d17SVlad Yasevich 
691065b07e5dSVlad Yasevich 	if (put_user(len, optlen))
691165b07e5dSVlad Yasevich 		return -EFAULT;
69125e739d17SVlad Yasevich 	if (put_user(num_idents, &p->shmac_num_idents))
691365b07e5dSVlad Yasevich 		return -EFAULT;
69147a84bd46SXin Long 	for (i = 0; i < num_idents; i++) {
69157a84bd46SXin Long 		__u16 hmacid = ntohs(hmacs->hmac_ids[i]);
69167a84bd46SXin Long 
69177a84bd46SXin Long 		if (copy_to_user(&p->shmac_idents[i], &hmacid, sizeof(__u16)))
69185e739d17SVlad Yasevich 			return -EFAULT;
69197a84bd46SXin Long 	}
692065b07e5dSVlad Yasevich 	return 0;
692165b07e5dSVlad Yasevich }
692265b07e5dSVlad Yasevich 
sctp_getsockopt_active_key(struct sock * sk,int len,char __user * optval,int __user * optlen)692365b07e5dSVlad Yasevich static int sctp_getsockopt_active_key(struct sock *sk, int len,
692465b07e5dSVlad Yasevich 				    char __user *optval, int __user *optlen)
692565b07e5dSVlad Yasevich {
6926b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
692765b07e5dSVlad Yasevich 	struct sctp_authkeyid val;
692865b07e5dSVlad Yasevich 	struct sctp_association *asoc;
692965b07e5dSVlad Yasevich 
693065b07e5dSVlad Yasevich 	if (len < sizeof(struct sctp_authkeyid))
693165b07e5dSVlad Yasevich 		return -EINVAL;
6932c76f97c9SMarcelo Ricardo Leitner 
6933c76f97c9SMarcelo Ricardo Leitner 	len = sizeof(struct sctp_authkeyid);
6934c76f97c9SMarcelo Ricardo Leitner 	if (copy_from_user(&val, optval, len))
693565b07e5dSVlad Yasevich 		return -EFAULT;
693665b07e5dSVlad Yasevich 
693765b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, val.scact_assoc_id);
693865b07e5dSVlad Yasevich 	if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
693965b07e5dSVlad Yasevich 		return -EINVAL;
694065b07e5dSVlad Yasevich 
6941219f9ea4SXin Long 	if (asoc) {
6942219f9ea4SXin Long 		if (!asoc->peer.auth_capable)
6943219f9ea4SXin Long 			return -EACCES;
694465b07e5dSVlad Yasevich 		val.scact_keynumber = asoc->active_key_id;
6945219f9ea4SXin Long 	} else {
6946219f9ea4SXin Long 		if (!ep->auth_enable)
6947219f9ea4SXin Long 			return -EACCES;
6948b14878ccSVlad Yasevich 		val.scact_keynumber = ep->active_key_id;
6949219f9ea4SXin Long 	}
695065b07e5dSVlad Yasevich 
69515e739d17SVlad Yasevich 	if (put_user(len, optlen))
69525e739d17SVlad Yasevich 		return -EFAULT;
69535e739d17SVlad Yasevich 	if (copy_to_user(optval, &val, len))
69545e739d17SVlad Yasevich 		return -EFAULT;
69555e739d17SVlad Yasevich 
695665b07e5dSVlad Yasevich 	return 0;
695765b07e5dSVlad Yasevich }
695865b07e5dSVlad Yasevich 
sctp_getsockopt_peer_auth_chunks(struct sock * sk,int len,char __user * optval,int __user * optlen)695965b07e5dSVlad Yasevich static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
696065b07e5dSVlad Yasevich 				    char __user *optval, int __user *optlen)
696165b07e5dSVlad Yasevich {
6962411223c0SAl Viro 	struct sctp_authchunks __user *p = (void __user *)optval;
696365b07e5dSVlad Yasevich 	struct sctp_authchunks val;
696465b07e5dSVlad Yasevich 	struct sctp_association *asoc;
696565b07e5dSVlad Yasevich 	struct sctp_chunks_param *ch;
69665e739d17SVlad Yasevich 	u32    num_chunks = 0;
696765b07e5dSVlad Yasevich 	char __user *to;
696865b07e5dSVlad Yasevich 
69695e739d17SVlad Yasevich 	if (len < sizeof(struct sctp_authchunks))
697065b07e5dSVlad Yasevich 		return -EINVAL;
697165b07e5dSVlad Yasevich 
6972c76f97c9SMarcelo Ricardo Leitner 	if (copy_from_user(&val, optval, sizeof(val)))
697365b07e5dSVlad Yasevich 		return -EFAULT;
697465b07e5dSVlad Yasevich 
6975411223c0SAl Viro 	to = p->gauth_chunks;
697665b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
697765b07e5dSVlad Yasevich 	if (!asoc)
697865b07e5dSVlad Yasevich 		return -EINVAL;
697965b07e5dSVlad Yasevich 
6980219f9ea4SXin Long 	if (!asoc->peer.auth_capable)
6981219f9ea4SXin Long 		return -EACCES;
6982219f9ea4SXin Long 
698365b07e5dSVlad Yasevich 	ch = asoc->peer.peer_chunks;
69845e739d17SVlad Yasevich 	if (!ch)
69855e739d17SVlad Yasevich 		goto num;
698665b07e5dSVlad Yasevich 
698765b07e5dSVlad Yasevich 	/* See if the user provided enough room for all the data */
69883c918704SXin Long 	num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr);
6989b40db684SVlad Yasevich 	if (len < num_chunks)
699065b07e5dSVlad Yasevich 		return -EINVAL;
699165b07e5dSVlad Yasevich 
69925e739d17SVlad Yasevich 	if (copy_to_user(to, ch->chunks, num_chunks))
699365b07e5dSVlad Yasevich 		return -EFAULT;
69945e739d17SVlad Yasevich num:
69955e739d17SVlad Yasevich 	len = sizeof(struct sctp_authchunks) + num_chunks;
69968d72651dSwangweidong 	if (put_user(len, optlen))
69978d72651dSwangweidong 		return -EFAULT;
69987e8616d8SVlad Yasevich 	if (put_user(num_chunks, &p->gauth_number_of_chunks))
69997e8616d8SVlad Yasevich 		return -EFAULT;
700065b07e5dSVlad Yasevich 	return 0;
700165b07e5dSVlad Yasevich }
700265b07e5dSVlad Yasevich 
sctp_getsockopt_local_auth_chunks(struct sock * sk,int len,char __user * optval,int __user * optlen)700365b07e5dSVlad Yasevich static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
700465b07e5dSVlad Yasevich 				    char __user *optval, int __user *optlen)
700565b07e5dSVlad Yasevich {
7006b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
7007411223c0SAl Viro 	struct sctp_authchunks __user *p = (void __user *)optval;
700865b07e5dSVlad Yasevich 	struct sctp_authchunks val;
700965b07e5dSVlad Yasevich 	struct sctp_association *asoc;
701065b07e5dSVlad Yasevich 	struct sctp_chunks_param *ch;
70115e739d17SVlad Yasevich 	u32    num_chunks = 0;
701265b07e5dSVlad Yasevich 	char __user *to;
701365b07e5dSVlad Yasevich 
70145e739d17SVlad Yasevich 	if (len < sizeof(struct sctp_authchunks))
701565b07e5dSVlad Yasevich 		return -EINVAL;
701665b07e5dSVlad Yasevich 
7017c76f97c9SMarcelo Ricardo Leitner 	if (copy_from_user(&val, optval, sizeof(val)))
701865b07e5dSVlad Yasevich 		return -EFAULT;
701965b07e5dSVlad Yasevich 
7020411223c0SAl Viro 	to = p->gauth_chunks;
702165b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
702248c07217SXin Long 	if (!asoc && val.gauth_assoc_id != SCTP_FUTURE_ASSOC &&
702348c07217SXin Long 	    sctp_style(sk, UDP))
702465b07e5dSVlad Yasevich 		return -EINVAL;
702565b07e5dSVlad Yasevich 
7026219f9ea4SXin Long 	if (asoc) {
7027219f9ea4SXin Long 		if (!asoc->peer.auth_capable)
7028219f9ea4SXin Long 			return -EACCES;
7029219f9ea4SXin Long 		ch = (struct sctp_chunks_param *)asoc->c.auth_chunks;
7030219f9ea4SXin Long 	} else {
7031219f9ea4SXin Long 		if (!ep->auth_enable)
7032219f9ea4SXin Long 			return -EACCES;
7033219f9ea4SXin Long 		ch = ep->auth_chunk_list;
7034219f9ea4SXin Long 	}
70355e739d17SVlad Yasevich 	if (!ch)
70365e739d17SVlad Yasevich 		goto num;
70375e739d17SVlad Yasevich 
70383c918704SXin Long 	num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr);
70395e739d17SVlad Yasevich 	if (len < sizeof(struct sctp_authchunks) + num_chunks)
704065b07e5dSVlad Yasevich 		return -EINVAL;
704165b07e5dSVlad Yasevich 
70425e739d17SVlad Yasevich 	if (copy_to_user(to, ch->chunks, num_chunks))
70435e739d17SVlad Yasevich 		return -EFAULT;
70445e739d17SVlad Yasevich num:
70455e739d17SVlad Yasevich 	len = sizeof(struct sctp_authchunks) + num_chunks;
704665b07e5dSVlad Yasevich 	if (put_user(len, optlen))
704765b07e5dSVlad Yasevich 		return -EFAULT;
70487e8616d8SVlad Yasevich 	if (put_user(num_chunks, &p->gauth_number_of_chunks))
70497e8616d8SVlad Yasevich 		return -EFAULT;
705065b07e5dSVlad Yasevich 
705165b07e5dSVlad Yasevich 	return 0;
705265b07e5dSVlad Yasevich }
705365b07e5dSVlad Yasevich 
7054aea3c5c0SWei Yongjun /*
7055aea3c5c0SWei Yongjun  * 8.2.5.  Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER)
7056aea3c5c0SWei Yongjun  * This option gets the current number of associations that are attached
7057aea3c5c0SWei Yongjun  * to a one-to-many style socket.  The option value is an uint32_t.
7058aea3c5c0SWei Yongjun  */
sctp_getsockopt_assoc_number(struct sock * sk,int len,char __user * optval,int __user * optlen)7059aea3c5c0SWei Yongjun static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
7060aea3c5c0SWei Yongjun 				    char __user *optval, int __user *optlen)
7061aea3c5c0SWei Yongjun {
7062aea3c5c0SWei Yongjun 	struct sctp_sock *sp = sctp_sk(sk);
7063aea3c5c0SWei Yongjun 	struct sctp_association *asoc;
7064aea3c5c0SWei Yongjun 	u32 val = 0;
7065aea3c5c0SWei Yongjun 
7066aea3c5c0SWei Yongjun 	if (sctp_style(sk, TCP))
7067aea3c5c0SWei Yongjun 		return -EOPNOTSUPP;
7068aea3c5c0SWei Yongjun 
7069aea3c5c0SWei Yongjun 	if (len < sizeof(u32))
7070aea3c5c0SWei Yongjun 		return -EINVAL;
7071aea3c5c0SWei Yongjun 
7072aea3c5c0SWei Yongjun 	len = sizeof(u32);
7073aea3c5c0SWei Yongjun 
7074aea3c5c0SWei Yongjun 	list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
7075aea3c5c0SWei Yongjun 		val++;
7076aea3c5c0SWei Yongjun 	}
7077aea3c5c0SWei Yongjun 
7078aea3c5c0SWei Yongjun 	if (put_user(len, optlen))
7079aea3c5c0SWei Yongjun 		return -EFAULT;
7080aea3c5c0SWei Yongjun 	if (copy_to_user(optval, &val, len))
7081aea3c5c0SWei Yongjun 		return -EFAULT;
7082aea3c5c0SWei Yongjun 
7083aea3c5c0SWei Yongjun 	return 0;
7084aea3c5c0SWei Yongjun }
7085aea3c5c0SWei Yongjun 
7086209ba424SWei Yongjun /*
70877dc04d71SMichio Honda  * 8.1.23 SCTP_AUTO_ASCONF
70887dc04d71SMichio Honda  * See the corresponding setsockopt entry as description
70897dc04d71SMichio Honda  */
sctp_getsockopt_auto_asconf(struct sock * sk,int len,char __user * optval,int __user * optlen)70907dc04d71SMichio Honda static int sctp_getsockopt_auto_asconf(struct sock *sk, int len,
70917dc04d71SMichio Honda 				   char __user *optval, int __user *optlen)
70927dc04d71SMichio Honda {
70937dc04d71SMichio Honda 	int val = 0;
70947dc04d71SMichio Honda 
70957dc04d71SMichio Honda 	if (len < sizeof(int))
70967dc04d71SMichio Honda 		return -EINVAL;
70977dc04d71SMichio Honda 
70987dc04d71SMichio Honda 	len = sizeof(int);
70997dc04d71SMichio Honda 	if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk))
71007dc04d71SMichio Honda 		val = 1;
71017dc04d71SMichio Honda 	if (put_user(len, optlen))
71027dc04d71SMichio Honda 		return -EFAULT;
71037dc04d71SMichio Honda 	if (copy_to_user(optval, &val, len))
71047dc04d71SMichio Honda 		return -EFAULT;
71057dc04d71SMichio Honda 	return 0;
71067dc04d71SMichio Honda }
71077dc04d71SMichio Honda 
71087dc04d71SMichio Honda /*
7109209ba424SWei Yongjun  * 8.2.6. Get the Current Identifiers of Associations
7110209ba424SWei Yongjun  *        (SCTP_GET_ASSOC_ID_LIST)
7111209ba424SWei Yongjun  *
7112209ba424SWei Yongjun  * This option gets the current list of SCTP association identifiers of
7113209ba424SWei Yongjun  * the SCTP associations handled by a one-to-many style socket.
7114209ba424SWei Yongjun  */
sctp_getsockopt_assoc_ids(struct sock * sk,int len,char __user * optval,int __user * optlen)7115209ba424SWei Yongjun static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
7116209ba424SWei Yongjun 				    char __user *optval, int __user *optlen)
7117209ba424SWei Yongjun {
7118209ba424SWei Yongjun 	struct sctp_sock *sp = sctp_sk(sk);
7119209ba424SWei Yongjun 	struct sctp_association *asoc;
7120209ba424SWei Yongjun 	struct sctp_assoc_ids *ids;
712158405d6eSErick Archer 	size_t ids_size;
7122209ba424SWei Yongjun 	u32 num = 0;
7123209ba424SWei Yongjun 
7124209ba424SWei Yongjun 	if (sctp_style(sk, TCP))
7125209ba424SWei Yongjun 		return -EOPNOTSUPP;
7126209ba424SWei Yongjun 
7127209ba424SWei Yongjun 	if (len < sizeof(struct sctp_assoc_ids))
7128209ba424SWei Yongjun 		return -EINVAL;
7129209ba424SWei Yongjun 
7130209ba424SWei Yongjun 	list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
7131209ba424SWei Yongjun 		num++;
7132209ba424SWei Yongjun 	}
7133209ba424SWei Yongjun 
713458405d6eSErick Archer 	ids_size = struct_size(ids, gaids_assoc_id, num);
713558405d6eSErick Archer 	if (len < ids_size)
7136209ba424SWei Yongjun 		return -EINVAL;
7137209ba424SWei Yongjun 
713858405d6eSErick Archer 	len = ids_size;
71399ba0b963SMarcelo Ricardo Leitner 	ids = kmalloc(len, GFP_USER | __GFP_NOWARN);
7140209ba424SWei Yongjun 	if (unlikely(!ids))
7141209ba424SWei Yongjun 		return -ENOMEM;
7142209ba424SWei Yongjun 
7143209ba424SWei Yongjun 	ids->gaids_number_of_ids = num;
7144209ba424SWei Yongjun 	num = 0;
7145209ba424SWei Yongjun 	list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
7146209ba424SWei Yongjun 		ids->gaids_assoc_id[num++] = asoc->assoc_id;
7147209ba424SWei Yongjun 	}
7148209ba424SWei Yongjun 
7149209ba424SWei Yongjun 	if (put_user(len, optlen) || copy_to_user(optval, ids, len)) {
7150209ba424SWei Yongjun 		kfree(ids);
7151209ba424SWei Yongjun 		return -EFAULT;
7152209ba424SWei Yongjun 	}
7153209ba424SWei Yongjun 
7154209ba424SWei Yongjun 	kfree(ids);
7155209ba424SWei Yongjun 	return 0;
7156209ba424SWei Yongjun }
7157209ba424SWei Yongjun 
71585aa93bcfSNeil Horman /*
71595aa93bcfSNeil Horman  * SCTP_PEER_ADDR_THLDS
71605aa93bcfSNeil Horman  *
71615aa93bcfSNeil Horman  * This option allows us to fetch the partially failed threshold for one or all
71625aa93bcfSNeil Horman  * transports in an association.  See Section 6.1 of:
71635aa93bcfSNeil Horman  * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt
71645aa93bcfSNeil Horman  */
sctp_getsockopt_paddr_thresholds(struct sock * sk,char __user * optval,int len,int __user * optlen,bool v2)71655aa93bcfSNeil Horman static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
7166d467ac0aSXin Long 					    char __user *optval, int len,
7167d467ac0aSXin Long 					    int __user *optlen, bool v2)
71685aa93bcfSNeil Horman {
7169d467ac0aSXin Long 	struct sctp_paddrthlds_v2 val;
71705aa93bcfSNeil Horman 	struct sctp_transport *trans;
71715aa93bcfSNeil Horman 	struct sctp_association *asoc;
7172d467ac0aSXin Long 	int min;
71735aa93bcfSNeil Horman 
7174d467ac0aSXin Long 	min = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds);
7175d467ac0aSXin Long 	if (len < min)
71765aa93bcfSNeil Horman 		return -EINVAL;
7177d467ac0aSXin Long 	len = min;
7178d467ac0aSXin Long 	if (copy_from_user(&val, optval, len))
71795aa93bcfSNeil Horman 		return -EFAULT;
71805aa93bcfSNeil Horman 
71818add543eSXin Long 	if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) {
71825aa93bcfSNeil Horman 		trans = sctp_addr_id2transport(sk, &val.spt_address,
71835aa93bcfSNeil Horman 					       val.spt_assoc_id);
71845aa93bcfSNeil Horman 		if (!trans)
71855aa93bcfSNeil Horman 			return -ENOENT;
71865aa93bcfSNeil Horman 
71875aa93bcfSNeil Horman 		val.spt_pathmaxrxt = trans->pathmaxrxt;
71885aa93bcfSNeil Horman 		val.spt_pathpfthld = trans->pf_retrans;
7189d467ac0aSXin Long 		val.spt_pathcpthld = trans->ps_retrans;
71908add543eSXin Long 
7191f794dc23SXin Long 		goto out;
71928add543eSXin Long 	}
71938add543eSXin Long 
71948add543eSXin Long 	asoc = sctp_id2assoc(sk, val.spt_assoc_id);
71958add543eSXin Long 	if (!asoc && val.spt_assoc_id != SCTP_FUTURE_ASSOC &&
71968add543eSXin Long 	    sctp_style(sk, UDP))
71978add543eSXin Long 		return -EINVAL;
71988add543eSXin Long 
71998add543eSXin Long 	if (asoc) {
72008add543eSXin Long 		val.spt_pathpfthld = asoc->pf_retrans;
72018add543eSXin Long 		val.spt_pathmaxrxt = asoc->pathmaxrxt;
7202d467ac0aSXin Long 		val.spt_pathcpthld = asoc->ps_retrans;
72038add543eSXin Long 	} else {
72048add543eSXin Long 		struct sctp_sock *sp = sctp_sk(sk);
72058add543eSXin Long 
72068add543eSXin Long 		val.spt_pathpfthld = sp->pf_retrans;
72078add543eSXin Long 		val.spt_pathmaxrxt = sp->pathmaxrxt;
7208d467ac0aSXin Long 		val.spt_pathcpthld = sp->ps_retrans;
72095aa93bcfSNeil Horman 	}
72105aa93bcfSNeil Horman 
7211f794dc23SXin Long out:
72125aa93bcfSNeil Horman 	if (put_user(len, optlen) || copy_to_user(optval, &val, len))
72135aa93bcfSNeil Horman 		return -EFAULT;
72145aa93bcfSNeil Horman 
72155aa93bcfSNeil Horman 	return 0;
72165aa93bcfSNeil Horman }
72175aa93bcfSNeil Horman 
7218196d6759SMichele Baldessari /*
7219196d6759SMichele Baldessari  * SCTP_GET_ASSOC_STATS
7220196d6759SMichele Baldessari  *
7221196d6759SMichele Baldessari  * This option retrieves local per endpoint statistics. It is modeled
7222196d6759SMichele Baldessari  * after OpenSolaris' implementation
7223196d6759SMichele Baldessari  */
sctp_getsockopt_assoc_stats(struct sock * sk,int len,char __user * optval,int __user * optlen)7224196d6759SMichele Baldessari static int sctp_getsockopt_assoc_stats(struct sock *sk, int len,
7225196d6759SMichele Baldessari 				       char __user *optval,
7226196d6759SMichele Baldessari 				       int __user *optlen)
7227196d6759SMichele Baldessari {
7228196d6759SMichele Baldessari 	struct sctp_assoc_stats sas;
7229196d6759SMichele Baldessari 	struct sctp_association *asoc = NULL;
7230196d6759SMichele Baldessari 
7231196d6759SMichele Baldessari 	/* User must provide at least the assoc id */
7232196d6759SMichele Baldessari 	if (len < sizeof(sctp_assoc_t))
7233196d6759SMichele Baldessari 		return -EINVAL;
7234196d6759SMichele Baldessari 
7235726bc6b0SGuenter Roeck 	/* Allow the struct to grow and fill in as much as possible */
7236726bc6b0SGuenter Roeck 	len = min_t(size_t, len, sizeof(sas));
7237726bc6b0SGuenter Roeck 
7238196d6759SMichele Baldessari 	if (copy_from_user(&sas, optval, len))
7239196d6759SMichele Baldessari 		return -EFAULT;
7240196d6759SMichele Baldessari 
7241196d6759SMichele Baldessari 	asoc = sctp_id2assoc(sk, sas.sas_assoc_id);
7242196d6759SMichele Baldessari 	if (!asoc)
7243196d6759SMichele Baldessari 		return -EINVAL;
7244196d6759SMichele Baldessari 
7245196d6759SMichele Baldessari 	sas.sas_rtxchunks = asoc->stats.rtxchunks;
7246196d6759SMichele Baldessari 	sas.sas_gapcnt = asoc->stats.gapcnt;
7247196d6759SMichele Baldessari 	sas.sas_outofseqtsns = asoc->stats.outofseqtsns;
7248196d6759SMichele Baldessari 	sas.sas_osacks = asoc->stats.osacks;
7249196d6759SMichele Baldessari 	sas.sas_isacks = asoc->stats.isacks;
7250196d6759SMichele Baldessari 	sas.sas_octrlchunks = asoc->stats.octrlchunks;
7251196d6759SMichele Baldessari 	sas.sas_ictrlchunks = asoc->stats.ictrlchunks;
7252196d6759SMichele Baldessari 	sas.sas_oodchunks = asoc->stats.oodchunks;
7253196d6759SMichele Baldessari 	sas.sas_iodchunks = asoc->stats.iodchunks;
7254196d6759SMichele Baldessari 	sas.sas_ouodchunks = asoc->stats.ouodchunks;
7255196d6759SMichele Baldessari 	sas.sas_iuodchunks = asoc->stats.iuodchunks;
7256196d6759SMichele Baldessari 	sas.sas_idupchunks = asoc->stats.idupchunks;
7257196d6759SMichele Baldessari 	sas.sas_opackets = asoc->stats.opackets;
7258196d6759SMichele Baldessari 	sas.sas_ipackets = asoc->stats.ipackets;
7259196d6759SMichele Baldessari 
7260196d6759SMichele Baldessari 	/* New high max rto observed, will return 0 if not a single
7261196d6759SMichele Baldessari 	 * RTO update took place. obs_rto_ipaddr will be bogus
7262196d6759SMichele Baldessari 	 * in such a case
7263196d6759SMichele Baldessari 	 */
7264196d6759SMichele Baldessari 	sas.sas_maxrto = asoc->stats.max_obs_rto;
7265196d6759SMichele Baldessari 	memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr,
7266196d6759SMichele Baldessari 		sizeof(struct sockaddr_storage));
7267196d6759SMichele Baldessari 
7268196d6759SMichele Baldessari 	/* Mark beginning of a new observation period */
7269196d6759SMichele Baldessari 	asoc->stats.max_obs_rto = asoc->rto_min;
7270196d6759SMichele Baldessari 
7271196d6759SMichele Baldessari 	if (put_user(len, optlen))
7272196d6759SMichele Baldessari 		return -EFAULT;
7273196d6759SMichele Baldessari 
7274bb33381dSDaniel Borkmann 	pr_debug("%s: len:%d, assoc_id:%d\n", __func__, len, sas.sas_assoc_id);
7275196d6759SMichele Baldessari 
7276196d6759SMichele Baldessari 	if (copy_to_user(optval, &sas, len))
7277196d6759SMichele Baldessari 		return -EFAULT;
7278196d6759SMichele Baldessari 
7279196d6759SMichele Baldessari 	return 0;
7280196d6759SMichele Baldessari }
7281196d6759SMichele Baldessari 
sctp_getsockopt_recvrcvinfo(struct sock * sk,int len,char __user * optval,int __user * optlen)72820d3a421dSGeir Ola Vaagland static int sctp_getsockopt_recvrcvinfo(struct sock *sk,	int len,
72830d3a421dSGeir Ola Vaagland 				       char __user *optval,
72840d3a421dSGeir Ola Vaagland 				       int __user *optlen)
72850d3a421dSGeir Ola Vaagland {
72860d3a421dSGeir Ola Vaagland 	int val = 0;
72870d3a421dSGeir Ola Vaagland 
72880d3a421dSGeir Ola Vaagland 	if (len < sizeof(int))
72890d3a421dSGeir Ola Vaagland 		return -EINVAL;
72900d3a421dSGeir Ola Vaagland 
72910d3a421dSGeir Ola Vaagland 	len = sizeof(int);
72920d3a421dSGeir Ola Vaagland 	if (sctp_sk(sk)->recvrcvinfo)
72930d3a421dSGeir Ola Vaagland 		val = 1;
72940d3a421dSGeir Ola Vaagland 	if (put_user(len, optlen))
72950d3a421dSGeir Ola Vaagland 		return -EFAULT;
72960d3a421dSGeir Ola Vaagland 	if (copy_to_user(optval, &val, len))
72970d3a421dSGeir Ola Vaagland 		return -EFAULT;
72980d3a421dSGeir Ola Vaagland 
72990d3a421dSGeir Ola Vaagland 	return 0;
73000d3a421dSGeir Ola Vaagland }
73010d3a421dSGeir Ola Vaagland 
sctp_getsockopt_recvnxtinfo(struct sock * sk,int len,char __user * optval,int __user * optlen)73022347c80fSGeir Ola Vaagland static int sctp_getsockopt_recvnxtinfo(struct sock *sk,	int len,
73032347c80fSGeir Ola Vaagland 				       char __user *optval,
73042347c80fSGeir Ola Vaagland 				       int __user *optlen)
73052347c80fSGeir Ola Vaagland {
73062347c80fSGeir Ola Vaagland 	int val = 0;
73072347c80fSGeir Ola Vaagland 
73082347c80fSGeir Ola Vaagland 	if (len < sizeof(int))
73092347c80fSGeir Ola Vaagland 		return -EINVAL;
73102347c80fSGeir Ola Vaagland 
73112347c80fSGeir Ola Vaagland 	len = sizeof(int);
73122347c80fSGeir Ola Vaagland 	if (sctp_sk(sk)->recvnxtinfo)
73132347c80fSGeir Ola Vaagland 		val = 1;
73142347c80fSGeir Ola Vaagland 	if (put_user(len, optlen))
73152347c80fSGeir Ola Vaagland 		return -EFAULT;
73162347c80fSGeir Ola Vaagland 	if (copy_to_user(optval, &val, len))
73172347c80fSGeir Ola Vaagland 		return -EFAULT;
73182347c80fSGeir Ola Vaagland 
73192347c80fSGeir Ola Vaagland 	return 0;
73202347c80fSGeir Ola Vaagland }
73212347c80fSGeir Ola Vaagland 
sctp_getsockopt_pr_supported(struct sock * sk,int len,char __user * optval,int __user * optlen)732228aa4c26SXin Long static int sctp_getsockopt_pr_supported(struct sock *sk, int len,
732328aa4c26SXin Long 					char __user *optval,
732428aa4c26SXin Long 					int __user *optlen)
732528aa4c26SXin Long {
732628aa4c26SXin Long 	struct sctp_assoc_value params;
732728aa4c26SXin Long 	struct sctp_association *asoc;
732828aa4c26SXin Long 	int retval = -EFAULT;
732928aa4c26SXin Long 
733028aa4c26SXin Long 	if (len < sizeof(params)) {
733128aa4c26SXin Long 		retval = -EINVAL;
733228aa4c26SXin Long 		goto out;
733328aa4c26SXin Long 	}
733428aa4c26SXin Long 
733528aa4c26SXin Long 	len = sizeof(params);
733628aa4c26SXin Long 	if (copy_from_user(&params, optval, len))
733728aa4c26SXin Long 		goto out;
733828aa4c26SXin Long 
733928aa4c26SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
7340fb195605SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
7341fb195605SXin Long 	    sctp_style(sk, UDP)) {
734228aa4c26SXin Long 		retval = -EINVAL;
734328aa4c26SXin Long 		goto out;
734428aa4c26SXin Long 	}
734528aa4c26SXin Long 
73461c134753SXin Long 	params.assoc_value = asoc ? asoc->peer.prsctp_capable
7347fb195605SXin Long 				  : sctp_sk(sk)->ep->prsctp_enable;
7348fb195605SXin Long 
734928aa4c26SXin Long 	if (put_user(len, optlen))
735028aa4c26SXin Long 		goto out;
735128aa4c26SXin Long 
735228aa4c26SXin Long 	if (copy_to_user(optval, &params, len))
735328aa4c26SXin Long 		goto out;
735428aa4c26SXin Long 
735528aa4c26SXin Long 	retval = 0;
735628aa4c26SXin Long 
735728aa4c26SXin Long out:
735828aa4c26SXin Long 	return retval;
735928aa4c26SXin Long }
736028aa4c26SXin Long 
sctp_getsockopt_default_prinfo(struct sock * sk,int len,char __user * optval,int __user * optlen)7361f959fb44SXin Long static int sctp_getsockopt_default_prinfo(struct sock *sk, int len,
7362f959fb44SXin Long 					  char __user *optval,
7363f959fb44SXin Long 					  int __user *optlen)
7364f959fb44SXin Long {
7365f959fb44SXin Long 	struct sctp_default_prinfo info;
7366f959fb44SXin Long 	struct sctp_association *asoc;
7367f959fb44SXin Long 	int retval = -EFAULT;
7368f959fb44SXin Long 
7369f959fb44SXin Long 	if (len < sizeof(info)) {
7370f959fb44SXin Long 		retval = -EINVAL;
7371f959fb44SXin Long 		goto out;
7372f959fb44SXin Long 	}
7373f959fb44SXin Long 
7374f959fb44SXin Long 	len = sizeof(info);
7375f959fb44SXin Long 	if (copy_from_user(&info, optval, len))
7376f959fb44SXin Long 		goto out;
7377f959fb44SXin Long 
7378f959fb44SXin Long 	asoc = sctp_id2assoc(sk, info.pr_assoc_id);
73793a583059SXin Long 	if (!asoc && info.pr_assoc_id != SCTP_FUTURE_ASSOC &&
73803a583059SXin Long 	    sctp_style(sk, UDP)) {
73813a583059SXin Long 		retval = -EINVAL;
73823a583059SXin Long 		goto out;
73833a583059SXin Long 	}
73843a583059SXin Long 
7385f959fb44SXin Long 	if (asoc) {
7386f959fb44SXin Long 		info.pr_policy = SCTP_PR_POLICY(asoc->default_flags);
7387f959fb44SXin Long 		info.pr_value = asoc->default_timetolive;
73883a583059SXin Long 	} else {
7389f959fb44SXin Long 		struct sctp_sock *sp = sctp_sk(sk);
7390f959fb44SXin Long 
7391f959fb44SXin Long 		info.pr_policy = SCTP_PR_POLICY(sp->default_flags);
7392f959fb44SXin Long 		info.pr_value = sp->default_timetolive;
7393f959fb44SXin Long 	}
7394f959fb44SXin Long 
7395f959fb44SXin Long 	if (put_user(len, optlen))
7396f959fb44SXin Long 		goto out;
7397f959fb44SXin Long 
7398f959fb44SXin Long 	if (copy_to_user(optval, &info, len))
7399f959fb44SXin Long 		goto out;
7400f959fb44SXin Long 
7401f959fb44SXin Long 	retval = 0;
7402f959fb44SXin Long 
7403f959fb44SXin Long out:
7404f959fb44SXin Long 	return retval;
7405f959fb44SXin Long }
7406f959fb44SXin Long 
sctp_getsockopt_pr_assocstatus(struct sock * sk,int len,char __user * optval,int __user * optlen)7407826d253dSXin Long static int sctp_getsockopt_pr_assocstatus(struct sock *sk, int len,
7408826d253dSXin Long 					  char __user *optval,
7409826d253dSXin Long 					  int __user *optlen)
7410826d253dSXin Long {
7411826d253dSXin Long 	struct sctp_prstatus params;
7412826d253dSXin Long 	struct sctp_association *asoc;
7413826d253dSXin Long 	int policy;
7414826d253dSXin Long 	int retval = -EINVAL;
7415826d253dSXin Long 
7416826d253dSXin Long 	if (len < sizeof(params))
7417826d253dSXin Long 		goto out;
7418826d253dSXin Long 
7419826d253dSXin Long 	len = sizeof(params);
7420826d253dSXin Long 	if (copy_from_user(&params, optval, len)) {
7421826d253dSXin Long 		retval = -EFAULT;
7422826d253dSXin Long 		goto out;
7423826d253dSXin Long 	}
7424826d253dSXin Long 
7425826d253dSXin Long 	policy = params.sprstat_policy;
742671335836SXin Long 	if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) ||
742771335836SXin Long 	    ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK)))
7428826d253dSXin Long 		goto out;
7429826d253dSXin Long 
7430826d253dSXin Long 	asoc = sctp_id2assoc(sk, params.sprstat_assoc_id);
7431826d253dSXin Long 	if (!asoc)
7432826d253dSXin Long 		goto out;
7433826d253dSXin Long 
743471335836SXin Long 	if (policy == SCTP_PR_SCTP_ALL) {
7435826d253dSXin Long 		params.sprstat_abandoned_unsent = 0;
7436826d253dSXin Long 		params.sprstat_abandoned_sent = 0;
7437826d253dSXin Long 		for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) {
7438826d253dSXin Long 			params.sprstat_abandoned_unsent +=
7439826d253dSXin Long 				asoc->abandoned_unsent[policy];
7440826d253dSXin Long 			params.sprstat_abandoned_sent +=
7441826d253dSXin Long 				asoc->abandoned_sent[policy];
7442826d253dSXin Long 		}
7443826d253dSXin Long 	} else {
7444826d253dSXin Long 		params.sprstat_abandoned_unsent =
7445826d253dSXin Long 			asoc->abandoned_unsent[__SCTP_PR_INDEX(policy)];
7446826d253dSXin Long 		params.sprstat_abandoned_sent =
7447826d253dSXin Long 			asoc->abandoned_sent[__SCTP_PR_INDEX(policy)];
7448826d253dSXin Long 	}
7449826d253dSXin Long 
7450826d253dSXin Long 	if (put_user(len, optlen)) {
7451826d253dSXin Long 		retval = -EFAULT;
7452826d253dSXin Long 		goto out;
7453826d253dSXin Long 	}
7454826d253dSXin Long 
7455826d253dSXin Long 	if (copy_to_user(optval, &params, len)) {
7456826d253dSXin Long 		retval = -EFAULT;
7457826d253dSXin Long 		goto out;
7458826d253dSXin Long 	}
7459826d253dSXin Long 
7460826d253dSXin Long 	retval = 0;
7461826d253dSXin Long 
7462826d253dSXin Long out:
7463826d253dSXin Long 	return retval;
7464826d253dSXin Long }
7465826d253dSXin Long 
sctp_getsockopt_pr_streamstatus(struct sock * sk,int len,char __user * optval,int __user * optlen)7466d229d48dSXin Long static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len,
7467d229d48dSXin Long 					   char __user *optval,
7468d229d48dSXin Long 					   int __user *optlen)
7469d229d48dSXin Long {
7470f952be79SMarcelo Ricardo Leitner 	struct sctp_stream_out_ext *streamoute;
7471d229d48dSXin Long 	struct sctp_association *asoc;
7472d229d48dSXin Long 	struct sctp_prstatus params;
7473d229d48dSXin Long 	int retval = -EINVAL;
7474d229d48dSXin Long 	int policy;
7475d229d48dSXin Long 
7476d229d48dSXin Long 	if (len < sizeof(params))
7477d229d48dSXin Long 		goto out;
7478d229d48dSXin Long 
7479d229d48dSXin Long 	len = sizeof(params);
7480d229d48dSXin Long 	if (copy_from_user(&params, optval, len)) {
7481d229d48dSXin Long 		retval = -EFAULT;
7482d229d48dSXin Long 		goto out;
7483d229d48dSXin Long 	}
7484d229d48dSXin Long 
7485d229d48dSXin Long 	policy = params.sprstat_policy;
748671335836SXin Long 	if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) ||
748771335836SXin Long 	    ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK)))
7488d229d48dSXin Long 		goto out;
7489d229d48dSXin Long 
7490d229d48dSXin Long 	asoc = sctp_id2assoc(sk, params.sprstat_assoc_id);
7491cee360abSXin Long 	if (!asoc || params.sprstat_sid >= asoc->stream.outcnt)
7492d229d48dSXin Long 		goto out;
7493d229d48dSXin Long 
749405364ca0SKonstantin Khorenko 	streamoute = SCTP_SO(&asoc->stream, params.sprstat_sid)->ext;
7495f952be79SMarcelo Ricardo Leitner 	if (!streamoute) {
7496f952be79SMarcelo Ricardo Leitner 		/* Not allocated yet, means all stats are 0 */
7497f952be79SMarcelo Ricardo Leitner 		params.sprstat_abandoned_unsent = 0;
7498f952be79SMarcelo Ricardo Leitner 		params.sprstat_abandoned_sent = 0;
7499f952be79SMarcelo Ricardo Leitner 		retval = 0;
7500f952be79SMarcelo Ricardo Leitner 		goto out;
7501f952be79SMarcelo Ricardo Leitner 	}
7502f952be79SMarcelo Ricardo Leitner 
75030ac1077eSXin Long 	if (policy == SCTP_PR_SCTP_ALL) {
7504d229d48dSXin Long 		params.sprstat_abandoned_unsent = 0;
7505d229d48dSXin Long 		params.sprstat_abandoned_sent = 0;
7506d229d48dSXin Long 		for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) {
7507d229d48dSXin Long 			params.sprstat_abandoned_unsent +=
7508f952be79SMarcelo Ricardo Leitner 				streamoute->abandoned_unsent[policy];
7509d229d48dSXin Long 			params.sprstat_abandoned_sent +=
7510f952be79SMarcelo Ricardo Leitner 				streamoute->abandoned_sent[policy];
7511d229d48dSXin Long 		}
7512d229d48dSXin Long 	} else {
7513d229d48dSXin Long 		params.sprstat_abandoned_unsent =
7514f952be79SMarcelo Ricardo Leitner 			streamoute->abandoned_unsent[__SCTP_PR_INDEX(policy)];
7515d229d48dSXin Long 		params.sprstat_abandoned_sent =
7516f952be79SMarcelo Ricardo Leitner 			streamoute->abandoned_sent[__SCTP_PR_INDEX(policy)];
7517d229d48dSXin Long 	}
7518d229d48dSXin Long 
7519d229d48dSXin Long 	if (put_user(len, optlen) || copy_to_user(optval, &params, len)) {
7520d229d48dSXin Long 		retval = -EFAULT;
7521d229d48dSXin Long 		goto out;
7522d229d48dSXin Long 	}
7523d229d48dSXin Long 
7524d229d48dSXin Long 	retval = 0;
7525d229d48dSXin Long 
7526d229d48dSXin Long out:
7527d229d48dSXin Long 	return retval;
7528d229d48dSXin Long }
7529d229d48dSXin Long 
sctp_getsockopt_reconfig_supported(struct sock * sk,int len,char __user * optval,int __user * optlen)7530c0d8bab6SXin Long static int sctp_getsockopt_reconfig_supported(struct sock *sk, int len,
7531c0d8bab6SXin Long 					      char __user *optval,
7532c0d8bab6SXin Long 					      int __user *optlen)
7533c0d8bab6SXin Long {
7534c0d8bab6SXin Long 	struct sctp_assoc_value params;
7535c0d8bab6SXin Long 	struct sctp_association *asoc;
7536c0d8bab6SXin Long 	int retval = -EFAULT;
7537c0d8bab6SXin Long 
7538c0d8bab6SXin Long 	if (len < sizeof(params)) {
7539c0d8bab6SXin Long 		retval = -EINVAL;
7540c0d8bab6SXin Long 		goto out;
7541c0d8bab6SXin Long 	}
7542c0d8bab6SXin Long 
7543c0d8bab6SXin Long 	len = sizeof(params);
7544c0d8bab6SXin Long 	if (copy_from_user(&params, optval, len))
7545c0d8bab6SXin Long 		goto out;
7546c0d8bab6SXin Long 
7547c0d8bab6SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
7548acce7f3bSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
7549acce7f3bSXin Long 	    sctp_style(sk, UDP)) {
7550c0d8bab6SXin Long 		retval = -EINVAL;
7551c0d8bab6SXin Long 		goto out;
7552c0d8bab6SXin Long 	}
7553c0d8bab6SXin Long 
7554a96701fbSXin Long 	params.assoc_value = asoc ? asoc->peer.reconf_capable
7555acce7f3bSXin Long 				  : sctp_sk(sk)->ep->reconf_enable;
7556acce7f3bSXin Long 
7557c0d8bab6SXin Long 	if (put_user(len, optlen))
7558c0d8bab6SXin Long 		goto out;
7559c0d8bab6SXin Long 
7560c0d8bab6SXin Long 	if (copy_to_user(optval, &params, len))
7561c0d8bab6SXin Long 		goto out;
7562c0d8bab6SXin Long 
7563c0d8bab6SXin Long 	retval = 0;
7564c0d8bab6SXin Long 
7565c0d8bab6SXin Long out:
7566c0d8bab6SXin Long 	return retval;
7567c0d8bab6SXin Long }
7568c0d8bab6SXin Long 
sctp_getsockopt_enable_strreset(struct sock * sk,int len,char __user * optval,int __user * optlen)75699fb657aeSXin Long static int sctp_getsockopt_enable_strreset(struct sock *sk, int len,
75709fb657aeSXin Long 					   char __user *optval,
75719fb657aeSXin Long 					   int __user *optlen)
75729fb657aeSXin Long {
75739fb657aeSXin Long 	struct sctp_assoc_value params;
75749fb657aeSXin Long 	struct sctp_association *asoc;
75759fb657aeSXin Long 	int retval = -EFAULT;
75769fb657aeSXin Long 
75779fb657aeSXin Long 	if (len < sizeof(params)) {
75789fb657aeSXin Long 		retval = -EINVAL;
75799fb657aeSXin Long 		goto out;
75809fb657aeSXin Long 	}
75819fb657aeSXin Long 
75829fb657aeSXin Long 	len = sizeof(params);
75839fb657aeSXin Long 	if (copy_from_user(&params, optval, len))
75849fb657aeSXin Long 		goto out;
75859fb657aeSXin Long 
75869fb657aeSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
758799a62135SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
758899a62135SXin Long 	    sctp_style(sk, UDP)) {
75899fb657aeSXin Long 		retval = -EINVAL;
75909fb657aeSXin Long 		goto out;
75919fb657aeSXin Long 	}
75929fb657aeSXin Long 
759399a62135SXin Long 	params.assoc_value = asoc ? asoc->strreset_enable
759499a62135SXin Long 				  : sctp_sk(sk)->ep->strreset_enable;
759599a62135SXin Long 
75969fb657aeSXin Long 	if (put_user(len, optlen))
75979fb657aeSXin Long 		goto out;
75989fb657aeSXin Long 
75999fb657aeSXin Long 	if (copy_to_user(optval, &params, len))
76009fb657aeSXin Long 		goto out;
76019fb657aeSXin Long 
76029fb657aeSXin Long 	retval = 0;
76039fb657aeSXin Long 
76049fb657aeSXin Long out:
76059fb657aeSXin Long 	return retval;
76069fb657aeSXin Long }
76079fb657aeSXin Long 
sctp_getsockopt_scheduler(struct sock * sk,int len,char __user * optval,int __user * optlen)760813aa8770SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler(struct sock *sk, int len,
760913aa8770SMarcelo Ricardo Leitner 				     char __user *optval,
761013aa8770SMarcelo Ricardo Leitner 				     int __user *optlen)
761113aa8770SMarcelo Ricardo Leitner {
761213aa8770SMarcelo Ricardo Leitner 	struct sctp_assoc_value params;
761313aa8770SMarcelo Ricardo Leitner 	struct sctp_association *asoc;
761413aa8770SMarcelo Ricardo Leitner 	int retval = -EFAULT;
761513aa8770SMarcelo Ricardo Leitner 
761613aa8770SMarcelo Ricardo Leitner 	if (len < sizeof(params)) {
761713aa8770SMarcelo Ricardo Leitner 		retval = -EINVAL;
761813aa8770SMarcelo Ricardo Leitner 		goto out;
761913aa8770SMarcelo Ricardo Leitner 	}
762013aa8770SMarcelo Ricardo Leitner 
762113aa8770SMarcelo Ricardo Leitner 	len = sizeof(params);
762213aa8770SMarcelo Ricardo Leitner 	if (copy_from_user(&params, optval, len))
762313aa8770SMarcelo Ricardo Leitner 		goto out;
762413aa8770SMarcelo Ricardo Leitner 
762513aa8770SMarcelo Ricardo Leitner 	asoc = sctp_id2assoc(sk, params.assoc_id);
76267efba10dSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
76277efba10dSXin Long 	    sctp_style(sk, UDP)) {
762813aa8770SMarcelo Ricardo Leitner 		retval = -EINVAL;
762913aa8770SMarcelo Ricardo Leitner 		goto out;
763013aa8770SMarcelo Ricardo Leitner 	}
763113aa8770SMarcelo Ricardo Leitner 
76327efba10dSXin Long 	params.assoc_value = asoc ? sctp_sched_get_sched(asoc)
76337efba10dSXin Long 				  : sctp_sk(sk)->default_ss;
763413aa8770SMarcelo Ricardo Leitner 
763513aa8770SMarcelo Ricardo Leitner 	if (put_user(len, optlen))
763613aa8770SMarcelo Ricardo Leitner 		goto out;
763713aa8770SMarcelo Ricardo Leitner 
763813aa8770SMarcelo Ricardo Leitner 	if (copy_to_user(optval, &params, len))
763913aa8770SMarcelo Ricardo Leitner 		goto out;
764013aa8770SMarcelo Ricardo Leitner 
764113aa8770SMarcelo Ricardo Leitner 	retval = 0;
764213aa8770SMarcelo Ricardo Leitner 
764313aa8770SMarcelo Ricardo Leitner out:
764413aa8770SMarcelo Ricardo Leitner 	return retval;
764513aa8770SMarcelo Ricardo Leitner }
764613aa8770SMarcelo Ricardo Leitner 
sctp_getsockopt_scheduler_value(struct sock * sk,int len,char __user * optval,int __user * optlen)76470ccdf3c7SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler_value(struct sock *sk, int len,
76480ccdf3c7SMarcelo Ricardo Leitner 					   char __user *optval,
76490ccdf3c7SMarcelo Ricardo Leitner 					   int __user *optlen)
76500ccdf3c7SMarcelo Ricardo Leitner {
76510ccdf3c7SMarcelo Ricardo Leitner 	struct sctp_stream_value params;
76520ccdf3c7SMarcelo Ricardo Leitner 	struct sctp_association *asoc;
76530ccdf3c7SMarcelo Ricardo Leitner 	int retval = -EFAULT;
76540ccdf3c7SMarcelo Ricardo Leitner 
76550ccdf3c7SMarcelo Ricardo Leitner 	if (len < sizeof(params)) {
76560ccdf3c7SMarcelo Ricardo Leitner 		retval = -EINVAL;
76570ccdf3c7SMarcelo Ricardo Leitner 		goto out;
76580ccdf3c7SMarcelo Ricardo Leitner 	}
76590ccdf3c7SMarcelo Ricardo Leitner 
76600ccdf3c7SMarcelo Ricardo Leitner 	len = sizeof(params);
76610ccdf3c7SMarcelo Ricardo Leitner 	if (copy_from_user(&params, optval, len))
76620ccdf3c7SMarcelo Ricardo Leitner 		goto out;
76630ccdf3c7SMarcelo Ricardo Leitner 
76640ccdf3c7SMarcelo Ricardo Leitner 	asoc = sctp_id2assoc(sk, params.assoc_id);
76650ccdf3c7SMarcelo Ricardo Leitner 	if (!asoc) {
76660ccdf3c7SMarcelo Ricardo Leitner 		retval = -EINVAL;
76670ccdf3c7SMarcelo Ricardo Leitner 		goto out;
76680ccdf3c7SMarcelo Ricardo Leitner 	}
76690ccdf3c7SMarcelo Ricardo Leitner 
76700ccdf3c7SMarcelo Ricardo Leitner 	retval = sctp_sched_get_value(asoc, params.stream_id,
76710ccdf3c7SMarcelo Ricardo Leitner 				      &params.stream_value);
76720ccdf3c7SMarcelo Ricardo Leitner 	if (retval)
76730ccdf3c7SMarcelo Ricardo Leitner 		goto out;
76740ccdf3c7SMarcelo Ricardo Leitner 
76750ccdf3c7SMarcelo Ricardo Leitner 	if (put_user(len, optlen)) {
76760ccdf3c7SMarcelo Ricardo Leitner 		retval = -EFAULT;
76770ccdf3c7SMarcelo Ricardo Leitner 		goto out;
76780ccdf3c7SMarcelo Ricardo Leitner 	}
76790ccdf3c7SMarcelo Ricardo Leitner 
76800ccdf3c7SMarcelo Ricardo Leitner 	if (copy_to_user(optval, &params, len)) {
76810ccdf3c7SMarcelo Ricardo Leitner 		retval = -EFAULT;
76820ccdf3c7SMarcelo Ricardo Leitner 		goto out;
76830ccdf3c7SMarcelo Ricardo Leitner 	}
76840ccdf3c7SMarcelo Ricardo Leitner 
76850ccdf3c7SMarcelo Ricardo Leitner out:
76860ccdf3c7SMarcelo Ricardo Leitner 	return retval;
76870ccdf3c7SMarcelo Ricardo Leitner }
76880ccdf3c7SMarcelo Ricardo Leitner 
sctp_getsockopt_interleaving_supported(struct sock * sk,int len,char __user * optval,int __user * optlen)7689772a5869SXin Long static int sctp_getsockopt_interleaving_supported(struct sock *sk, int len,
7690772a5869SXin Long 						  char __user *optval,
7691772a5869SXin Long 						  int __user *optlen)
7692772a5869SXin Long {
7693772a5869SXin Long 	struct sctp_assoc_value params;
7694772a5869SXin Long 	struct sctp_association *asoc;
7695772a5869SXin Long 	int retval = -EFAULT;
7696772a5869SXin Long 
7697772a5869SXin Long 	if (len < sizeof(params)) {
7698772a5869SXin Long 		retval = -EINVAL;
7699772a5869SXin Long 		goto out;
7700772a5869SXin Long 	}
7701772a5869SXin Long 
7702772a5869SXin Long 	len = sizeof(params);
7703772a5869SXin Long 	if (copy_from_user(&params, optval, len))
7704772a5869SXin Long 		goto out;
7705772a5869SXin Long 
7706772a5869SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
77072e7709d1SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
77082e7709d1SXin Long 	    sctp_style(sk, UDP)) {
7709772a5869SXin Long 		retval = -EINVAL;
7710772a5869SXin Long 		goto out;
7711772a5869SXin Long 	}
7712772a5869SXin Long 
7713da1f6d4dSXin Long 	params.assoc_value = asoc ? asoc->peer.intl_capable
7714e55f4b8bSXin Long 				  : sctp_sk(sk)->ep->intl_enable;
77152e7709d1SXin Long 
7716772a5869SXin Long 	if (put_user(len, optlen))
7717772a5869SXin Long 		goto out;
7718772a5869SXin Long 
7719772a5869SXin Long 	if (copy_to_user(optval, &params, len))
7720772a5869SXin Long 		goto out;
7721772a5869SXin Long 
7722772a5869SXin Long 	retval = 0;
7723772a5869SXin Long 
7724772a5869SXin Long out:
7725772a5869SXin Long 	return retval;
7726772a5869SXin Long }
7727772a5869SXin Long 
sctp_getsockopt_reuse_port(struct sock * sk,int len,char __user * optval,int __user * optlen)7728b0e9a2feSXin Long static int sctp_getsockopt_reuse_port(struct sock *sk, int len,
7729b0e9a2feSXin Long 				      char __user *optval,
7730b0e9a2feSXin Long 				      int __user *optlen)
7731b0e9a2feSXin Long {
7732b0e9a2feSXin Long 	int val;
7733b0e9a2feSXin Long 
7734b0e9a2feSXin Long 	if (len < sizeof(int))
7735b0e9a2feSXin Long 		return -EINVAL;
7736b0e9a2feSXin Long 
7737b0e9a2feSXin Long 	len = sizeof(int);
7738b0e9a2feSXin Long 	val = sctp_sk(sk)->reuse;
7739b0e9a2feSXin Long 	if (put_user(len, optlen))
7740b0e9a2feSXin Long 		return -EFAULT;
7741b0e9a2feSXin Long 
7742b0e9a2feSXin Long 	if (copy_to_user(optval, &val, len))
7743b0e9a2feSXin Long 		return -EFAULT;
7744b0e9a2feSXin Long 
7745b0e9a2feSXin Long 	return 0;
7746b0e9a2feSXin Long }
7747b0e9a2feSXin Long 
sctp_getsockopt_event(struct sock * sk,int len,char __user * optval,int __user * optlen)7748480ba9c1SXin Long static int sctp_getsockopt_event(struct sock *sk, int len, char __user *optval,
7749480ba9c1SXin Long 				 int __user *optlen)
7750480ba9c1SXin Long {
7751480ba9c1SXin Long 	struct sctp_association *asoc;
7752480ba9c1SXin Long 	struct sctp_event param;
7753480ba9c1SXin Long 	__u16 subscribe;
7754480ba9c1SXin Long 
7755480ba9c1SXin Long 	if (len < sizeof(param))
7756480ba9c1SXin Long 		return -EINVAL;
7757480ba9c1SXin Long 
7758480ba9c1SXin Long 	len = sizeof(param);
7759480ba9c1SXin Long 	if (copy_from_user(&param, optval, len))
7760480ba9c1SXin Long 		return -EFAULT;
7761480ba9c1SXin Long 
7762480ba9c1SXin Long 	if (param.se_type < SCTP_SN_TYPE_BASE ||
7763480ba9c1SXin Long 	    param.se_type > SCTP_SN_TYPE_MAX)
7764480ba9c1SXin Long 		return -EINVAL;
7765480ba9c1SXin Long 
7766480ba9c1SXin Long 	asoc = sctp_id2assoc(sk, param.se_assoc_id);
7767d251f05eSXin Long 	if (!asoc && param.se_assoc_id != SCTP_FUTURE_ASSOC &&
7768d251f05eSXin Long 	    sctp_style(sk, UDP))
7769d251f05eSXin Long 		return -EINVAL;
7770d251f05eSXin Long 
7771480ba9c1SXin Long 	subscribe = asoc ? asoc->subscribe : sctp_sk(sk)->subscribe;
7772480ba9c1SXin Long 	param.se_on = sctp_ulpevent_type_enabled(subscribe, param.se_type);
7773480ba9c1SXin Long 
7774480ba9c1SXin Long 	if (put_user(len, optlen))
7775480ba9c1SXin Long 		return -EFAULT;
7776480ba9c1SXin Long 
7777480ba9c1SXin Long 	if (copy_to_user(optval, &param, len))
7778480ba9c1SXin Long 		return -EFAULT;
7779480ba9c1SXin Long 
7780480ba9c1SXin Long 	return 0;
7781480ba9c1SXin Long }
7782480ba9c1SXin Long 
sctp_getsockopt_asconf_supported(struct sock * sk,int len,char __user * optval,int __user * optlen)7783df2c71ffSXin Long static int sctp_getsockopt_asconf_supported(struct sock *sk, int len,
7784df2c71ffSXin Long 					    char __user *optval,
7785df2c71ffSXin Long 					    int __user *optlen)
7786df2c71ffSXin Long {
7787df2c71ffSXin Long 	struct sctp_assoc_value params;
7788df2c71ffSXin Long 	struct sctp_association *asoc;
7789df2c71ffSXin Long 	int retval = -EFAULT;
7790df2c71ffSXin Long 
7791df2c71ffSXin Long 	if (len < sizeof(params)) {
7792df2c71ffSXin Long 		retval = -EINVAL;
7793df2c71ffSXin Long 		goto out;
7794df2c71ffSXin Long 	}
7795df2c71ffSXin Long 
7796df2c71ffSXin Long 	len = sizeof(params);
7797df2c71ffSXin Long 	if (copy_from_user(&params, optval, len))
7798df2c71ffSXin Long 		goto out;
7799df2c71ffSXin Long 
7800df2c71ffSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
7801df2c71ffSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
7802df2c71ffSXin Long 	    sctp_style(sk, UDP)) {
7803df2c71ffSXin Long 		retval = -EINVAL;
7804df2c71ffSXin Long 		goto out;
7805df2c71ffSXin Long 	}
7806df2c71ffSXin Long 
7807df2c71ffSXin Long 	params.assoc_value = asoc ? asoc->peer.asconf_capable
7808df2c71ffSXin Long 				  : sctp_sk(sk)->ep->asconf_enable;
7809df2c71ffSXin Long 
7810df2c71ffSXin Long 	if (put_user(len, optlen))
7811df2c71ffSXin Long 		goto out;
7812df2c71ffSXin Long 
7813df2c71ffSXin Long 	if (copy_to_user(optval, &params, len))
7814df2c71ffSXin Long 		goto out;
7815df2c71ffSXin Long 
7816df2c71ffSXin Long 	retval = 0;
7817df2c71ffSXin Long 
7818df2c71ffSXin Long out:
7819df2c71ffSXin Long 	return retval;
7820df2c71ffSXin Long }
7821df2c71ffSXin Long 
sctp_getsockopt_auth_supported(struct sock * sk,int len,char __user * optval,int __user * optlen)782256dd525aSXin Long static int sctp_getsockopt_auth_supported(struct sock *sk, int len,
782356dd525aSXin Long 					  char __user *optval,
782456dd525aSXin Long 					  int __user *optlen)
782556dd525aSXin Long {
782656dd525aSXin Long 	struct sctp_assoc_value params;
782756dd525aSXin Long 	struct sctp_association *asoc;
782856dd525aSXin Long 	int retval = -EFAULT;
782956dd525aSXin Long 
783056dd525aSXin Long 	if (len < sizeof(params)) {
783156dd525aSXin Long 		retval = -EINVAL;
783256dd525aSXin Long 		goto out;
783356dd525aSXin Long 	}
783456dd525aSXin Long 
783556dd525aSXin Long 	len = sizeof(params);
783656dd525aSXin Long 	if (copy_from_user(&params, optval, len))
783756dd525aSXin Long 		goto out;
783856dd525aSXin Long 
783956dd525aSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
784056dd525aSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
784156dd525aSXin Long 	    sctp_style(sk, UDP)) {
784256dd525aSXin Long 		retval = -EINVAL;
784356dd525aSXin Long 		goto out;
784456dd525aSXin Long 	}
784556dd525aSXin Long 
784656dd525aSXin Long 	params.assoc_value = asoc ? asoc->peer.auth_capable
784756dd525aSXin Long 				  : sctp_sk(sk)->ep->auth_enable;
784856dd525aSXin Long 
784956dd525aSXin Long 	if (put_user(len, optlen))
785056dd525aSXin Long 		goto out;
785156dd525aSXin Long 
785256dd525aSXin Long 	if (copy_to_user(optval, &params, len))
785356dd525aSXin Long 		goto out;
785456dd525aSXin Long 
785556dd525aSXin Long 	retval = 0;
785656dd525aSXin Long 
785756dd525aSXin Long out:
785856dd525aSXin Long 	return retval;
785956dd525aSXin Long }
786056dd525aSXin Long 
sctp_getsockopt_ecn_supported(struct sock * sk,int len,char __user * optval,int __user * optlen)7861d5886b91SXin Long static int sctp_getsockopt_ecn_supported(struct sock *sk, int len,
7862d5886b91SXin Long 					 char __user *optval,
7863d5886b91SXin Long 					 int __user *optlen)
7864d5886b91SXin Long {
7865d5886b91SXin Long 	struct sctp_assoc_value params;
7866d5886b91SXin Long 	struct sctp_association *asoc;
7867d5886b91SXin Long 	int retval = -EFAULT;
7868d5886b91SXin Long 
7869d5886b91SXin Long 	if (len < sizeof(params)) {
7870d5886b91SXin Long 		retval = -EINVAL;
7871d5886b91SXin Long 		goto out;
7872d5886b91SXin Long 	}
7873d5886b91SXin Long 
7874d5886b91SXin Long 	len = sizeof(params);
7875d5886b91SXin Long 	if (copy_from_user(&params, optval, len))
7876d5886b91SXin Long 		goto out;
7877d5886b91SXin Long 
7878d5886b91SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
7879d5886b91SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
7880d5886b91SXin Long 	    sctp_style(sk, UDP)) {
7881d5886b91SXin Long 		retval = -EINVAL;
7882d5886b91SXin Long 		goto out;
7883d5886b91SXin Long 	}
7884d5886b91SXin Long 
7885d5886b91SXin Long 	params.assoc_value = asoc ? asoc->peer.ecn_capable
7886d5886b91SXin Long 				  : sctp_sk(sk)->ep->ecn_enable;
7887d5886b91SXin Long 
7888d5886b91SXin Long 	if (put_user(len, optlen))
7889d5886b91SXin Long 		goto out;
7890d5886b91SXin Long 
7891d5886b91SXin Long 	if (copy_to_user(optval, &params, len))
7892d5886b91SXin Long 		goto out;
7893d5886b91SXin Long 
7894d5886b91SXin Long 	retval = 0;
7895d5886b91SXin Long 
7896d5886b91SXin Long out:
7897d5886b91SXin Long 	return retval;
7898d5886b91SXin Long }
7899d5886b91SXin Long 
sctp_getsockopt_pf_expose(struct sock * sk,int len,char __user * optval,int __user * optlen)79008d2a6935SXin Long static int sctp_getsockopt_pf_expose(struct sock *sk, int len,
79018d2a6935SXin Long 				     char __user *optval,
79028d2a6935SXin Long 				     int __user *optlen)
79038d2a6935SXin Long {
79048d2a6935SXin Long 	struct sctp_assoc_value params;
79058d2a6935SXin Long 	struct sctp_association *asoc;
79068d2a6935SXin Long 	int retval = -EFAULT;
79078d2a6935SXin Long 
79088d2a6935SXin Long 	if (len < sizeof(params)) {
79098d2a6935SXin Long 		retval = -EINVAL;
79108d2a6935SXin Long 		goto out;
79118d2a6935SXin Long 	}
79128d2a6935SXin Long 
79138d2a6935SXin Long 	len = sizeof(params);
79148d2a6935SXin Long 	if (copy_from_user(&params, optval, len))
79158d2a6935SXin Long 		goto out;
79168d2a6935SXin Long 
79178d2a6935SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
79188d2a6935SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
79198d2a6935SXin Long 	    sctp_style(sk, UDP)) {
79208d2a6935SXin Long 		retval = -EINVAL;
79218d2a6935SXin Long 		goto out;
79228d2a6935SXin Long 	}
79238d2a6935SXin Long 
79248d2a6935SXin Long 	params.assoc_value = asoc ? asoc->pf_expose
79258d2a6935SXin Long 				  : sctp_sk(sk)->pf_expose;
79268d2a6935SXin Long 
79278d2a6935SXin Long 	if (put_user(len, optlen))
79288d2a6935SXin Long 		goto out;
79298d2a6935SXin Long 
79308d2a6935SXin Long 	if (copy_to_user(optval, &params, len))
79318d2a6935SXin Long 		goto out;
79328d2a6935SXin Long 
79338d2a6935SXin Long 	retval = 0;
79348d2a6935SXin Long 
79358d2a6935SXin Long out:
79368d2a6935SXin Long 	return retval;
79378d2a6935SXin Long }
79388d2a6935SXin Long 
sctp_getsockopt_encap_port(struct sock * sk,int len,char __user * optval,int __user * optlen)79398dba2960SXin Long static int sctp_getsockopt_encap_port(struct sock *sk, int len,
79408dba2960SXin Long 				      char __user *optval, int __user *optlen)
79418dba2960SXin Long {
79428dba2960SXin Long 	struct sctp_association *asoc;
79438dba2960SXin Long 	struct sctp_udpencaps encap;
79448dba2960SXin Long 	struct sctp_transport *t;
79458dba2960SXin Long 	__be16 encap_port;
79468dba2960SXin Long 
79478dba2960SXin Long 	if (len < sizeof(encap))
79488dba2960SXin Long 		return -EINVAL;
79498dba2960SXin Long 
79508dba2960SXin Long 	len = sizeof(encap);
79518dba2960SXin Long 	if (copy_from_user(&encap, optval, len))
79528dba2960SXin Long 		return -EFAULT;
79538dba2960SXin Long 
79548dba2960SXin Long 	/* If an address other than INADDR_ANY is specified, and
79558dba2960SXin Long 	 * no transport is found, then the request is invalid.
79568dba2960SXin Long 	 */
79578dba2960SXin Long 	if (!sctp_is_any(sk, (union sctp_addr *)&encap.sue_address)) {
79588dba2960SXin Long 		t = sctp_addr_id2transport(sk, &encap.sue_address,
79598dba2960SXin Long 					   encap.sue_assoc_id);
79608dba2960SXin Long 		if (!t) {
79618dba2960SXin Long 			pr_debug("%s: failed no transport\n", __func__);
79628dba2960SXin Long 			return -EINVAL;
79638dba2960SXin Long 		}
79648dba2960SXin Long 
79658dba2960SXin Long 		encap_port = t->encap_port;
79668dba2960SXin Long 		goto out;
79678dba2960SXin Long 	}
79688dba2960SXin Long 
79698dba2960SXin Long 	/* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the
79708dba2960SXin Long 	 * socket is a one to many style socket, and an association
79718dba2960SXin Long 	 * was not found, then the id was invalid.
79728dba2960SXin Long 	 */
79738dba2960SXin Long 	asoc = sctp_id2assoc(sk, encap.sue_assoc_id);
79748dba2960SXin Long 	if (!asoc && encap.sue_assoc_id != SCTP_FUTURE_ASSOC &&
79758dba2960SXin Long 	    sctp_style(sk, UDP)) {
79768dba2960SXin Long 		pr_debug("%s: failed no association\n", __func__);
79778dba2960SXin Long 		return -EINVAL;
79788dba2960SXin Long 	}
79798dba2960SXin Long 
79808dba2960SXin Long 	if (asoc) {
79818dba2960SXin Long 		encap_port = asoc->encap_port;
79828dba2960SXin Long 		goto out;
79838dba2960SXin Long 	}
79848dba2960SXin Long 
79858dba2960SXin Long 	encap_port = sctp_sk(sk)->encap_port;
79868dba2960SXin Long 
79878dba2960SXin Long out:
79888dba2960SXin Long 	encap.sue_port = (__force uint16_t)encap_port;
79898dba2960SXin Long 	if (copy_to_user(optval, &encap, len))
79908dba2960SXin Long 		return -EFAULT;
79918dba2960SXin Long 
79928dba2960SXin Long 	if (put_user(len, optlen))
79938dba2960SXin Long 		return -EFAULT;
79948dba2960SXin Long 
79958dba2960SXin Long 	return 0;
79968dba2960SXin Long }
79978dba2960SXin Long 
sctp_getsockopt_probe_interval(struct sock * sk,int len,char __user * optval,int __user * optlen)79983190b649SXin Long static int sctp_getsockopt_probe_interval(struct sock *sk, int len,
79993190b649SXin Long 					  char __user *optval,
80003190b649SXin Long 					  int __user *optlen)
80013190b649SXin Long {
80023190b649SXin Long 	struct sctp_probeinterval params;
80033190b649SXin Long 	struct sctp_association *asoc;
80043190b649SXin Long 	struct sctp_transport *t;
80053190b649SXin Long 	__u32 probe_interval;
80063190b649SXin Long 
80073190b649SXin Long 	if (len < sizeof(params))
80083190b649SXin Long 		return -EINVAL;
80093190b649SXin Long 
80103190b649SXin Long 	len = sizeof(params);
80113190b649SXin Long 	if (copy_from_user(&params, optval, len))
80123190b649SXin Long 		return -EFAULT;
80133190b649SXin Long 
80143190b649SXin Long 	/* If an address other than INADDR_ANY is specified, and
80153190b649SXin Long 	 * no transport is found, then the request is invalid.
80163190b649SXin Long 	 */
80173190b649SXin Long 	if (!sctp_is_any(sk, (union sctp_addr *)&params.spi_address)) {
80183190b649SXin Long 		t = sctp_addr_id2transport(sk, &params.spi_address,
80193190b649SXin Long 					   params.spi_assoc_id);
80203190b649SXin Long 		if (!t) {
80213190b649SXin Long 			pr_debug("%s: failed no transport\n", __func__);
80223190b649SXin Long 			return -EINVAL;
80233190b649SXin Long 		}
80243190b649SXin Long 
80253190b649SXin Long 		probe_interval = jiffies_to_msecs(t->probe_interval);
80263190b649SXin Long 		goto out;
80273190b649SXin Long 	}
80283190b649SXin Long 
80293190b649SXin Long 	/* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the
80303190b649SXin Long 	 * socket is a one to many style socket, and an association
80313190b649SXin Long 	 * was not found, then the id was invalid.
80323190b649SXin Long 	 */
80333190b649SXin Long 	asoc = sctp_id2assoc(sk, params.spi_assoc_id);
80343190b649SXin Long 	if (!asoc && params.spi_assoc_id != SCTP_FUTURE_ASSOC &&
80353190b649SXin Long 	    sctp_style(sk, UDP)) {
80363190b649SXin Long 		pr_debug("%s: failed no association\n", __func__);
80373190b649SXin Long 		return -EINVAL;
80383190b649SXin Long 	}
80393190b649SXin Long 
80403190b649SXin Long 	if (asoc) {
80413190b649SXin Long 		probe_interval = jiffies_to_msecs(asoc->probe_interval);
80423190b649SXin Long 		goto out;
80433190b649SXin Long 	}
80443190b649SXin Long 
80453190b649SXin Long 	probe_interval = sctp_sk(sk)->probe_interval;
80463190b649SXin Long 
80473190b649SXin Long out:
80483190b649SXin Long 	params.spi_interval = probe_interval;
80493190b649SXin Long 	if (copy_to_user(optval, &params, len))
80503190b649SXin Long 		return -EFAULT;
80513190b649SXin Long 
80523190b649SXin Long 	if (put_user(len, optlen))
80533190b649SXin Long 		return -EFAULT;
80543190b649SXin Long 
80553190b649SXin Long 	return 0;
80563190b649SXin Long }
80573190b649SXin Long 
sctp_getsockopt(struct sock * sk,int level,int optname,char __user * optval,int __user * optlen)8058dda91928SDaniel Borkmann static int sctp_getsockopt(struct sock *sk, int level, int optname,
80591da177e4SLinus Torvalds 			   char __user *optval, int __user *optlen)
80601da177e4SLinus Torvalds {
80611da177e4SLinus Torvalds 	int retval = 0;
80621da177e4SLinus Torvalds 	int len;
80631da177e4SLinus Torvalds 
8064bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname);
80651da177e4SLinus Torvalds 
80661da177e4SLinus Torvalds 	/* I can hardly begin to describe how wrong this is.  This is
80671da177e4SLinus Torvalds 	 * so broken as to be worse than useless.  The API draft
80681da177e4SLinus Torvalds 	 * REALLY is NOT helpful here...  I am not convinced that the
80691da177e4SLinus Torvalds 	 * semantics of getsockopt() with a level OTHER THAN SOL_SCTP
80701da177e4SLinus Torvalds 	 * are at all well-founded.
80711da177e4SLinus Torvalds 	 */
80721da177e4SLinus Torvalds 	if (level != SOL_SCTP) {
80731da177e4SLinus Torvalds 		struct sctp_af *af = sctp_sk(sk)->pf->af;
80741da177e4SLinus Torvalds 
80751da177e4SLinus Torvalds 		retval = af->getsockopt(sk, level, optname, optval, optlen);
80761da177e4SLinus Torvalds 		return retval;
80771da177e4SLinus Torvalds 	}
80781da177e4SLinus Torvalds 
80791da177e4SLinus Torvalds 	if (get_user(len, optlen))
80801da177e4SLinus Torvalds 		return -EFAULT;
80811da177e4SLinus Torvalds 
8082a4b8e71bSJiri Slaby 	if (len < 0)
8083a4b8e71bSJiri Slaby 		return -EINVAL;
8084a4b8e71bSJiri Slaby 
8085048ed4b6Swangweidong 	lock_sock(sk);
80861da177e4SLinus Torvalds 
80871da177e4SLinus Torvalds 	switch (optname) {
80881da177e4SLinus Torvalds 	case SCTP_STATUS:
80891da177e4SLinus Torvalds 		retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen);
80901da177e4SLinus Torvalds 		break;
80911da177e4SLinus Torvalds 	case SCTP_DISABLE_FRAGMENTS:
80921da177e4SLinus Torvalds 		retval = sctp_getsockopt_disable_fragments(sk, len, optval,
80931da177e4SLinus Torvalds 							   optlen);
80941da177e4SLinus Torvalds 		break;
80951da177e4SLinus Torvalds 	case SCTP_EVENTS:
80961da177e4SLinus Torvalds 		retval = sctp_getsockopt_events(sk, len, optval, optlen);
80971da177e4SLinus Torvalds 		break;
80981da177e4SLinus Torvalds 	case SCTP_AUTOCLOSE:
80991da177e4SLinus Torvalds 		retval = sctp_getsockopt_autoclose(sk, len, optval, optlen);
81001da177e4SLinus Torvalds 		break;
81011da177e4SLinus Torvalds 	case SCTP_SOCKOPT_PEELOFF:
81021da177e4SLinus Torvalds 		retval = sctp_getsockopt_peeloff(sk, len, optval, optlen);
81031da177e4SLinus Torvalds 		break;
81042cb5c8e3SNeil Horman 	case SCTP_SOCKOPT_PEELOFF_FLAGS:
81052cb5c8e3SNeil Horman 		retval = sctp_getsockopt_peeloff_flags(sk, len, optval, optlen);
81062cb5c8e3SNeil Horman 		break;
81071da177e4SLinus Torvalds 	case SCTP_PEER_ADDR_PARAMS:
81081da177e4SLinus Torvalds 		retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
81091da177e4SLinus Torvalds 							  optlen);
81101da177e4SLinus Torvalds 		break;
81114580ccc0SShan Wei 	case SCTP_DELAYED_SACK:
8112d364d927SWei Yongjun 		retval = sctp_getsockopt_delayed_ack(sk, len, optval,
81137708610bSFrank Filz 							  optlen);
81147708610bSFrank Filz 		break;
81151da177e4SLinus Torvalds 	case SCTP_INITMSG:
81161da177e4SLinus Torvalds 		retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
81171da177e4SLinus Torvalds 		break;
81181da177e4SLinus Torvalds 	case SCTP_GET_PEER_ADDRS:
81191da177e4SLinus Torvalds 		retval = sctp_getsockopt_peer_addrs(sk, len, optval,
81201da177e4SLinus Torvalds 						    optlen);
81211da177e4SLinus Torvalds 		break;
81221da177e4SLinus Torvalds 	case SCTP_GET_LOCAL_ADDRS:
81231da177e4SLinus Torvalds 		retval = sctp_getsockopt_local_addrs(sk, len, optval,
81241da177e4SLinus Torvalds 						     optlen);
81251da177e4SLinus Torvalds 		break;
8126c6ba68a2SVlad Yasevich 	case SCTP_SOCKOPT_CONNECTX3:
8127c6ba68a2SVlad Yasevich 		retval = sctp_getsockopt_connectx3(sk, len, optval, optlen);
8128c6ba68a2SVlad Yasevich 		break;
81291da177e4SLinus Torvalds 	case SCTP_DEFAULT_SEND_PARAM:
81301da177e4SLinus Torvalds 		retval = sctp_getsockopt_default_send_param(sk, len,
81311da177e4SLinus Torvalds 							    optval, optlen);
81321da177e4SLinus Torvalds 		break;
81336b3fd5f3SGeir Ola Vaagland 	case SCTP_DEFAULT_SNDINFO:
81346b3fd5f3SGeir Ola Vaagland 		retval = sctp_getsockopt_default_sndinfo(sk, len,
81356b3fd5f3SGeir Ola Vaagland 							 optval, optlen);
81366b3fd5f3SGeir Ola Vaagland 		break;
81371da177e4SLinus Torvalds 	case SCTP_PRIMARY_ADDR:
81381da177e4SLinus Torvalds 		retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen);
81391da177e4SLinus Torvalds 		break;
81401da177e4SLinus Torvalds 	case SCTP_NODELAY:
81411da177e4SLinus Torvalds 		retval = sctp_getsockopt_nodelay(sk, len, optval, optlen);
81421da177e4SLinus Torvalds 		break;
81431da177e4SLinus Torvalds 	case SCTP_RTOINFO:
81441da177e4SLinus Torvalds 		retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen);
81451da177e4SLinus Torvalds 		break;
81461da177e4SLinus Torvalds 	case SCTP_ASSOCINFO:
81471da177e4SLinus Torvalds 		retval = sctp_getsockopt_associnfo(sk, len, optval, optlen);
81481da177e4SLinus Torvalds 		break;
81491da177e4SLinus Torvalds 	case SCTP_I_WANT_MAPPED_V4_ADDR:
81501da177e4SLinus Torvalds 		retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen);
81511da177e4SLinus Torvalds 		break;
81521da177e4SLinus Torvalds 	case SCTP_MAXSEG:
81531da177e4SLinus Torvalds 		retval = sctp_getsockopt_maxseg(sk, len, optval, optlen);
81541da177e4SLinus Torvalds 		break;
81551da177e4SLinus Torvalds 	case SCTP_GET_PEER_ADDR_INFO:
81561da177e4SLinus Torvalds 		retval = sctp_getsockopt_peer_addr_info(sk, len, optval,
81571da177e4SLinus Torvalds 							optlen);
81581da177e4SLinus Torvalds 		break;
81590f3fffd8SIvan Skytte Jorgensen 	case SCTP_ADAPTATION_LAYER:
81600f3fffd8SIvan Skytte Jorgensen 		retval = sctp_getsockopt_adaptation_layer(sk, len, optval,
81611da177e4SLinus Torvalds 							optlen);
81621da177e4SLinus Torvalds 		break;
81636ab792f5SIvan Skytte Jorgensen 	case SCTP_CONTEXT:
81646ab792f5SIvan Skytte Jorgensen 		retval = sctp_getsockopt_context(sk, len, optval, optlen);
81656ab792f5SIvan Skytte Jorgensen 		break;
8166b6e1331fSVlad Yasevich 	case SCTP_FRAGMENT_INTERLEAVE:
8167b6e1331fSVlad Yasevich 		retval = sctp_getsockopt_fragment_interleave(sk, len, optval,
8168b6e1331fSVlad Yasevich 							     optlen);
8169b6e1331fSVlad Yasevich 		break;
8170d49d91d7SVlad Yasevich 	case SCTP_PARTIAL_DELIVERY_POINT:
8171d49d91d7SVlad Yasevich 		retval = sctp_getsockopt_partial_delivery_point(sk, len, optval,
8172d49d91d7SVlad Yasevich 								optlen);
8173d49d91d7SVlad Yasevich 		break;
817470331571SVlad Yasevich 	case SCTP_MAX_BURST:
817570331571SVlad Yasevich 		retval = sctp_getsockopt_maxburst(sk, len, optval, optlen);
817670331571SVlad Yasevich 		break;
817765b07e5dSVlad Yasevich 	case SCTP_AUTH_KEY:
817865b07e5dSVlad Yasevich 	case SCTP_AUTH_CHUNK:
817965b07e5dSVlad Yasevich 	case SCTP_AUTH_DELETE_KEY:
8180601590ecSXin Long 	case SCTP_AUTH_DEACTIVATE_KEY:
818165b07e5dSVlad Yasevich 		retval = -EOPNOTSUPP;
818265b07e5dSVlad Yasevich 		break;
818365b07e5dSVlad Yasevich 	case SCTP_HMAC_IDENT:
818465b07e5dSVlad Yasevich 		retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen);
818565b07e5dSVlad Yasevich 		break;
818665b07e5dSVlad Yasevich 	case SCTP_AUTH_ACTIVE_KEY:
818765b07e5dSVlad Yasevich 		retval = sctp_getsockopt_active_key(sk, len, optval, optlen);
818865b07e5dSVlad Yasevich 		break;
818965b07e5dSVlad Yasevich 	case SCTP_PEER_AUTH_CHUNKS:
819065b07e5dSVlad Yasevich 		retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval,
819165b07e5dSVlad Yasevich 							optlen);
819265b07e5dSVlad Yasevich 		break;
819365b07e5dSVlad Yasevich 	case SCTP_LOCAL_AUTH_CHUNKS:
819465b07e5dSVlad Yasevich 		retval = sctp_getsockopt_local_auth_chunks(sk, len, optval,
819565b07e5dSVlad Yasevich 							optlen);
819665b07e5dSVlad Yasevich 		break;
8197aea3c5c0SWei Yongjun 	case SCTP_GET_ASSOC_NUMBER:
8198aea3c5c0SWei Yongjun 		retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
8199aea3c5c0SWei Yongjun 		break;
8200209ba424SWei Yongjun 	case SCTP_GET_ASSOC_ID_LIST:
8201209ba424SWei Yongjun 		retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen);
8202209ba424SWei Yongjun 		break;
82037dc04d71SMichio Honda 	case SCTP_AUTO_ASCONF:
82047dc04d71SMichio Honda 		retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);
82057dc04d71SMichio Honda 		break;
82065aa93bcfSNeil Horman 	case SCTP_PEER_ADDR_THLDS:
8207d467ac0aSXin Long 		retval = sctp_getsockopt_paddr_thresholds(sk, optval, len,
8208d467ac0aSXin Long 							  optlen, false);
8209d467ac0aSXin Long 		break;
8210d467ac0aSXin Long 	case SCTP_PEER_ADDR_THLDS_V2:
8211d467ac0aSXin Long 		retval = sctp_getsockopt_paddr_thresholds(sk, optval, len,
8212d467ac0aSXin Long 							  optlen, true);
82135aa93bcfSNeil Horman 		break;
8214196d6759SMichele Baldessari 	case SCTP_GET_ASSOC_STATS:
8215196d6759SMichele Baldessari 		retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen);
8216196d6759SMichele Baldessari 		break;
82170d3a421dSGeir Ola Vaagland 	case SCTP_RECVRCVINFO:
82180d3a421dSGeir Ola Vaagland 		retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen);
82190d3a421dSGeir Ola Vaagland 		break;
82202347c80fSGeir Ola Vaagland 	case SCTP_RECVNXTINFO:
82212347c80fSGeir Ola Vaagland 		retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen);
82222347c80fSGeir Ola Vaagland 		break;
822328aa4c26SXin Long 	case SCTP_PR_SUPPORTED:
822428aa4c26SXin Long 		retval = sctp_getsockopt_pr_supported(sk, len, optval, optlen);
822528aa4c26SXin Long 		break;
8226f959fb44SXin Long 	case SCTP_DEFAULT_PRINFO:
8227f959fb44SXin Long 		retval = sctp_getsockopt_default_prinfo(sk, len, optval,
8228f959fb44SXin Long 							optlen);
8229f959fb44SXin Long 		break;
8230826d253dSXin Long 	case SCTP_PR_ASSOC_STATUS:
8231826d253dSXin Long 		retval = sctp_getsockopt_pr_assocstatus(sk, len, optval,
8232826d253dSXin Long 							optlen);
8233826d253dSXin Long 		break;
8234d229d48dSXin Long 	case SCTP_PR_STREAM_STATUS:
8235d229d48dSXin Long 		retval = sctp_getsockopt_pr_streamstatus(sk, len, optval,
8236d229d48dSXin Long 							 optlen);
8237d229d48dSXin Long 		break;
8238c0d8bab6SXin Long 	case SCTP_RECONFIG_SUPPORTED:
8239c0d8bab6SXin Long 		retval = sctp_getsockopt_reconfig_supported(sk, len, optval,
8240c0d8bab6SXin Long 							    optlen);
8241c0d8bab6SXin Long 		break;
82429fb657aeSXin Long 	case SCTP_ENABLE_STREAM_RESET:
82439fb657aeSXin Long 		retval = sctp_getsockopt_enable_strreset(sk, len, optval,
82449fb657aeSXin Long 							 optlen);
82459fb657aeSXin Long 		break;
824613aa8770SMarcelo Ricardo Leitner 	case SCTP_STREAM_SCHEDULER:
824713aa8770SMarcelo Ricardo Leitner 		retval = sctp_getsockopt_scheduler(sk, len, optval,
824813aa8770SMarcelo Ricardo Leitner 						   optlen);
824913aa8770SMarcelo Ricardo Leitner 		break;
82500ccdf3c7SMarcelo Ricardo Leitner 	case SCTP_STREAM_SCHEDULER_VALUE:
82510ccdf3c7SMarcelo Ricardo Leitner 		retval = sctp_getsockopt_scheduler_value(sk, len, optval,
82520ccdf3c7SMarcelo Ricardo Leitner 							 optlen);
82530ccdf3c7SMarcelo Ricardo Leitner 		break;
8254772a5869SXin Long 	case SCTP_INTERLEAVING_SUPPORTED:
8255772a5869SXin Long 		retval = sctp_getsockopt_interleaving_supported(sk, len, optval,
8256772a5869SXin Long 								optlen);
8257772a5869SXin Long 		break;
8258b0e9a2feSXin Long 	case SCTP_REUSE_PORT:
8259b0e9a2feSXin Long 		retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen);
8260b0e9a2feSXin Long 		break;
8261480ba9c1SXin Long 	case SCTP_EVENT:
8262480ba9c1SXin Long 		retval = sctp_getsockopt_event(sk, len, optval, optlen);
8263480ba9c1SXin Long 		break;
8264df2c71ffSXin Long 	case SCTP_ASCONF_SUPPORTED:
8265df2c71ffSXin Long 		retval = sctp_getsockopt_asconf_supported(sk, len, optval,
8266df2c71ffSXin Long 							  optlen);
8267df2c71ffSXin Long 		break;
826856dd525aSXin Long 	case SCTP_AUTH_SUPPORTED:
826956dd525aSXin Long 		retval = sctp_getsockopt_auth_supported(sk, len, optval,
827056dd525aSXin Long 							optlen);
827156dd525aSXin Long 		break;
8272d5886b91SXin Long 	case SCTP_ECN_SUPPORTED:
8273d5886b91SXin Long 		retval = sctp_getsockopt_ecn_supported(sk, len, optval, optlen);
8274d5886b91SXin Long 		break;
82758d2a6935SXin Long 	case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
82768d2a6935SXin Long 		retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen);
82778d2a6935SXin Long 		break;
82788dba2960SXin Long 	case SCTP_REMOTE_UDP_ENCAPS_PORT:
82798dba2960SXin Long 		retval = sctp_getsockopt_encap_port(sk, len, optval, optlen);
82808dba2960SXin Long 		break;
82813190b649SXin Long 	case SCTP_PLPMTUD_PROBE_INTERVAL:
82823190b649SXin Long 		retval = sctp_getsockopt_probe_interval(sk, len, optval, optlen);
82833190b649SXin Long 		break;
82841da177e4SLinus Torvalds 	default:
82851da177e4SLinus Torvalds 		retval = -ENOPROTOOPT;
82861da177e4SLinus Torvalds 		break;
82873ff50b79SStephen Hemminger 	}
82881da177e4SLinus Torvalds 
8289048ed4b6Swangweidong 	release_sock(sk);
82901da177e4SLinus Torvalds 	return retval;
82911da177e4SLinus Torvalds }
82921da177e4SLinus Torvalds 
sctp_bpf_bypass_getsockopt(int level,int optname)82932598619eSAlexander Mikhalitsyn static bool sctp_bpf_bypass_getsockopt(int level, int optname)
82942598619eSAlexander Mikhalitsyn {
82952598619eSAlexander Mikhalitsyn 	if (level == SOL_SCTP) {
82962598619eSAlexander Mikhalitsyn 		switch (optname) {
82972598619eSAlexander Mikhalitsyn 		case SCTP_SOCKOPT_PEELOFF:
82982598619eSAlexander Mikhalitsyn 		case SCTP_SOCKOPT_PEELOFF_FLAGS:
82992598619eSAlexander Mikhalitsyn 		case SCTP_SOCKOPT_CONNECTX3:
83002598619eSAlexander Mikhalitsyn 			return true;
83012598619eSAlexander Mikhalitsyn 		default:
83022598619eSAlexander Mikhalitsyn 			return false;
83032598619eSAlexander Mikhalitsyn 		}
83042598619eSAlexander Mikhalitsyn 	}
83052598619eSAlexander Mikhalitsyn 
83062598619eSAlexander Mikhalitsyn 	return false;
83072598619eSAlexander Mikhalitsyn }
83082598619eSAlexander Mikhalitsyn 
sctp_hash(struct sock * sk)8309086c653fSCraig Gallek static int sctp_hash(struct sock *sk)
83101da177e4SLinus Torvalds {
83111da177e4SLinus Torvalds 	/* STUB */
8312086c653fSCraig Gallek 	return 0;
83131da177e4SLinus Torvalds }
83141da177e4SLinus Torvalds 
sctp_unhash(struct sock * sk)83151da177e4SLinus Torvalds static void sctp_unhash(struct sock *sk)
83161da177e4SLinus Torvalds {
83171da177e4SLinus Torvalds 	/* STUB */
83181da177e4SLinus Torvalds }
83191da177e4SLinus Torvalds 
83201da177e4SLinus Torvalds /* Check if port is acceptable.  Possibly find first available port.
83211da177e4SLinus Torvalds  *
83221da177e4SLinus Torvalds  * The port hash table (contained in the 'global' SCTP protocol storage
83231da177e4SLinus Torvalds  * returned by struct sctp_protocol *sctp_get_protocol()). The hash
83241da177e4SLinus Torvalds  * table is an array of 4096 lists (sctp_bind_hashbucket). Each
83251da177e4SLinus Torvalds  * list (the list number is the port number hashed out, so as you
83261da177e4SLinus Torvalds  * would expect from a hash function, all the ports in a given list have
83271da177e4SLinus Torvalds  * such a number that hashes out to the same list number; you were
83281da177e4SLinus Torvalds  * expecting that, right?); so each list has a set of ports, with a
83291da177e4SLinus Torvalds  * link to the socket (struct sock) that uses it, the port number and
83301da177e4SLinus Torvalds  * a fastreuse flag (FIXME: NPI ipg).
83311da177e4SLinus Torvalds  */
83321da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create(
8333f1f43763SEric W. Biederman 	struct sctp_bind_hashbucket *head, struct net *, unsigned short snum);
83341da177e4SLinus Torvalds 
sctp_get_port_local(struct sock * sk,union sctp_addr * addr)83358e2ef6abSMao Wenan static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
83361da177e4SLinus Torvalds {
83376ba84574SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
83386ba84574SXin Long 	bool reuse = (sk->sk_reuse || sp->reuse);
83391da177e4SLinus Torvalds 	struct sctp_bind_hashbucket *head; /* hash list */
8340fb822388SMaciej Żenczykowski 	struct net *net = sock_net(sk);
83416ba84574SXin Long 	kuid_t uid = sock_i_uid(sk);
8342b67bfe0dSSasha Levin 	struct sctp_bind_bucket *pp;
83431da177e4SLinus Torvalds 	unsigned short snum;
83441da177e4SLinus Torvalds 	int ret;
83451da177e4SLinus Torvalds 
834604afd8b2SAl Viro 	snum = ntohs(addr->v4.sin_port);
83471da177e4SLinus Torvalds 
8348bb33381dSDaniel Borkmann 	pr_debug("%s: begins, snum:%d\n", __func__, snum);
8349bb33381dSDaniel Borkmann 
83501da177e4SLinus Torvalds 	if (snum == 0) {
835106393009SStephen Hemminger 		/* Search for an available port. */
8352227b60f5SStephen Hemminger 		int low, high, remaining, index;
8353227b60f5SStephen Hemminger 		unsigned int rover;
8354227b60f5SStephen Hemminger 
835591d0b78cSJakub Sitnicki 		inet_sk_get_local_port_range(sk, &low, &high);
8356227b60f5SStephen Hemminger 		remaining = (high - low) + 1;
83578032bf12SJason A. Donenfeld 		rover = get_random_u32_below(remaining) + low;
83581da177e4SLinus Torvalds 
83591da177e4SLinus Torvalds 		do {
83601da177e4SLinus Torvalds 			rover++;
83611da177e4SLinus Torvalds 			if ((rover < low) || (rover > high))
83621da177e4SLinus Torvalds 				rover = low;
8363122ff243SWANG Cong 			if (inet_is_local_reserved_port(net, rover))
8364e3826f1eSAmerigo Wang 				continue;
8365fb822388SMaciej Żenczykowski 			index = sctp_phashfn(net, rover);
83661da177e4SLinus Torvalds 			head = &sctp_port_hashtable[index];
83673106ecb4SXin Long 			spin_lock_bh(&head->lock);
8368b67bfe0dSSasha Levin 			sctp_for_each_hentry(pp, &head->chain)
8369f1f43763SEric W. Biederman 				if ((pp->port == rover) &&
8370fb822388SMaciej Żenczykowski 				    net_eq(net, pp->net))
83711da177e4SLinus Torvalds 					goto next;
83721da177e4SLinus Torvalds 			break;
83731da177e4SLinus Torvalds 		next:
83743106ecb4SXin Long 			spin_unlock_bh(&head->lock);
83753106ecb4SXin Long 			cond_resched();
83761da177e4SLinus Torvalds 		} while (--remaining > 0);
83771da177e4SLinus Torvalds 
83781da177e4SLinus Torvalds 		/* Exhausted local port range during search? */
83791da177e4SLinus Torvalds 		ret = 1;
83801da177e4SLinus Torvalds 		if (remaining <= 0)
83813106ecb4SXin Long 			return ret;
83821da177e4SLinus Torvalds 
83831da177e4SLinus Torvalds 		/* OK, here is the one we will use.  HEAD (the port
83841da177e4SLinus Torvalds 		 * hash table list entry) is non-NULL and we hold it's
83851da177e4SLinus Torvalds 		 * mutex.
83861da177e4SLinus Torvalds 		 */
83871da177e4SLinus Torvalds 		snum = rover;
83881da177e4SLinus Torvalds 	} else {
83891da177e4SLinus Torvalds 		/* We are given an specific port number; we verify
83901da177e4SLinus Torvalds 		 * that it is not being used. If it is used, we will
83911da177e4SLinus Torvalds 		 * exahust the search in the hash list corresponding
83921da177e4SLinus Torvalds 		 * to the port number (snum) - we detect that with the
83931da177e4SLinus Torvalds 		 * port iterator, pp being NULL.
83941da177e4SLinus Torvalds 		 */
8395fb822388SMaciej Żenczykowski 		head = &sctp_port_hashtable[sctp_phashfn(net, snum)];
83963106ecb4SXin Long 		spin_lock_bh(&head->lock);
8397b67bfe0dSSasha Levin 		sctp_for_each_hentry(pp, &head->chain) {
8398fb822388SMaciej Żenczykowski 			if ((pp->port == snum) && net_eq(pp->net, net))
83991da177e4SLinus Torvalds 				goto pp_found;
84001da177e4SLinus Torvalds 		}
84011da177e4SLinus Torvalds 	}
84021da177e4SLinus Torvalds 	pp = NULL;
84031da177e4SLinus Torvalds 	goto pp_not_found;
84041da177e4SLinus Torvalds pp_found:
84051da177e4SLinus Torvalds 	if (!hlist_empty(&pp->owner)) {
84061da177e4SLinus Torvalds 		/* We had a port hash table hit - there is an
84071da177e4SLinus Torvalds 		 * available port (pp != NULL) and it is being
84081da177e4SLinus Torvalds 		 * used by other socket (pp->owner not empty); that other
84091da177e4SLinus Torvalds 		 * socket is going to be sk2.
84101da177e4SLinus Torvalds 		 */
84111da177e4SLinus Torvalds 		struct sock *sk2;
84121da177e4SLinus Torvalds 
8413bb33381dSDaniel Borkmann 		pr_debug("%s: found a possible match\n", __func__);
8414bb33381dSDaniel Borkmann 
84156ba84574SXin Long 		if ((pp->fastreuse && reuse &&
84166ba84574SXin Long 		     sk->sk_state != SCTP_SS_LISTENING) ||
84176ba84574SXin Long 		    (pp->fastreuseport && sk->sk_reuseport &&
84186ba84574SXin Long 		     uid_eq(pp->fastuid, uid)))
84191da177e4SLinus Torvalds 			goto success;
84201da177e4SLinus Torvalds 
84211da177e4SLinus Torvalds 		/* Run through the list of sockets bound to the port
84221da177e4SLinus Torvalds 		 * (pp->port) [via the pointers bind_next and
84231da177e4SLinus Torvalds 		 * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one,
84241da177e4SLinus Torvalds 		 * we get the endpoint they describe and run through
84251da177e4SLinus Torvalds 		 * the endpoint's list of IP (v4 or v6) addresses,
84261da177e4SLinus Torvalds 		 * comparing each of the addresses with the address of
84271da177e4SLinus Torvalds 		 * the socket sk. If we find a match, then that means
84281da177e4SLinus Torvalds 		 * that this port/socket (sk) combination are already
84291da177e4SLinus Torvalds 		 * in an endpoint.
84301da177e4SLinus Torvalds 		 */
8431b67bfe0dSSasha Levin 		sk_for_each_bound(sk2, &pp->owner) {
8432f87b1ac0SXin Long 			int bound_dev_if2 = READ_ONCE(sk2->sk_bound_dev_if);
84336ba84574SXin Long 			struct sctp_sock *sp2 = sctp_sk(sk2);
84346ba84574SXin Long 			struct sctp_endpoint *ep2 = sp2->ep;
84351da177e4SLinus Torvalds 
84364e54064eSVlad Yasevich 			if (sk == sk2 ||
84376ba84574SXin Long 			    (reuse && (sk2->sk_reuse || sp2->reuse) &&
84386ba84574SXin Long 			     sk2->sk_state != SCTP_SS_LISTENING) ||
84396ba84574SXin Long 			    (sk->sk_reuseport && sk2->sk_reuseport &&
84406ba84574SXin Long 			     uid_eq(uid, sock_i_uid(sk2))))
84411da177e4SLinus Torvalds 				continue;
84421da177e4SLinus Torvalds 
8443f87b1ac0SXin Long 			if ((!sk->sk_bound_dev_if || !bound_dev_if2 ||
8444f87b1ac0SXin Long 			     sk->sk_bound_dev_if == bound_dev_if2) &&
8445f87b1ac0SXin Long 			    sctp_bind_addr_conflict(&ep2->base.bind_addr,
84466ba84574SXin Long 						    addr, sp2, sp)) {
84478e2ef6abSMao Wenan 				ret = 1;
84481da177e4SLinus Torvalds 				goto fail_unlock;
84491da177e4SLinus Torvalds 			}
84501da177e4SLinus Torvalds 		}
8451bb33381dSDaniel Borkmann 
8452bb33381dSDaniel Borkmann 		pr_debug("%s: found a match\n", __func__);
84531da177e4SLinus Torvalds 	}
84541da177e4SLinus Torvalds pp_not_found:
84551da177e4SLinus Torvalds 	/* If there was a hash table miss, create a new port.  */
84561da177e4SLinus Torvalds 	ret = 1;
8457fb822388SMaciej Żenczykowski 	if (!pp && !(pp = sctp_bucket_create(head, net, snum)))
84581da177e4SLinus Torvalds 		goto fail_unlock;
84591da177e4SLinus Torvalds 
84601da177e4SLinus Torvalds 	/* In either case (hit or miss), make sure fastreuse is 1 only
84611da177e4SLinus Torvalds 	 * if sk->sk_reuse is too (that is, if the caller requested
84621da177e4SLinus Torvalds 	 * SO_REUSEADDR on this socket -sk-).
84631da177e4SLinus Torvalds 	 */
8464ce5325c1SVlad Yasevich 	if (hlist_empty(&pp->owner)) {
8465b0e9a2feSXin Long 		if (reuse && sk->sk_state != SCTP_SS_LISTENING)
8466ce5325c1SVlad Yasevich 			pp->fastreuse = 1;
8467ce5325c1SVlad Yasevich 		else
8468ce5325c1SVlad Yasevich 			pp->fastreuse = 0;
84696ba84574SXin Long 
84706ba84574SXin Long 		if (sk->sk_reuseport) {
84716ba84574SXin Long 			pp->fastreuseport = 1;
84726ba84574SXin Long 			pp->fastuid = uid;
84736ba84574SXin Long 		} else {
84746ba84574SXin Long 			pp->fastreuseport = 0;
84756ba84574SXin Long 		}
84766ba84574SXin Long 	} else {
84776ba84574SXin Long 		if (pp->fastreuse &&
8478b0e9a2feSXin Long 		    (!reuse || sk->sk_state == SCTP_SS_LISTENING))
84791da177e4SLinus Torvalds 			pp->fastreuse = 0;
84801da177e4SLinus Torvalds 
84816ba84574SXin Long 		if (pp->fastreuseport &&
84826ba84574SXin Long 		    (!sk->sk_reuseport || !uid_eq(pp->fastuid, uid)))
84836ba84574SXin Long 			pp->fastreuseport = 0;
84846ba84574SXin Long 	}
84856ba84574SXin Long 
84861da177e4SLinus Torvalds 	/* We are set, so fill up all the data in the hash table
84871da177e4SLinus Torvalds 	 * entry, tie the socket list information with the rest of the
84881da177e4SLinus Torvalds 	 * sockets FIXME: Blurry, NPI (ipg).
84891da177e4SLinus Torvalds 	 */
84901da177e4SLinus Torvalds success:
84916ba84574SXin Long 	if (!sp->bind_hash) {
8492c720c7e8SEric Dumazet 		inet_sk(sk)->inet_num = snum;
84931da177e4SLinus Torvalds 		sk_add_bind_node(sk, &pp->owner);
84946ba84574SXin Long 		sp->bind_hash = pp;
84951da177e4SLinus Torvalds 	}
84961da177e4SLinus Torvalds 	ret = 0;
84971da177e4SLinus Torvalds 
84981da177e4SLinus Torvalds fail_unlock:
84993106ecb4SXin Long 	spin_unlock_bh(&head->lock);
85001da177e4SLinus Torvalds 	return ret;
85011da177e4SLinus Torvalds }
85021da177e4SLinus Torvalds 
85031da177e4SLinus Torvalds /* Assign a 'snum' port to the socket.  If snum == 0, an ephemeral
85041da177e4SLinus Torvalds  * port is requested.
85051da177e4SLinus Torvalds  */
sctp_get_port(struct sock * sk,unsigned short snum)85061da177e4SLinus Torvalds static int sctp_get_port(struct sock *sk, unsigned short snum)
85071da177e4SLinus Torvalds {
85081da177e4SLinus Torvalds 	union sctp_addr addr;
85091da177e4SLinus Torvalds 	struct sctp_af *af = sctp_sk(sk)->pf->af;
85101da177e4SLinus Torvalds 
85111da177e4SLinus Torvalds 	/* Set up a dummy address struct from the sk. */
85121da177e4SLinus Torvalds 	af->from_sk(&addr, sk);
85131da177e4SLinus Torvalds 	addr.v4.sin_port = htons(snum);
85141da177e4SLinus Torvalds 
85151da177e4SLinus Torvalds 	/* Note: sk->sk_num gets filled in if ephemeral port request. */
85168e2ef6abSMao Wenan 	return sctp_get_port_local(sk, &addr);
85171da177e4SLinus Torvalds }
85181da177e4SLinus Torvalds 
85191da177e4SLinus Torvalds /*
85201da177e4SLinus Torvalds  *  Move a socket to LISTENING state.
85211da177e4SLinus Torvalds  */
sctp_listen_start(struct sock * sk,int backlog)8522dda91928SDaniel Borkmann static int sctp_listen_start(struct sock *sk, int backlog)
85231da177e4SLinus Torvalds {
85245e8f3f70SVlad Yasevich 	struct sctp_sock *sp = sctp_sk(sk);
85255e8f3f70SVlad Yasevich 	struct sctp_endpoint *ep = sp->ep;
85265821c769SHerbert Xu 	struct crypto_shash *tfm = NULL;
85273c68198eSNeil Horman 	char alg[32];
8528*b4ff0116SXin Long 	int err;
85291da177e4SLinus Torvalds 
85301da177e4SLinus Torvalds 	/* Allocate HMAC for generating cookie. */
85313c68198eSNeil Horman 	if (!sp->hmac && sp->sctp_hmac_alg) {
85323c68198eSNeil Horman 		sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg);
85335821c769SHerbert Xu 		tfm = crypto_alloc_shash(alg, 0, 0);
85348dc4984aSVlad Yasevich 		if (IS_ERR(tfm)) {
8535e87cc472SJoe Perches 			net_info_ratelimited("failed to load transform for %s: %ld\n",
85363c68198eSNeil Horman 					     sp->sctp_hmac_alg, PTR_ERR(tfm));
85375e8f3f70SVlad Yasevich 			return -ENOSYS;
85385e8f3f70SVlad Yasevich 		}
85395e8f3f70SVlad Yasevich 		sctp_sk(sk)->hmac = tfm;
85405e8f3f70SVlad Yasevich 	}
85415e8f3f70SVlad Yasevich 
85425e8f3f70SVlad Yasevich 	/*
85435e8f3f70SVlad Yasevich 	 * If a bind() or sctp_bindx() is not called prior to a listen()
85445e8f3f70SVlad Yasevich 	 * call that allows new associations to be accepted, the system
85455e8f3f70SVlad Yasevich 	 * picks an ephemeral port and will choose an address set equivalent
85465e8f3f70SVlad Yasevich 	 * to binding with a wildcard address.
85475e8f3f70SVlad Yasevich 	 *
85485e8f3f70SVlad Yasevich 	 * This is not currently spelled out in the SCTP sockets
85495e8f3f70SVlad Yasevich 	 * extensions draft, but follows the practice as seen in TCP
85505e8f3f70SVlad Yasevich 	 * sockets.
85515e8f3f70SVlad Yasevich 	 *
85525e8f3f70SVlad Yasevich 	 */
8553cbabf463SYafang Shao 	inet_sk_set_state(sk, SCTP_SS_LISTENING);
85545e8f3f70SVlad Yasevich 	if (!ep->base.bind_addr.port) {
85557f64cb5bSXin Long 		if (sctp_autobind(sk)) {
8556*b4ff0116SXin Long 			err = -EAGAIN;
8557*b4ff0116SXin Long 			goto err;
85587f64cb5bSXin Long 		}
85595e8f3f70SVlad Yasevich 	} else {
8560c720c7e8SEric Dumazet 		if (sctp_get_port(sk, inet_sk(sk)->inet_num)) {
8561*b4ff0116SXin Long 			err = -EADDRINUSE;
8562*b4ff0116SXin Long 			goto err;
85635e8f3f70SVlad Yasevich 		}
85645e8f3f70SVlad Yasevich 	}
85655e8f3f70SVlad Yasevich 
8566099ecf59SEric Dumazet 	WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
8567*b4ff0116SXin Long 	err = sctp_hash_endpoint(ep);
8568*b4ff0116SXin Long 	if (err)
8569*b4ff0116SXin Long 		goto err;
8570*b4ff0116SXin Long 
8571*b4ff0116SXin Long 	return 0;
8572*b4ff0116SXin Long err:
8573*b4ff0116SXin Long 	inet_sk_set_state(sk, SCTP_SS_CLOSED);
8574*b4ff0116SXin Long 	return err;
85755e8f3f70SVlad Yasevich }
85765e8f3f70SVlad Yasevich 
85775e8f3f70SVlad Yasevich /*
85785e8f3f70SVlad Yasevich  * 4.1.3 / 5.1.3 listen()
85795e8f3f70SVlad Yasevich  *
85805e8f3f70SVlad Yasevich  *   By default, new associations are not accepted for UDP style sockets.
85815e8f3f70SVlad Yasevich  *   An application uses listen() to mark a socket as being able to
85825e8f3f70SVlad Yasevich  *   accept new associations.
85835e8f3f70SVlad Yasevich  *
85845e8f3f70SVlad Yasevich  *   On TCP style sockets, applications use listen() to ready the SCTP
85855e8f3f70SVlad Yasevich  *   endpoint for accepting inbound associations.
85865e8f3f70SVlad Yasevich  *
85875e8f3f70SVlad Yasevich  *   On both types of endpoints a backlog of '0' disables listening.
85885e8f3f70SVlad Yasevich  *
85895e8f3f70SVlad Yasevich  *  Move a socket to LISTENING state.
85905e8f3f70SVlad Yasevich  */
sctp_inet_listen(struct socket * sock,int backlog)85915e8f3f70SVlad Yasevich int sctp_inet_listen(struct socket *sock, int backlog)
85925e8f3f70SVlad Yasevich {
85935e8f3f70SVlad Yasevich 	struct sock *sk = sock->sk;
85945e8f3f70SVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
85955e8f3f70SVlad Yasevich 	int err = -EINVAL;
85965e8f3f70SVlad Yasevich 
85975e8f3f70SVlad Yasevich 	if (unlikely(backlog < 0))
85985e8f3f70SVlad Yasevich 		return err;
85995e8f3f70SVlad Yasevich 
8600048ed4b6Swangweidong 	lock_sock(sk);
86015e8f3f70SVlad Yasevich 
86025e8f3f70SVlad Yasevich 	/* Peeled-off sockets are not allowed to listen().  */
86035e8f3f70SVlad Yasevich 	if (sctp_style(sk, UDP_HIGH_BANDWIDTH))
86045e8f3f70SVlad Yasevich 		goto out;
86055e8f3f70SVlad Yasevich 
86065e8f3f70SVlad Yasevich 	if (sock->state != SS_UNCONNECTED)
86075e8f3f70SVlad Yasevich 		goto out;
86085e8f3f70SVlad Yasevich 
860934b2789fSXin Long 	if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED))
861034b2789fSXin Long 		goto out;
861134b2789fSXin Long 
86125e8f3f70SVlad Yasevich 	/* If backlog is zero, disable listening. */
86135e8f3f70SVlad Yasevich 	if (!backlog) {
86145e8f3f70SVlad Yasevich 		if (sctp_sstate(sk, CLOSED))
86155e8f3f70SVlad Yasevich 			goto out;
86165e8f3f70SVlad Yasevich 
86175e8f3f70SVlad Yasevich 		err = 0;
86185e8f3f70SVlad Yasevich 		sctp_unhash_endpoint(ep);
86195e8f3f70SVlad Yasevich 		sk->sk_state = SCTP_SS_CLOSED;
8620b0e9a2feSXin Long 		if (sk->sk_reuse || sctp_sk(sk)->reuse)
86215e8f3f70SVlad Yasevich 			sctp_sk(sk)->bind_hash->fastreuse = 1;
86221da177e4SLinus Torvalds 		goto out;
86231da177e4SLinus Torvalds 	}
86241da177e4SLinus Torvalds 
86255e8f3f70SVlad Yasevich 	/* If we are already listening, just update the backlog */
86265e8f3f70SVlad Yasevich 	if (sctp_sstate(sk, LISTENING))
8627099ecf59SEric Dumazet 		WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
86285e8f3f70SVlad Yasevich 	else {
86295e8f3f70SVlad Yasevich 		err = sctp_listen_start(sk, backlog);
86301da177e4SLinus Torvalds 		if (err)
86315e8f3f70SVlad Yasevich 			goto out;
86325e8f3f70SVlad Yasevich 	}
86331da177e4SLinus Torvalds 
86345e8f3f70SVlad Yasevich 	err = 0;
86351da177e4SLinus Torvalds out:
8636048ed4b6Swangweidong 	release_sock(sk);
86371da177e4SLinus Torvalds 	return err;
86381da177e4SLinus Torvalds }
86391da177e4SLinus Torvalds 
86401da177e4SLinus Torvalds /*
86411da177e4SLinus Torvalds  * This function is done by modeling the current datagram_poll() and the
86421da177e4SLinus Torvalds  * tcp_poll().  Note that, based on these implementations, we don't
86431da177e4SLinus Torvalds  * lock the socket in this function, even though it seems that,
86441da177e4SLinus Torvalds  * ideally, locking or some other mechanisms can be used to ensure
86459bffc4acSNeil Horman  * the integrity of the counters (sndbuf and wmem_alloc) used
86461da177e4SLinus Torvalds  * in this place.  We assume that we don't need locks either until proven
86471da177e4SLinus Torvalds  * otherwise.
86481da177e4SLinus Torvalds  *
86491da177e4SLinus Torvalds  * Another thing to note is that we include the Async I/O support
86501da177e4SLinus Torvalds  * here, again, by modeling the current TCP/UDP code.  We don't have
86511da177e4SLinus Torvalds  * a good way to test with it yet.
86521da177e4SLinus Torvalds  */
sctp_poll(struct file * file,struct socket * sock,poll_table * wait)8653a11e1d43SLinus Torvalds __poll_t sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
86541da177e4SLinus Torvalds {
86551da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
86561da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
8657ade994f4SAl Viro 	__poll_t mask;
86581da177e4SLinus Torvalds 
8659a11e1d43SLinus Torvalds 	poll_wait(file, sk_sleep(sk), wait);
8660a11e1d43SLinus Torvalds 
8661486bdee0SMarcelo Ricardo Leitner 	sock_rps_record_flow(sk);
8662486bdee0SMarcelo Ricardo Leitner 
86631da177e4SLinus Torvalds 	/* A TCP-style listening socket becomes readable when the accept queue
86641da177e4SLinus Torvalds 	 * is not empty.
86651da177e4SLinus Torvalds 	 */
86661da177e4SLinus Torvalds 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
86671da177e4SLinus Torvalds 		return (!list_empty(&sp->ep->asocs)) ?
8668a9a08845SLinus Torvalds 			(EPOLLIN | EPOLLRDNORM) : 0;
86691da177e4SLinus Torvalds 
86701da177e4SLinus Torvalds 	mask = 0;
86711da177e4SLinus Torvalds 
86721da177e4SLinus Torvalds 	/* Is there any exceptional events?  */
86733ef7cf57SEric Dumazet 	if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
8674a9a08845SLinus Torvalds 		mask |= EPOLLERR |
8675a9a08845SLinus Torvalds 			(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0);
8676f348d70aSDavide Libenzi 	if (sk->sk_shutdown & RCV_SHUTDOWN)
8677a9a08845SLinus Torvalds 		mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM;
86781da177e4SLinus Torvalds 	if (sk->sk_shutdown == SHUTDOWN_MASK)
8679a9a08845SLinus Torvalds 		mask |= EPOLLHUP;
86801da177e4SLinus Torvalds 
86811da177e4SLinus Torvalds 	/* Is it readable?  Reconsider this code with TCP-style support.  */
86823ef7cf57SEric Dumazet 	if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
8683a9a08845SLinus Torvalds 		mask |= EPOLLIN | EPOLLRDNORM;
86841da177e4SLinus Torvalds 
86851da177e4SLinus Torvalds 	/* The association is either gone or not ready.  */
86861da177e4SLinus Torvalds 	if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED))
86871da177e4SLinus Torvalds 		return mask;
86881da177e4SLinus Torvalds 
86891da177e4SLinus Torvalds 	/* Is it writable?  */
86901da177e4SLinus Torvalds 	if (sctp_writeable(sk)) {
8691a9a08845SLinus Torvalds 		mask |= EPOLLOUT | EPOLLWRNORM;
86921da177e4SLinus Torvalds 	} else {
86939cd3e072SEric Dumazet 		sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
86941da177e4SLinus Torvalds 		/*
86951da177e4SLinus Torvalds 		 * Since the socket is not locked, the buffer
86961da177e4SLinus Torvalds 		 * might be made available after the writeable check and
86971da177e4SLinus Torvalds 		 * before the bit is set.  This could cause a lost I/O
86981da177e4SLinus Torvalds 		 * signal.  tcp_poll() has a race breaker for this race
86991da177e4SLinus Torvalds 		 * condition.  Based on their implementation, we put
87001da177e4SLinus Torvalds 		 * in the following code to cover it as well.
87011da177e4SLinus Torvalds 		 */
87021da177e4SLinus Torvalds 		if (sctp_writeable(sk))
8703a9a08845SLinus Torvalds 			mask |= EPOLLOUT | EPOLLWRNORM;
87041da177e4SLinus Torvalds 	}
87051da177e4SLinus Torvalds 	return mask;
87061da177e4SLinus Torvalds }
87071da177e4SLinus Torvalds 
87081da177e4SLinus Torvalds /********************************************************************
87091da177e4SLinus Torvalds  * 2nd Level Abstractions
87101da177e4SLinus Torvalds  ********************************************************************/
87111da177e4SLinus Torvalds 
sctp_bucket_create(struct sctp_bind_hashbucket * head,struct net * net,unsigned short snum)87121da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create(
8713f1f43763SEric W. Biederman 	struct sctp_bind_hashbucket *head, struct net *net, unsigned short snum)
87141da177e4SLinus Torvalds {
87151da177e4SLinus Torvalds 	struct sctp_bind_bucket *pp;
87161da177e4SLinus Torvalds 
871754e6ecb2SChristoph Lameter 	pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC);
87181da177e4SLinus Torvalds 	if (pp) {
8719935a7f6eSLi Zefan 		SCTP_DBG_OBJCNT_INC(bind_bucket);
87201da177e4SLinus Torvalds 		pp->port = snum;
87211da177e4SLinus Torvalds 		pp->fastreuse = 0;
87221da177e4SLinus Torvalds 		INIT_HLIST_HEAD(&pp->owner);
8723f1f43763SEric W. Biederman 		pp->net = net;
8724d970dbf8SVlad Yasevich 		hlist_add_head(&pp->node, &head->chain);
87251da177e4SLinus Torvalds 	}
87261da177e4SLinus Torvalds 	return pp;
87271da177e4SLinus Torvalds }
87281da177e4SLinus Torvalds 
87291da177e4SLinus Torvalds /* Caller must hold hashbucket lock for this tb with local BH disabled */
sctp_bucket_destroy(struct sctp_bind_bucket * pp)87301da177e4SLinus Torvalds static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
87311da177e4SLinus Torvalds {
873237fa6878SSridhar Samudrala 	if (pp && hlist_empty(&pp->owner)) {
8733d970dbf8SVlad Yasevich 		__hlist_del(&pp->node);
87341da177e4SLinus Torvalds 		kmem_cache_free(sctp_bucket_cachep, pp);
87351da177e4SLinus Torvalds 		SCTP_DBG_OBJCNT_DEC(bind_bucket);
87361da177e4SLinus Torvalds 	}
87371da177e4SLinus Torvalds }
87381da177e4SLinus Torvalds 
87391da177e4SLinus Torvalds /* Release this socket's reference to a local port.  */
__sctp_put_port(struct sock * sk)87401da177e4SLinus Torvalds static inline void __sctp_put_port(struct sock *sk)
87411da177e4SLinus Torvalds {
87421da177e4SLinus Torvalds 	struct sctp_bind_hashbucket *head =
8743f1f43763SEric W. Biederman 		&sctp_port_hashtable[sctp_phashfn(sock_net(sk),
8744f1f43763SEric W. Biederman 						  inet_sk(sk)->inet_num)];
87451da177e4SLinus Torvalds 	struct sctp_bind_bucket *pp;
87461da177e4SLinus Torvalds 
87473c8e43baSwangweidong 	spin_lock(&head->lock);
87481da177e4SLinus Torvalds 	pp = sctp_sk(sk)->bind_hash;
87491da177e4SLinus Torvalds 	__sk_del_bind_node(sk);
87501da177e4SLinus Torvalds 	sctp_sk(sk)->bind_hash = NULL;
8751c720c7e8SEric Dumazet 	inet_sk(sk)->inet_num = 0;
87521da177e4SLinus Torvalds 	sctp_bucket_destroy(pp);
87533c8e43baSwangweidong 	spin_unlock(&head->lock);
87541da177e4SLinus Torvalds }
87551da177e4SLinus Torvalds 
sctp_put_port(struct sock * sk)87561da177e4SLinus Torvalds void sctp_put_port(struct sock *sk)
87571da177e4SLinus Torvalds {
875879b91130Swangweidong 	local_bh_disable();
87591da177e4SLinus Torvalds 	__sctp_put_port(sk);
876079b91130Swangweidong 	local_bh_enable();
87611da177e4SLinus Torvalds }
87621da177e4SLinus Torvalds 
87631da177e4SLinus Torvalds /*
87641da177e4SLinus Torvalds  * The system picks an ephemeral port and choose an address set equivalent
87651da177e4SLinus Torvalds  * to binding with a wildcard address.
87661da177e4SLinus Torvalds  * One of those addresses will be the primary address for the association.
87671da177e4SLinus Torvalds  * This automatically enables the multihoming capability of SCTP.
87681da177e4SLinus Torvalds  */
sctp_autobind(struct sock * sk)87691da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk)
87701da177e4SLinus Torvalds {
87711da177e4SLinus Torvalds 	union sctp_addr autoaddr;
87721da177e4SLinus Torvalds 	struct sctp_af *af;
87736fbfa9f9SAl Viro 	__be16 port;
87741da177e4SLinus Torvalds 
87751da177e4SLinus Torvalds 	/* Initialize a local sockaddr structure to INADDR_ANY. */
87761da177e4SLinus Torvalds 	af = sctp_sk(sk)->pf->af;
87771da177e4SLinus Torvalds 
8778c720c7e8SEric Dumazet 	port = htons(inet_sk(sk)->inet_num);
87791da177e4SLinus Torvalds 	af->inaddr_any(&autoaddr, port);
87801da177e4SLinus Torvalds 
87811da177e4SLinus Torvalds 	return sctp_do_bind(sk, &autoaddr, af->sockaddr_len);
87821da177e4SLinus Torvalds }
87831da177e4SLinus Torvalds 
87841da177e4SLinus Torvalds /* Parse out IPPROTO_SCTP CMSG headers.  Perform only minimal validation.
87851da177e4SLinus Torvalds  *
87861da177e4SLinus Torvalds  * From RFC 2292
87871da177e4SLinus Torvalds  * 4.2 The cmsghdr Structure *
87881da177e4SLinus Torvalds  *
87891da177e4SLinus Torvalds  * When ancillary data is sent or received, any number of ancillary data
87901da177e4SLinus Torvalds  * objects can be specified by the msg_control and msg_controllen members of
87911da177e4SLinus Torvalds  * the msghdr structure, because each object is preceded by
87921da177e4SLinus Torvalds  * a cmsghdr structure defining the object's length (the cmsg_len member).
87931da177e4SLinus Torvalds  * Historically Berkeley-derived implementations have passed only one object
87941da177e4SLinus Torvalds  * at a time, but this API allows multiple objects to be
87951da177e4SLinus Torvalds  * passed in a single call to sendmsg() or recvmsg(). The following example
87961da177e4SLinus Torvalds  * shows two ancillary data objects in a control buffer.
87971da177e4SLinus Torvalds  *
87981da177e4SLinus Torvalds  *   |<--------------------------- msg_controllen -------------------------->|
87991da177e4SLinus Torvalds  *   |                                                                       |
88001da177e4SLinus Torvalds  *
88011da177e4SLinus Torvalds  *   |<----- ancillary data object ----->|<----- ancillary data object ----->|
88021da177e4SLinus Torvalds  *
88031da177e4SLinus Torvalds  *   |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->|
88041da177e4SLinus Torvalds  *   |                                   |                                   |
88051da177e4SLinus Torvalds  *
88061da177e4SLinus Torvalds  *   |<---------- cmsg_len ---------->|  |<--------- cmsg_len ----------->|  |
88071da177e4SLinus Torvalds  *
88081da177e4SLinus Torvalds  *   |<--------- CMSG_LEN() --------->|  |<-------- CMSG_LEN() ---------->|  |
88091da177e4SLinus Torvalds  *   |                                |  |                                |  |
88101da177e4SLinus Torvalds  *
88111da177e4SLinus Torvalds  *   +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+
88121da177e4SLinus Torvalds  *   |cmsg_|cmsg_|cmsg_|XX|           |XX|cmsg_|cmsg_|cmsg_|XX|           |XX|
88131da177e4SLinus Torvalds  *
88141da177e4SLinus Torvalds  *   |len  |level|type |XX|cmsg_data[]|XX|len  |level|type |XX|cmsg_data[]|XX|
88151da177e4SLinus Torvalds  *
88161da177e4SLinus Torvalds  *   +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+
88171da177e4SLinus Torvalds  *    ^
88181da177e4SLinus Torvalds  *    |
88191da177e4SLinus Torvalds  *
88201da177e4SLinus Torvalds  * msg_control
88211da177e4SLinus Torvalds  * points here
88221da177e4SLinus Torvalds  */
sctp_msghdr_parse(const struct msghdr * msg,struct sctp_cmsgs * cmsgs)8823a05437acSXin Long static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
88241da177e4SLinus Torvalds {
8825ab38fb04SVlad Yasevich 	struct msghdr *my_msg = (struct msghdr *)msg;
8826a05437acSXin Long 	struct cmsghdr *cmsg;
88271da177e4SLinus Torvalds 
8828f95b414eSGu Zheng 	for_each_cmsghdr(cmsg, my_msg) {
8829ab38fb04SVlad Yasevich 		if (!CMSG_OK(my_msg, cmsg))
88301da177e4SLinus Torvalds 			return -EINVAL;
88311da177e4SLinus Torvalds 
88321da177e4SLinus Torvalds 		/* Should we parse this header or ignore?  */
88331da177e4SLinus Torvalds 		if (cmsg->cmsg_level != IPPROTO_SCTP)
88341da177e4SLinus Torvalds 			continue;
88351da177e4SLinus Torvalds 
88361da177e4SLinus Torvalds 		/* Strictly check lengths following example in SCM code.  */
88371da177e4SLinus Torvalds 		switch (cmsg->cmsg_type) {
88381da177e4SLinus Torvalds 		case SCTP_INIT:
88391da177e4SLinus Torvalds 			/* SCTP Socket API Extension
884063b94938SGeir Ola Vaagland 			 * 5.3.1 SCTP Initiation Structure (SCTP_INIT)
88411da177e4SLinus Torvalds 			 *
88421da177e4SLinus Torvalds 			 * This cmsghdr structure provides information for
88431da177e4SLinus Torvalds 			 * initializing new SCTP associations with sendmsg().
88441da177e4SLinus Torvalds 			 * The SCTP_INITMSG socket option uses this same data
88451da177e4SLinus Torvalds 			 * structure.  This structure is not used for
88461da177e4SLinus Torvalds 			 * recvmsg().
88471da177e4SLinus Torvalds 			 *
88481da177e4SLinus Torvalds 			 * cmsg_level    cmsg_type      cmsg_data[]
88491da177e4SLinus Torvalds 			 * ------------  ------------   ----------------------
88501da177e4SLinus Torvalds 			 * IPPROTO_SCTP  SCTP_INIT      struct sctp_initmsg
88511da177e4SLinus Torvalds 			 */
885263b94938SGeir Ola Vaagland 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg)))
88531da177e4SLinus Torvalds 				return -EINVAL;
885463b94938SGeir Ola Vaagland 
885563b94938SGeir Ola Vaagland 			cmsgs->init = CMSG_DATA(cmsg);
88561da177e4SLinus Torvalds 			break;
88571da177e4SLinus Torvalds 
88581da177e4SLinus Torvalds 		case SCTP_SNDRCV:
88591da177e4SLinus Torvalds 			/* SCTP Socket API Extension
886063b94938SGeir Ola Vaagland 			 * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV)
88611da177e4SLinus Torvalds 			 *
88621da177e4SLinus Torvalds 			 * This cmsghdr structure specifies SCTP options for
88631da177e4SLinus Torvalds 			 * sendmsg() and describes SCTP header information
88641da177e4SLinus Torvalds 			 * about a received message through recvmsg().
88651da177e4SLinus Torvalds 			 *
88661da177e4SLinus Torvalds 			 * cmsg_level    cmsg_type      cmsg_data[]
88671da177e4SLinus Torvalds 			 * ------------  ------------   ----------------------
88681da177e4SLinus Torvalds 			 * IPPROTO_SCTP  SCTP_SNDRCV    struct sctp_sndrcvinfo
88691da177e4SLinus Torvalds 			 */
887063b94938SGeir Ola Vaagland 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
88711da177e4SLinus Torvalds 				return -EINVAL;
88721da177e4SLinus Torvalds 
887363b94938SGeir Ola Vaagland 			cmsgs->srinfo = CMSG_DATA(cmsg);
88741da177e4SLinus Torvalds 
887563b94938SGeir Ola Vaagland 			if (cmsgs->srinfo->sinfo_flags &
8876eaa5c54dSIvan Skytte Jorgensen 			    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
887749102805SXin Long 			      SCTP_SACK_IMMEDIATELY | SCTP_SENDALL |
887849102805SXin Long 			      SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF))
88791da177e4SLinus Torvalds 				return -EINVAL;
88801da177e4SLinus Torvalds 			break;
88811da177e4SLinus Torvalds 
888263b94938SGeir Ola Vaagland 		case SCTP_SNDINFO:
888363b94938SGeir Ola Vaagland 			/* SCTP Socket API Extension
888463b94938SGeir Ola Vaagland 			 * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO)
888563b94938SGeir Ola Vaagland 			 *
888663b94938SGeir Ola Vaagland 			 * This cmsghdr structure specifies SCTP options for
888763b94938SGeir Ola Vaagland 			 * sendmsg(). This structure and SCTP_RCVINFO replaces
888863b94938SGeir Ola Vaagland 			 * SCTP_SNDRCV which has been deprecated.
888963b94938SGeir Ola Vaagland 			 *
889063b94938SGeir Ola Vaagland 			 * cmsg_level    cmsg_type      cmsg_data[]
889163b94938SGeir Ola Vaagland 			 * ------------  ------------   ---------------------
889263b94938SGeir Ola Vaagland 			 * IPPROTO_SCTP  SCTP_SNDINFO    struct sctp_sndinfo
889363b94938SGeir Ola Vaagland 			 */
889463b94938SGeir Ola Vaagland 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo)))
889563b94938SGeir Ola Vaagland 				return -EINVAL;
889663b94938SGeir Ola Vaagland 
889763b94938SGeir Ola Vaagland 			cmsgs->sinfo = CMSG_DATA(cmsg);
889863b94938SGeir Ola Vaagland 
889963b94938SGeir Ola Vaagland 			if (cmsgs->sinfo->snd_flags &
890063b94938SGeir Ola Vaagland 			    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
890149102805SXin Long 			      SCTP_SACK_IMMEDIATELY | SCTP_SENDALL |
890249102805SXin Long 			      SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF))
890363b94938SGeir Ola Vaagland 				return -EINVAL;
890463b94938SGeir Ola Vaagland 			break;
8905ed63afb8SXin Long 		case SCTP_PRINFO:
8906ed63afb8SXin Long 			/* SCTP Socket API Extension
8907ed63afb8SXin Long 			 * 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO)
8908ed63afb8SXin Long 			 *
8909ed63afb8SXin Long 			 * This cmsghdr structure specifies SCTP options for sendmsg().
8910ed63afb8SXin Long 			 *
8911ed63afb8SXin Long 			 * cmsg_level    cmsg_type      cmsg_data[]
8912ed63afb8SXin Long 			 * ------------  ------------   ---------------------
8913ed63afb8SXin Long 			 * IPPROTO_SCTP  SCTP_PRINFO    struct sctp_prinfo
8914ed63afb8SXin Long 			 */
8915ed63afb8SXin Long 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_prinfo)))
8916ed63afb8SXin Long 				return -EINVAL;
8917ed63afb8SXin Long 
8918ed63afb8SXin Long 			cmsgs->prinfo = CMSG_DATA(cmsg);
8919ed63afb8SXin Long 			if (cmsgs->prinfo->pr_policy & ~SCTP_PR_SCTP_MASK)
8920ed63afb8SXin Long 				return -EINVAL;
8921ed63afb8SXin Long 
8922ed63afb8SXin Long 			if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
8923ed63afb8SXin Long 				cmsgs->prinfo->pr_value = 0;
8924ed63afb8SXin Long 			break;
89253ff547c0SXin Long 		case SCTP_AUTHINFO:
89263ff547c0SXin Long 			/* SCTP Socket API Extension
89273ff547c0SXin Long 			 * 5.3.8 SCTP AUTH Information Structure (SCTP_AUTHINFO)
89283ff547c0SXin Long 			 *
89293ff547c0SXin Long 			 * This cmsghdr structure specifies SCTP options for sendmsg().
89303ff547c0SXin Long 			 *
89313ff547c0SXin Long 			 * cmsg_level    cmsg_type      cmsg_data[]
89323ff547c0SXin Long 			 * ------------  ------------   ---------------------
89333ff547c0SXin Long 			 * IPPROTO_SCTP  SCTP_AUTHINFO  struct sctp_authinfo
89343ff547c0SXin Long 			 */
89353ff547c0SXin Long 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_authinfo)))
89363ff547c0SXin Long 				return -EINVAL;
89373ff547c0SXin Long 
89383ff547c0SXin Long 			cmsgs->authinfo = CMSG_DATA(cmsg);
89393ff547c0SXin Long 			break;
89402c0dbaa0SXin Long 		case SCTP_DSTADDRV4:
89412c0dbaa0SXin Long 		case SCTP_DSTADDRV6:
89422c0dbaa0SXin Long 			/* SCTP Socket API Extension
89432c0dbaa0SXin Long 			 * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6)
89442c0dbaa0SXin Long 			 *
89452c0dbaa0SXin Long 			 * This cmsghdr structure specifies SCTP options for sendmsg().
89462c0dbaa0SXin Long 			 *
89472c0dbaa0SXin Long 			 * cmsg_level    cmsg_type         cmsg_data[]
89482c0dbaa0SXin Long 			 * ------------  ------------   ---------------------
89492c0dbaa0SXin Long 			 * IPPROTO_SCTP  SCTP_DSTADDRV4 struct in_addr
89502c0dbaa0SXin Long 			 * ------------  ------------   ---------------------
89512c0dbaa0SXin Long 			 * IPPROTO_SCTP  SCTP_DSTADDRV6 struct in6_addr
89522c0dbaa0SXin Long 			 */
89532c0dbaa0SXin Long 			cmsgs->addrs_msg = my_msg;
89542c0dbaa0SXin Long 			break;
89551da177e4SLinus Torvalds 		default:
89561da177e4SLinus Torvalds 			return -EINVAL;
89573ff50b79SStephen Hemminger 		}
89581da177e4SLinus Torvalds 	}
895963b94938SGeir Ola Vaagland 
89601da177e4SLinus Torvalds 	return 0;
89611da177e4SLinus Torvalds }
89621da177e4SLinus Torvalds 
89631da177e4SLinus Torvalds /*
89641da177e4SLinus Torvalds  * Wait for a packet..
89651da177e4SLinus Torvalds  * Note: This function is the same function as in core/datagram.c
89661da177e4SLinus Torvalds  * with a few modifications to make lksctp work.
89671da177e4SLinus Torvalds  */
sctp_wait_for_packet(struct sock * sk,int * err,long * timeo_p)89681da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p)
89691da177e4SLinus Torvalds {
89701da177e4SLinus Torvalds 	int error;
89711da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
89721da177e4SLinus Torvalds 
8973aa395145SEric Dumazet 	prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
89741da177e4SLinus Torvalds 
89751da177e4SLinus Torvalds 	/* Socket errors? */
89761da177e4SLinus Torvalds 	error = sock_error(sk);
89771da177e4SLinus Torvalds 	if (error)
89781da177e4SLinus Torvalds 		goto out;
89791da177e4SLinus Torvalds 
89801da177e4SLinus Torvalds 	if (!skb_queue_empty(&sk->sk_receive_queue))
89811da177e4SLinus Torvalds 		goto ready;
89821da177e4SLinus Torvalds 
89831da177e4SLinus Torvalds 	/* Socket shut down?  */
89841da177e4SLinus Torvalds 	if (sk->sk_shutdown & RCV_SHUTDOWN)
89851da177e4SLinus Torvalds 		goto out;
89861da177e4SLinus Torvalds 
89871da177e4SLinus Torvalds 	/* Sequenced packets can come disconnected.  If so we report the
89881da177e4SLinus Torvalds 	 * problem.
89891da177e4SLinus Torvalds 	 */
89901da177e4SLinus Torvalds 	error = -ENOTCONN;
89911da177e4SLinus Torvalds 
89921da177e4SLinus Torvalds 	/* Is there a good reason to think that we may receive some data?  */
89931da177e4SLinus Torvalds 	if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING))
89941da177e4SLinus Torvalds 		goto out;
89951da177e4SLinus Torvalds 
89961da177e4SLinus Torvalds 	/* Handle signals.  */
89971da177e4SLinus Torvalds 	if (signal_pending(current))
89981da177e4SLinus Torvalds 		goto interrupted;
89991da177e4SLinus Torvalds 
90001da177e4SLinus Torvalds 	/* Let another process have a go.  Since we are going to sleep
90011da177e4SLinus Torvalds 	 * anyway.  Note: This may cause odd behaviors if the message
90021da177e4SLinus Torvalds 	 * does not fit in the user's buffer, but this seems to be the
90031da177e4SLinus Torvalds 	 * only way to honor MSG_DONTWAIT realistically.
90041da177e4SLinus Torvalds 	 */
9005048ed4b6Swangweidong 	release_sock(sk);
90061da177e4SLinus Torvalds 	*timeo_p = schedule_timeout(*timeo_p);
9007048ed4b6Swangweidong 	lock_sock(sk);
90081da177e4SLinus Torvalds 
90091da177e4SLinus Torvalds ready:
9010aa395145SEric Dumazet 	finish_wait(sk_sleep(sk), &wait);
90111da177e4SLinus Torvalds 	return 0;
90121da177e4SLinus Torvalds 
90131da177e4SLinus Torvalds interrupted:
90141da177e4SLinus Torvalds 	error = sock_intr_errno(*timeo_p);
90151da177e4SLinus Torvalds 
90161da177e4SLinus Torvalds out:
9017aa395145SEric Dumazet 	finish_wait(sk_sleep(sk), &wait);
90181da177e4SLinus Torvalds 	*err = error;
90191da177e4SLinus Torvalds 	return error;
90201da177e4SLinus Torvalds }
90211da177e4SLinus Torvalds 
90221da177e4SLinus Torvalds /* Receive a datagram.
90231da177e4SLinus Torvalds  * Note: This is pretty much the same routine as in core/datagram.c
90241da177e4SLinus Torvalds  * with a few changes to make lksctp work.
90251da177e4SLinus Torvalds  */
sctp_skb_recv_datagram(struct sock * sk,int flags,int * err)9026ec095263SOliver Hartkopp struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int *err)
90271da177e4SLinus Torvalds {
90281da177e4SLinus Torvalds 	int error;
90291da177e4SLinus Torvalds 	struct sk_buff *skb;
90301da177e4SLinus Torvalds 	long timeo;
90311da177e4SLinus Torvalds 
9032ec095263SOliver Hartkopp 	timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
90331da177e4SLinus Torvalds 
9034bb33381dSDaniel Borkmann 	pr_debug("%s: timeo:%ld, max:%ld\n", __func__, timeo,
9035bb33381dSDaniel Borkmann 		 MAX_SCHEDULE_TIMEOUT);
90361da177e4SLinus Torvalds 
90371da177e4SLinus Torvalds 	do {
90381da177e4SLinus Torvalds 		/* Again only user level code calls this function,
90391da177e4SLinus Torvalds 		 * so nothing interrupt level
90401da177e4SLinus Torvalds 		 * will suddenly eat the receive_queue.
90411da177e4SLinus Torvalds 		 *
90421da177e4SLinus Torvalds 		 *  Look at current nfs client by the way...
90438917a3c0SDavid Shwatrz 		 *  However, this function was correct in any case. 8)
90441da177e4SLinus Torvalds 		 */
90451da177e4SLinus Torvalds 		if (flags & MSG_PEEK) {
90461da177e4SLinus Torvalds 			skb = skb_peek(&sk->sk_receive_queue);
90471da177e4SLinus Torvalds 			if (skb)
904863354797SReshetova, Elena 				refcount_inc(&skb->users);
90491da177e4SLinus Torvalds 		} else {
9050311b2177SMarcelo Ricardo Leitner 			skb = __skb_dequeue(&sk->sk_receive_queue);
90511da177e4SLinus Torvalds 		}
90521da177e4SLinus Torvalds 
90531da177e4SLinus Torvalds 		if (skb)
90541da177e4SLinus Torvalds 			return skb;
90551da177e4SLinus Torvalds 
90566736dc35SNeil Horman 		/* Caller is allowed not to check sk->sk_err before calling. */
90576736dc35SNeil Horman 		error = sock_error(sk);
90586736dc35SNeil Horman 		if (error)
90596736dc35SNeil Horman 			goto no_packet;
90606736dc35SNeil Horman 
90611da177e4SLinus Torvalds 		if (sk->sk_shutdown & RCV_SHUTDOWN)
90621da177e4SLinus Torvalds 			break;
90631da177e4SLinus Torvalds 
90648465a5fcSNeil Horman 
90651da177e4SLinus Torvalds 		/* User doesn't want to wait.  */
90661da177e4SLinus Torvalds 		error = -EAGAIN;
90671da177e4SLinus Torvalds 		if (!timeo)
90681da177e4SLinus Torvalds 			goto no_packet;
90691da177e4SLinus Torvalds 	} while (sctp_wait_for_packet(sk, err, &timeo) == 0);
90701da177e4SLinus Torvalds 
90711da177e4SLinus Torvalds 	return NULL;
90721da177e4SLinus Torvalds 
90731da177e4SLinus Torvalds no_packet:
90741da177e4SLinus Torvalds 	*err = error;
90751da177e4SLinus Torvalds 	return NULL;
90761da177e4SLinus Torvalds }
90771da177e4SLinus Torvalds 
90781da177e4SLinus Torvalds /* If sndbuf has changed, wake up per association sndbuf waiters.  */
__sctp_write_space(struct sctp_association * asoc)90791da177e4SLinus Torvalds static void __sctp_write_space(struct sctp_association *asoc)
90801da177e4SLinus Torvalds {
90811da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
90821da177e4SLinus Torvalds 
9083ceb5d58bSEric Dumazet 	if (sctp_wspace(asoc) <= 0)
9084ceb5d58bSEric Dumazet 		return;
9085ceb5d58bSEric Dumazet 
90861da177e4SLinus Torvalds 	if (waitqueue_active(&asoc->wait))
90871da177e4SLinus Torvalds 		wake_up_interruptible(&asoc->wait);
90881da177e4SLinus Torvalds 
90891da177e4SLinus Torvalds 	if (sctp_writeable(sk)) {
9090ceb5d58bSEric Dumazet 		struct socket_wq *wq;
9091eaefd110SEric Dumazet 
9092ceb5d58bSEric Dumazet 		rcu_read_lock();
9093ceb5d58bSEric Dumazet 		wq = rcu_dereference(sk->sk_wq);
9094ceb5d58bSEric Dumazet 		if (wq) {
9095ceb5d58bSEric Dumazet 			if (waitqueue_active(&wq->wait))
9096ceb5d58bSEric Dumazet 				wake_up_interruptible(&wq->wait);
90971da177e4SLinus Torvalds 
90981da177e4SLinus Torvalds 			/* Note that we try to include the Async I/O support
90991da177e4SLinus Torvalds 			 * here by modeling from the current TCP/UDP code.
91001da177e4SLinus Torvalds 			 * We have not tested with it yet.
91011da177e4SLinus Torvalds 			 */
9102eaefd110SEric Dumazet 			if (!(sk->sk_shutdown & SEND_SHUTDOWN))
9103ceb5d58bSEric Dumazet 				sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT);
91041da177e4SLinus Torvalds 		}
9105ceb5d58bSEric Dumazet 		rcu_read_unlock();
91061da177e4SLinus Torvalds 	}
91071da177e4SLinus Torvalds }
91081da177e4SLinus Torvalds 
sctp_wake_up_waiters(struct sock * sk,struct sctp_association * asoc)910952c35befSDaniel Borkmann static void sctp_wake_up_waiters(struct sock *sk,
911052c35befSDaniel Borkmann 				 struct sctp_association *asoc)
911152c35befSDaniel Borkmann {
911252c35befSDaniel Borkmann 	struct sctp_association *tmp = asoc;
911352c35befSDaniel Borkmann 
911452c35befSDaniel Borkmann 	/* We do accounting for the sndbuf space per association,
911552c35befSDaniel Borkmann 	 * so we only need to wake our own association.
911652c35befSDaniel Borkmann 	 */
911752c35befSDaniel Borkmann 	if (asoc->ep->sndbuf_policy)
911852c35befSDaniel Borkmann 		return __sctp_write_space(asoc);
911952c35befSDaniel Borkmann 
91201e1cdf8aSDaniel Borkmann 	/* If association goes down and is just flushing its
91211e1cdf8aSDaniel Borkmann 	 * outq, then just normally notify others.
91221e1cdf8aSDaniel Borkmann 	 */
91231e1cdf8aSDaniel Borkmann 	if (asoc->base.dead)
91241e1cdf8aSDaniel Borkmann 		return sctp_write_space(sk);
91251e1cdf8aSDaniel Borkmann 
912652c35befSDaniel Borkmann 	/* Accounting for the sndbuf space is per socket, so we
912752c35befSDaniel Borkmann 	 * need to wake up others, try to be fair and in case of
912852c35befSDaniel Borkmann 	 * other associations, let them have a go first instead
912952c35befSDaniel Borkmann 	 * of just doing a sctp_write_space() call.
913052c35befSDaniel Borkmann 	 *
913152c35befSDaniel Borkmann 	 * Note that we reach sctp_wake_up_waiters() only when
913252c35befSDaniel Borkmann 	 * associations free up queued chunks, thus we are under
913352c35befSDaniel Borkmann 	 * lock and the list of associations on a socket is
913452c35befSDaniel Borkmann 	 * guaranteed not to change.
913552c35befSDaniel Borkmann 	 */
913652c35befSDaniel Borkmann 	for (tmp = list_next_entry(tmp, asocs); 1;
913752c35befSDaniel Borkmann 	     tmp = list_next_entry(tmp, asocs)) {
913852c35befSDaniel Borkmann 		/* Manually skip the head element. */
913952c35befSDaniel Borkmann 		if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs))
914052c35befSDaniel Borkmann 			continue;
914152c35befSDaniel Borkmann 		/* Wake up association. */
914252c35befSDaniel Borkmann 		__sctp_write_space(tmp);
914352c35befSDaniel Borkmann 		/* We've reached the end. */
914452c35befSDaniel Borkmann 		if (tmp == asoc)
914552c35befSDaniel Borkmann 			break;
914652c35befSDaniel Borkmann 	}
914752c35befSDaniel Borkmann }
914852c35befSDaniel Borkmann 
91491da177e4SLinus Torvalds /* Do accounting for the sndbuf space.
91501da177e4SLinus Torvalds  * Decrement the used sndbuf space of the corresponding association by the
91511da177e4SLinus Torvalds  * data size which was just transmitted(freed).
91521da177e4SLinus Torvalds  */
sctp_wfree(struct sk_buff * skb)91531da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb)
91541da177e4SLinus Torvalds {
9155f869c912SDaniel Borkmann 	struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg;
9156f869c912SDaniel Borkmann 	struct sctp_association *asoc = chunk->asoc;
9157f869c912SDaniel Borkmann 	struct sock *sk = asoc->base.sk;
91581da177e4SLinus Torvalds 
91593ab224beSHideo Aoki 	sk_mem_uncharge(sk, skb->truesize);
9160dc9511ddSEric Dumazet 	sk_wmem_queued_add(sk, -(skb->truesize + sizeof(struct sctp_chunk)));
9161605c0ac1SXin Long 	asoc->sndbuf_used -= skb->truesize + sizeof(struct sctp_chunk);
9162605c0ac1SXin Long 	WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk),
9163605c0ac1SXin Long 				      &sk->sk_wmem_alloc));
91644d93df0aSNeil Horman 
9165ec2e506cSXin Long 	if (chunk->shkey) {
9166ec2e506cSXin Long 		struct sctp_shared_key *shkey = chunk->shkey;
9167ec2e506cSXin Long 
9168ec2e506cSXin Long 		/* refcnt == 2 and !list_empty mean after this release, it's
9169ec2e506cSXin Long 		 * not being used anywhere, and it's time to notify userland
9170ec2e506cSXin Long 		 * that this shkey can be freed if it's been deactivated.
9171ec2e506cSXin Long 		 */
9172ec2e506cSXin Long 		if (shkey->deactivated && !list_empty(&shkey->key_list) &&
9173ec2e506cSXin Long 		    refcount_read(&shkey->refcnt) == 2) {
9174ec2e506cSXin Long 			struct sctp_ulpevent *ev;
9175ec2e506cSXin Long 
9176ec2e506cSXin Long 			ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id,
9177ec2e506cSXin Long 							SCTP_AUTH_FREE_KEY,
9178ec2e506cSXin Long 							GFP_KERNEL);
9179ec2e506cSXin Long 			if (ev)
9180ec2e506cSXin Long 				asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
9181ec2e506cSXin Long 		}
91821b1e0bc9SXin Long 		sctp_auth_shkey_release(chunk->shkey);
9183ec2e506cSXin Long 	}
91841b1e0bc9SXin Long 
91854eb701dfSNeil Horman 	sock_wfree(skb);
918652c35befSDaniel Borkmann 	sctp_wake_up_waiters(sk, asoc);
91871da177e4SLinus Torvalds 
91881da177e4SLinus Torvalds 	sctp_association_put(asoc);
91891da177e4SLinus Torvalds }
91901da177e4SLinus Torvalds 
9191331c4ee7SVlad Yasevich /* Do accounting for the receive space on the socket.
9192331c4ee7SVlad Yasevich  * Accounting for the association is done in ulpevent.c
9193331c4ee7SVlad Yasevich  * We set this as a destructor for the cloned data skbs so that
9194331c4ee7SVlad Yasevich  * accounting is done at the correct time.
9195331c4ee7SVlad Yasevich  */
sctp_sock_rfree(struct sk_buff * skb)9196331c4ee7SVlad Yasevich void sctp_sock_rfree(struct sk_buff *skb)
9197331c4ee7SVlad Yasevich {
9198331c4ee7SVlad Yasevich 	struct sock *sk = skb->sk;
9199331c4ee7SVlad Yasevich 	struct sctp_ulpevent *event = sctp_skb2event(skb);
9200331c4ee7SVlad Yasevich 
9201331c4ee7SVlad Yasevich 	atomic_sub(event->rmem_len, &sk->sk_rmem_alloc);
92024d93df0aSNeil Horman 
92034d93df0aSNeil Horman 	/*
92043ab224beSHideo Aoki 	 * Mimic the behavior of sock_rfree
92054d93df0aSNeil Horman 	 */
92063ab224beSHideo Aoki 	sk_mem_uncharge(sk, event->rmem_len);
9207331c4ee7SVlad Yasevich }
9208331c4ee7SVlad Yasevich 
9209331c4ee7SVlad Yasevich 
92101da177e4SLinus Torvalds /* Helper function to wait for space in the sndbuf.  */
sctp_wait_for_sndbuf(struct sctp_association * asoc,long * timeo_p,size_t msg_len)92111da177e4SLinus Torvalds static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
9212a0ff6600SXin Long 				size_t msg_len)
92131da177e4SLinus Torvalds {
92141da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
92151da177e4SLinus Torvalds 	long current_timeo = *timeo_p;
92161da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
9217a0ff6600SXin Long 	int err = 0;
92181da177e4SLinus Torvalds 
9219bb33381dSDaniel Borkmann 	pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc,
9220bb33381dSDaniel Borkmann 		 *timeo_p, msg_len);
92211da177e4SLinus Torvalds 
92221da177e4SLinus Torvalds 	/* Increment the association's refcnt.  */
92231da177e4SLinus Torvalds 	sctp_association_hold(asoc);
92241da177e4SLinus Torvalds 
92251da177e4SLinus Torvalds 	/* Wait on the association specific sndbuf space. */
92261da177e4SLinus Torvalds 	for (;;) {
92271da177e4SLinus Torvalds 		prepare_to_wait_exclusive(&asoc->wait, &wait,
92281da177e4SLinus Torvalds 					  TASK_INTERRUPTIBLE);
9229ca3af4ddSXin Long 		if (asoc->base.dead)
9230ca3af4ddSXin Long 			goto do_dead;
92311da177e4SLinus Torvalds 		if (!*timeo_p)
92321da177e4SLinus Torvalds 			goto do_nonblock;
9233ca3af4ddSXin Long 		if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING)
92341da177e4SLinus Torvalds 			goto do_error;
92351da177e4SLinus Torvalds 		if (signal_pending(current))
92361da177e4SLinus Torvalds 			goto do_interrupted;
92371033990aSXin Long 		if ((int)msg_len <= sctp_wspace(asoc) &&
92381033990aSXin Long 		    sk_wmem_schedule(sk, msg_len))
92391da177e4SLinus Torvalds 			break;
92401da177e4SLinus Torvalds 
92411da177e4SLinus Torvalds 		/* Let another process have a go.  Since we are going
92421da177e4SLinus Torvalds 		 * to sleep anyway.
92431da177e4SLinus Torvalds 		 */
9244048ed4b6Swangweidong 		release_sock(sk);
92451da177e4SLinus Torvalds 		current_timeo = schedule_timeout(current_timeo);
9246048ed4b6Swangweidong 		lock_sock(sk);
9247a0ff6600SXin Long 		if (sk != asoc->base.sk)
9248a0ff6600SXin Long 			goto do_error;
92491da177e4SLinus Torvalds 
92501da177e4SLinus Torvalds 		*timeo_p = current_timeo;
92511da177e4SLinus Torvalds 	}
92521da177e4SLinus Torvalds 
92531da177e4SLinus Torvalds out:
92541da177e4SLinus Torvalds 	finish_wait(&asoc->wait, &wait);
92551da177e4SLinus Torvalds 
92561da177e4SLinus Torvalds 	/* Release the association's refcnt.  */
92571da177e4SLinus Torvalds 	sctp_association_put(asoc);
92581da177e4SLinus Torvalds 
92591da177e4SLinus Torvalds 	return err;
92601da177e4SLinus Torvalds 
9261ca3af4ddSXin Long do_dead:
9262ca3af4ddSXin Long 	err = -ESRCH;
9263ca3af4ddSXin Long 	goto out;
9264ca3af4ddSXin Long 
92651da177e4SLinus Torvalds do_error:
92661da177e4SLinus Torvalds 	err = -EPIPE;
92671da177e4SLinus Torvalds 	goto out;
92681da177e4SLinus Torvalds 
92691da177e4SLinus Torvalds do_interrupted:
92701da177e4SLinus Torvalds 	err = sock_intr_errno(*timeo_p);
92711da177e4SLinus Torvalds 	goto out;
92721da177e4SLinus Torvalds 
92731da177e4SLinus Torvalds do_nonblock:
92741da177e4SLinus Torvalds 	err = -EAGAIN;
92751da177e4SLinus Torvalds 	goto out;
92761da177e4SLinus Torvalds }
92771da177e4SLinus Torvalds 
sctp_data_ready(struct sock * sk)9278676d2369SDavid S. Miller void sctp_data_ready(struct sock *sk)
9279561b1733SWei Yongjun {
92807ef52737SDavid S. Miller 	struct socket_wq *wq;
92817ef52737SDavid S. Miller 
928240e0b090SPeilin Ye 	trace_sk_data_ready(sk);
928340e0b090SPeilin Ye 
92847ef52737SDavid S. Miller 	rcu_read_lock();
92857ef52737SDavid S. Miller 	wq = rcu_dereference(sk->sk_wq);
92861ce0bf50SHerbert Xu 	if (skwq_has_sleeper(wq))
9287a9a08845SLinus Torvalds 		wake_up_interruptible_sync_poll(&wq->wait, EPOLLIN |
9288a9a08845SLinus Torvalds 						EPOLLRDNORM | EPOLLRDBAND);
9289561b1733SWei Yongjun 	sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
92907ef52737SDavid S. Miller 	rcu_read_unlock();
9291561b1733SWei Yongjun }
9292561b1733SWei Yongjun 
92931da177e4SLinus Torvalds /* If socket sndbuf has changed, wake up all per association waiters.  */
sctp_write_space(struct sock * sk)92941da177e4SLinus Torvalds void sctp_write_space(struct sock *sk)
92951da177e4SLinus Torvalds {
92961da177e4SLinus Torvalds 	struct sctp_association *asoc;
92971da177e4SLinus Torvalds 
92981da177e4SLinus Torvalds 	/* Wake up the tasks in each wait queue.  */
92999dbc15f0SRobert P. J. Day 	list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) {
93001da177e4SLinus Torvalds 		__sctp_write_space(asoc);
93011da177e4SLinus Torvalds 	}
93021da177e4SLinus Torvalds }
93031da177e4SLinus Torvalds 
93041da177e4SLinus Torvalds /* Is there any sndbuf space available on the socket?
93051da177e4SLinus Torvalds  *
93069bffc4acSNeil Horman  * Note that sk_wmem_alloc is the sum of the send buffers on all of the
93071da177e4SLinus Torvalds  * associations on the same socket.  For a UDP-style socket with
93081da177e4SLinus Torvalds  * multiple associations, it is possible for it to be "unwriteable"
93091da177e4SLinus Torvalds  * prematurely.  I assume that this is acceptable because
93101da177e4SLinus Torvalds  * a premature "unwriteable" is better than an accidental "writeable" which
93111da177e4SLinus Torvalds  * would cause an unwanted block under certain circumstances.  For the 1-1
93121da177e4SLinus Torvalds  * UDP-style sockets or TCP-style sockets, this code should work.
93131da177e4SLinus Torvalds  *  - Daisy
93141da177e4SLinus Torvalds  */
sctp_writeable(const struct sock * sk)9315dc9511ddSEric Dumazet static bool sctp_writeable(const struct sock *sk)
93161da177e4SLinus Torvalds {
9317dc9511ddSEric Dumazet 	return READ_ONCE(sk->sk_sndbuf) > READ_ONCE(sk->sk_wmem_queued);
93181da177e4SLinus Torvalds }
93191da177e4SLinus Torvalds 
93201da177e4SLinus Torvalds /* Wait for an association to go into ESTABLISHED state. If timeout is 0,
93211da177e4SLinus Torvalds  * returns immediately with EINPROGRESS.
93221da177e4SLinus Torvalds  */
sctp_wait_for_connect(struct sctp_association * asoc,long * timeo_p)93231da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)
93241da177e4SLinus Torvalds {
93251da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
93261da177e4SLinus Torvalds 	int err = 0;
93271da177e4SLinus Torvalds 	long current_timeo = *timeo_p;
93281da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
93291da177e4SLinus Torvalds 
9330bb33381dSDaniel Borkmann 	pr_debug("%s: asoc:%p, timeo:%ld\n", __func__, asoc, *timeo_p);
93311da177e4SLinus Torvalds 
93321da177e4SLinus Torvalds 	/* Increment the association's refcnt.  */
93331da177e4SLinus Torvalds 	sctp_association_hold(asoc);
93341da177e4SLinus Torvalds 
93351da177e4SLinus Torvalds 	for (;;) {
93361da177e4SLinus Torvalds 		prepare_to_wait_exclusive(&asoc->wait, &wait,
93371da177e4SLinus Torvalds 					  TASK_INTERRUPTIBLE);
93381da177e4SLinus Torvalds 		if (!*timeo_p)
93391da177e4SLinus Torvalds 			goto do_nonblock;
93401da177e4SLinus Torvalds 		if (sk->sk_shutdown & RCV_SHUTDOWN)
93411da177e4SLinus Torvalds 			break;
93421da177e4SLinus Torvalds 		if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
93431da177e4SLinus Torvalds 		    asoc->base.dead)
93441da177e4SLinus Torvalds 			goto do_error;
93451da177e4SLinus Torvalds 		if (signal_pending(current))
93461da177e4SLinus Torvalds 			goto do_interrupted;
93471da177e4SLinus Torvalds 
93481da177e4SLinus Torvalds 		if (sctp_state(asoc, ESTABLISHED))
93491da177e4SLinus Torvalds 			break;
93501da177e4SLinus Torvalds 
93511da177e4SLinus Torvalds 		/* Let another process have a go.  Since we are going
93521da177e4SLinus Torvalds 		 * to sleep anyway.
93531da177e4SLinus Torvalds 		 */
9354048ed4b6Swangweidong 		release_sock(sk);
93551da177e4SLinus Torvalds 		current_timeo = schedule_timeout(current_timeo);
9356048ed4b6Swangweidong 		lock_sock(sk);
93571da177e4SLinus Torvalds 
93581da177e4SLinus Torvalds 		*timeo_p = current_timeo;
93591da177e4SLinus Torvalds 	}
93601da177e4SLinus Torvalds 
93611da177e4SLinus Torvalds out:
93621da177e4SLinus Torvalds 	finish_wait(&asoc->wait, &wait);
93631da177e4SLinus Torvalds 
93641da177e4SLinus Torvalds 	/* Release the association's refcnt.  */
93651da177e4SLinus Torvalds 	sctp_association_put(asoc);
93661da177e4SLinus Torvalds 
93671da177e4SLinus Torvalds 	return err;
93681da177e4SLinus Torvalds 
93691da177e4SLinus Torvalds do_error:
937081845c21SVlad Yasevich 	if (asoc->init_err_counter + 1 > asoc->max_init_attempts)
93711da177e4SLinus Torvalds 		err = -ETIMEDOUT;
93721da177e4SLinus Torvalds 	else
93731da177e4SLinus Torvalds 		err = -ECONNREFUSED;
93741da177e4SLinus Torvalds 	goto out;
93751da177e4SLinus Torvalds 
93761da177e4SLinus Torvalds do_interrupted:
93771da177e4SLinus Torvalds 	err = sock_intr_errno(*timeo_p);
93781da177e4SLinus Torvalds 	goto out;
93791da177e4SLinus Torvalds 
93801da177e4SLinus Torvalds do_nonblock:
93811da177e4SLinus Torvalds 	err = -EINPROGRESS;
93821da177e4SLinus Torvalds 	goto out;
93831da177e4SLinus Torvalds }
93841da177e4SLinus Torvalds 
sctp_wait_for_accept(struct sock * sk,long timeo)93851da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo)
93861da177e4SLinus Torvalds {
93871da177e4SLinus Torvalds 	struct sctp_endpoint *ep;
93881da177e4SLinus Torvalds 	int err = 0;
93891da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
93901da177e4SLinus Torvalds 
93911da177e4SLinus Torvalds 	ep = sctp_sk(sk)->ep;
93921da177e4SLinus Torvalds 
93931da177e4SLinus Torvalds 
93941da177e4SLinus Torvalds 	for (;;) {
9395aa395145SEric Dumazet 		prepare_to_wait_exclusive(sk_sleep(sk), &wait,
93961da177e4SLinus Torvalds 					  TASK_INTERRUPTIBLE);
93971da177e4SLinus Torvalds 
93981da177e4SLinus Torvalds 		if (list_empty(&ep->asocs)) {
9399048ed4b6Swangweidong 			release_sock(sk);
94001da177e4SLinus Torvalds 			timeo = schedule_timeout(timeo);
9401048ed4b6Swangweidong 			lock_sock(sk);
94021da177e4SLinus Torvalds 		}
94031da177e4SLinus Torvalds 
94041da177e4SLinus Torvalds 		err = -EINVAL;
94051da177e4SLinus Torvalds 		if (!sctp_sstate(sk, LISTENING))
94061da177e4SLinus Torvalds 			break;
94071da177e4SLinus Torvalds 
94081da177e4SLinus Torvalds 		err = 0;
94091da177e4SLinus Torvalds 		if (!list_empty(&ep->asocs))
94101da177e4SLinus Torvalds 			break;
94111da177e4SLinus Torvalds 
94121da177e4SLinus Torvalds 		err = sock_intr_errno(timeo);
94131da177e4SLinus Torvalds 		if (signal_pending(current))
94141da177e4SLinus Torvalds 			break;
94151da177e4SLinus Torvalds 
94161da177e4SLinus Torvalds 		err = -EAGAIN;
94171da177e4SLinus Torvalds 		if (!timeo)
94181da177e4SLinus Torvalds 			break;
94191da177e4SLinus Torvalds 	}
94201da177e4SLinus Torvalds 
9421aa395145SEric Dumazet 	finish_wait(sk_sleep(sk), &wait);
94221da177e4SLinus Torvalds 
94231da177e4SLinus Torvalds 	return err;
94241da177e4SLinus Torvalds }
94251da177e4SLinus Torvalds 
sctp_wait_for_close(struct sock * sk,long timeout)942604675210Ssebastian@breakpoint.cc static void sctp_wait_for_close(struct sock *sk, long timeout)
94271da177e4SLinus Torvalds {
94281da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
94291da177e4SLinus Torvalds 
94301da177e4SLinus Torvalds 	do {
9431aa395145SEric Dumazet 		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
94321da177e4SLinus Torvalds 		if (list_empty(&sctp_sk(sk)->ep->asocs))
94331da177e4SLinus Torvalds 			break;
9434048ed4b6Swangweidong 		release_sock(sk);
94351da177e4SLinus Torvalds 		timeout = schedule_timeout(timeout);
9436048ed4b6Swangweidong 		lock_sock(sk);
94371da177e4SLinus Torvalds 	} while (!signal_pending(current) && timeout);
94381da177e4SLinus Torvalds 
9439aa395145SEric Dumazet 	finish_wait(sk_sleep(sk), &wait);
94401da177e4SLinus Torvalds }
94411da177e4SLinus Torvalds 
sctp_skb_set_owner_r_frag(struct sk_buff * skb,struct sock * sk)9442ea2bc483STsutomu Fujii static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
9443ea2bc483STsutomu Fujii {
9444ea2bc483STsutomu Fujii 	struct sk_buff *frag;
9445ea2bc483STsutomu Fujii 
9446ea2bc483STsutomu Fujii 	if (!skb->data_len)
9447ea2bc483STsutomu Fujii 		goto done;
9448ea2bc483STsutomu Fujii 
9449ea2bc483STsutomu Fujii 	/* Don't forget the fragments. */
94501b003be3SDavid S. Miller 	skb_walk_frags(skb, frag)
9451ea2bc483STsutomu Fujii 		sctp_skb_set_owner_r_frag(frag, sk);
9452ea2bc483STsutomu Fujii 
9453ea2bc483STsutomu Fujii done:
9454ea2bc483STsutomu Fujii 	sctp_skb_set_owner_r(skb, sk);
9455ea2bc483STsutomu Fujii }
9456ea2bc483STsutomu Fujii 
sctp_copy_sock(struct sock * newsk,struct sock * sk,struct sctp_association * asoc)9457914e1c8bSVlad Yasevich void sctp_copy_sock(struct sock *newsk, struct sock *sk,
9458914e1c8bSVlad Yasevich 		    struct sctp_association *asoc)
9459914e1c8bSVlad Yasevich {
9460914e1c8bSVlad Yasevich 	struct inet_sock *inet = inet_sk(sk);
946109cb47a2SJulia Lawall 	struct inet_sock *newinet;
94622277c7cdSRichard Haines 	struct sctp_sock *sp = sctp_sk(sk);
9463914e1c8bSVlad Yasevich 
9464914e1c8bSVlad Yasevich 	newsk->sk_type = sk->sk_type;
9465914e1c8bSVlad Yasevich 	newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
9466914e1c8bSVlad Yasevich 	newsk->sk_flags = sk->sk_flags;
946750a5ffb1SMarcelo Ricardo Leitner 	newsk->sk_tsflags = sk->sk_tsflags;
946828448b80STom Herbert 	newsk->sk_no_check_tx = sk->sk_no_check_tx;
946928448b80STom Herbert 	newsk->sk_no_check_rx = sk->sk_no_check_rx;
9470914e1c8bSVlad Yasevich 	newsk->sk_reuse = sk->sk_reuse;
9471b0e9a2feSXin Long 	sctp_sk(newsk)->reuse = sp->reuse;
9472914e1c8bSVlad Yasevich 
9473914e1c8bSVlad Yasevich 	newsk->sk_shutdown = sk->sk_shutdown;
94746431b0f6SKuniyuki Iwashima 	newsk->sk_destruct = sk->sk_destruct;
9475914e1c8bSVlad Yasevich 	newsk->sk_family = sk->sk_family;
9476914e1c8bSVlad Yasevich 	newsk->sk_protocol = IPPROTO_SCTP;
9477914e1c8bSVlad Yasevich 	newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
9478914e1c8bSVlad Yasevich 	newsk->sk_sndbuf = sk->sk_sndbuf;
9479914e1c8bSVlad Yasevich 	newsk->sk_rcvbuf = sk->sk_rcvbuf;
9480914e1c8bSVlad Yasevich 	newsk->sk_lingertime = sk->sk_lingertime;
9481914e1c8bSVlad Yasevich 	newsk->sk_rcvtimeo = sk->sk_rcvtimeo;
9482914e1c8bSVlad Yasevich 	newsk->sk_sndtimeo = sk->sk_sndtimeo;
9483486bdee0SMarcelo Ricardo Leitner 	newsk->sk_rxhash = sk->sk_rxhash;
9484914e1c8bSVlad Yasevich 
9485914e1c8bSVlad Yasevich 	newinet = inet_sk(newsk);
9486914e1c8bSVlad Yasevich 
9487914e1c8bSVlad Yasevich 	/* Initialize sk's sport, dport, rcv_saddr and daddr for
9488914e1c8bSVlad Yasevich 	 * getsockname() and getpeername()
9489914e1c8bSVlad Yasevich 	 */
9490c720c7e8SEric Dumazet 	newinet->inet_sport = inet->inet_sport;
9491c720c7e8SEric Dumazet 	newinet->inet_saddr = inet->inet_saddr;
9492c720c7e8SEric Dumazet 	newinet->inet_rcv_saddr = inet->inet_rcv_saddr;
9493c720c7e8SEric Dumazet 	newinet->inet_dport = htons(asoc->peer.port);
9494914e1c8bSVlad Yasevich 	newinet->pmtudisc = inet->pmtudisc;
9495f866fbc8SEric Dumazet 	atomic_set(&newinet->inet_id, get_random_u16());
9496914e1c8bSVlad Yasevich 
9497914e1c8bSVlad Yasevich 	newinet->uc_ttl = inet->uc_ttl;
9498b09bde5cSEric Dumazet 	inet_set_bit(MC_LOOP, newsk);
9499914e1c8bSVlad Yasevich 	newinet->mc_ttl = 1;
9500914e1c8bSVlad Yasevich 	newinet->mc_index = 0;
9501914e1c8bSVlad Yasevich 	newinet->mc_list = NULL;
950201ce63c9SMarcelo Ricardo Leitner 
950301ce63c9SMarcelo Ricardo Leitner 	if (newsk->sk_flags & SK_FLAGS_TIMESTAMP)
950401ce63c9SMarcelo Ricardo Leitner 		net_enable_timestamp();
95053538a5c8SMarcelo Ricardo Leitner 
950621c00a18SLu Wei 	/* Set newsk security attributes from original sk and connection
9507c081d53fSXin Long 	 * security attribute from asoc.
95082277c7cdSRichard Haines 	 */
9509c081d53fSXin Long 	security_sctp_sk_clone(asoc, sk, newsk);
9510914e1c8bSVlad Yasevich }
9511914e1c8bSVlad Yasevich 
sctp_copy_descendant(struct sock * sk_to,const struct sock * sk_from)95122d45a02dSMarcelo Ricardo Leitner static inline void sctp_copy_descendant(struct sock *sk_to,
95132d45a02dSMarcelo Ricardo Leitner 					const struct sock *sk_from)
95142d45a02dSMarcelo Ricardo Leitner {
9515fe81d9f6SHenry Ptasinski 	size_t ancestor_size = sizeof(struct inet_sock);
95162d45a02dSMarcelo Ricardo Leitner 
9517fe81d9f6SHenry Ptasinski 	ancestor_size += sk_from->sk_prot->obj_size;
9518fe81d9f6SHenry Ptasinski 	ancestor_size -= offsetof(struct sctp_sock, pd_lobby);
95192d45a02dSMarcelo Ricardo Leitner 	__inet_sk_copy_descendant(sk_to, sk_from, ancestor_size);
95202d45a02dSMarcelo Ricardo Leitner }
95212d45a02dSMarcelo Ricardo Leitner 
95221da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the assoc
95231da177e4SLinus Torvalds  * and its messages to the newsk.
95241da177e4SLinus Torvalds  */
sctp_sock_migrate(struct sock * oldsk,struct sock * newsk,struct sctp_association * assoc,enum sctp_socket_type type)952589664c62SXin Long static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
95261da177e4SLinus Torvalds 			     struct sctp_association *assoc,
9527b7ef2618SXin Long 			     enum sctp_socket_type type)
95281da177e4SLinus Torvalds {
95291da177e4SLinus Torvalds 	struct sctp_sock *oldsp = sctp_sk(oldsk);
95301da177e4SLinus Torvalds 	struct sctp_sock *newsp = sctp_sk(newsk);
95311da177e4SLinus Torvalds 	struct sctp_bind_bucket *pp; /* hash list port iterator */
95321da177e4SLinus Torvalds 	struct sctp_endpoint *newep = newsp->ep;
95331da177e4SLinus Torvalds 	struct sk_buff *skb, *tmp;
95341da177e4SLinus Torvalds 	struct sctp_ulpevent *event;
9535f26f7c48SVlad Yasevich 	struct sctp_bind_hashbucket *head;
953689664c62SXin Long 	int err;
95371da177e4SLinus Torvalds 
95381da177e4SLinus Torvalds 	/* Migrate socket buffer sizes and all the socket level options to the
95391da177e4SLinus Torvalds 	 * new socket.
95401da177e4SLinus Torvalds 	 */
95411da177e4SLinus Torvalds 	newsk->sk_sndbuf = oldsk->sk_sndbuf;
95421da177e4SLinus Torvalds 	newsk->sk_rcvbuf = oldsk->sk_rcvbuf;
95431da177e4SLinus Torvalds 	/* Brute force copy old sctp opt. */
95442d45a02dSMarcelo Ricardo Leitner 	sctp_copy_descendant(newsk, oldsk);
95451da177e4SLinus Torvalds 
95461da177e4SLinus Torvalds 	/* Restore the ep value that was overwritten with the above structure
95471da177e4SLinus Torvalds 	 * copy.
95481da177e4SLinus Torvalds 	 */
95491da177e4SLinus Torvalds 	newsp->ep = newep;
95501da177e4SLinus Torvalds 	newsp->hmac = NULL;
95511da177e4SLinus Torvalds 
95521da177e4SLinus Torvalds 	/* Hook this new socket in to the bind_hash list. */
9553f1f43763SEric W. Biederman 	head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk),
9554f1f43763SEric W. Biederman 						 inet_sk(oldsk)->inet_num)];
9555489ce5f4SNicholas Mc Guire 	spin_lock_bh(&head->lock);
95561da177e4SLinus Torvalds 	pp = sctp_sk(oldsk)->bind_hash;
95571da177e4SLinus Torvalds 	sk_add_bind_node(newsk, &pp->owner);
95581da177e4SLinus Torvalds 	sctp_sk(newsk)->bind_hash = pp;
9559c720c7e8SEric Dumazet 	inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num;
9560489ce5f4SNicholas Mc Guire 	spin_unlock_bh(&head->lock);
95611da177e4SLinus Torvalds 
95624243cac1SVladislav Yasevich 	/* Copy the bind_addr list from the original endpoint to the new
95634243cac1SVladislav Yasevich 	 * endpoint so that we can handle restarts properly
95644243cac1SVladislav Yasevich 	 */
956589664c62SXin Long 	err = sctp_bind_addr_dup(&newsp->ep->base.bind_addr,
95668e71a11cSVlad Yasevich 				 &oldsp->ep->base.bind_addr, GFP_KERNEL);
956789664c62SXin Long 	if (err)
956889664c62SXin Long 		return err;
95694243cac1SVladislav Yasevich 
9570c6f33e05SXin Long 	/* New ep's auth_hmacs should be set if old ep's is set, in case
9571c6f33e05SXin Long 	 * that net->sctp.auth_enable has been changed to 0 by users and
9572c6f33e05SXin Long 	 * new ep's auth_hmacs couldn't be set in sctp_endpoint_init().
9573c6f33e05SXin Long 	 */
9574c6f33e05SXin Long 	if (oldsp->ep->auth_hmacs) {
9575c6f33e05SXin Long 		err = sctp_auth_init_hmacs(newsp->ep, GFP_KERNEL);
9576c6f33e05SXin Long 		if (err)
9577c6f33e05SXin Long 			return err;
9578c6f33e05SXin Long 	}
9579c6f33e05SXin Long 
958034e5b011SXin Long 	sctp_auto_asconf_init(newsp);
958134e5b011SXin Long 
95821da177e4SLinus Torvalds 	/* Move any messages in the old socket's receive queue that are for the
95831da177e4SLinus Torvalds 	 * peeled off association to the new socket's receive queue.
95841da177e4SLinus Torvalds 	 */
95851da177e4SLinus Torvalds 	sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
95861da177e4SLinus Torvalds 		event = sctp_skb2event(skb);
95871da177e4SLinus Torvalds 		if (event->asoc == assoc) {
95888728b834SDavid S. Miller 			__skb_unlink(skb, &oldsk->sk_receive_queue);
95891da177e4SLinus Torvalds 			__skb_queue_tail(&newsk->sk_receive_queue, skb);
9590ea2bc483STsutomu Fujii 			sctp_skb_set_owner_r_frag(skb, newsk);
95911da177e4SLinus Torvalds 		}
95921da177e4SLinus Torvalds 	}
95931da177e4SLinus Torvalds 
95941da177e4SLinus Torvalds 	/* Clean up any messages pending delivery due to partial
95951da177e4SLinus Torvalds 	 * delivery.   Three cases:
95961da177e4SLinus Torvalds 	 * 1) No partial deliver;  no work.
95971da177e4SLinus Torvalds 	 * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
95981da177e4SLinus Torvalds 	 * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue.
95991da177e4SLinus Torvalds 	 */
9600b6e1331fSVlad Yasevich 	atomic_set(&sctp_sk(newsk)->pd_mode, assoc->ulpq.pd_mode);
96011da177e4SLinus Torvalds 
9602b6e1331fSVlad Yasevich 	if (atomic_read(&sctp_sk(oldsk)->pd_mode)) {
96031da177e4SLinus Torvalds 		struct sk_buff_head *queue;
96041da177e4SLinus Torvalds 
96051da177e4SLinus Torvalds 		/* Decide which queue to move pd_lobby skbs to. */
96061da177e4SLinus Torvalds 		if (assoc->ulpq.pd_mode) {
96071da177e4SLinus Torvalds 			queue = &newsp->pd_lobby;
96081da177e4SLinus Torvalds 		} else
96091da177e4SLinus Torvalds 			queue = &newsk->sk_receive_queue;
96101da177e4SLinus Torvalds 
96111da177e4SLinus Torvalds 		/* Walk through the pd_lobby, looking for skbs that
96121da177e4SLinus Torvalds 		 * need moved to the new socket.
96131da177e4SLinus Torvalds 		 */
96141da177e4SLinus Torvalds 		sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
96151da177e4SLinus Torvalds 			event = sctp_skb2event(skb);
96161da177e4SLinus Torvalds 			if (event->asoc == assoc) {
96178728b834SDavid S. Miller 				__skb_unlink(skb, &oldsp->pd_lobby);
96181da177e4SLinus Torvalds 				__skb_queue_tail(queue, skb);
9619ea2bc483STsutomu Fujii 				sctp_skb_set_owner_r_frag(skb, newsk);
96201da177e4SLinus Torvalds 			}
96211da177e4SLinus Torvalds 		}
96221da177e4SLinus Torvalds 
96231da177e4SLinus Torvalds 		/* Clear up any skbs waiting for the partial
96241da177e4SLinus Torvalds 		 * delivery to finish.
96251da177e4SLinus Torvalds 		 */
96261da177e4SLinus Torvalds 		if (assoc->ulpq.pd_mode)
9627b6e1331fSVlad Yasevich 			sctp_clear_pd(oldsk, NULL);
96281da177e4SLinus Torvalds 
96291da177e4SLinus Torvalds 	}
96301da177e4SLinus Torvalds 
963113228238SXin Long 	sctp_for_each_rx_skb(assoc, newsk, sctp_skb_set_owner_r_frag);
9632ea2bc483STsutomu Fujii 
96331da177e4SLinus Torvalds 	/* Set the type of socket to indicate that it is peeled off from the
96341da177e4SLinus Torvalds 	 * original UDP-style socket or created with the accept() call on a
96351da177e4SLinus Torvalds 	 * TCP-style socket..
96361da177e4SLinus Torvalds 	 */
96371da177e4SLinus Torvalds 	newsp->type = type;
96381da177e4SLinus Torvalds 
963961c9fed4SVladislav Yasevich 	/* Mark the new socket "in-use" by the user so that any packets
964061c9fed4SVladislav Yasevich 	 * that may arrive on the association after we've moved it are
964161c9fed4SVladislav Yasevich 	 * queued to the backlog.  This prevents a potential race between
964261c9fed4SVladislav Yasevich 	 * backlog processing on the old socket and new-packet processing
964361c9fed4SVladislav Yasevich 	 * on the new socket.
96445131a184SZach Brown 	 *
96455131a184SZach Brown 	 * The caller has just allocated newsk so we can guarantee that other
96465131a184SZach Brown 	 * paths won't try to lock it and then oldsk.
964761c9fed4SVladislav Yasevich 	 */
96485131a184SZach Brown 	lock_sock_nested(newsk, SINGLE_DEPTH_NESTING);
96495c3e82feSQiujun Huang 	sctp_for_each_tx_datachunk(assoc, true, sctp_clear_owner_w);
96501da177e4SLinus Torvalds 	sctp_assoc_migrate(assoc, newsk);
96515c3e82feSQiujun Huang 	sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w);
96521da177e4SLinus Torvalds 
96531da177e4SLinus Torvalds 	/* If the association on the newsk is already closed before accept()
96541da177e4SLinus Torvalds 	 * is called, set RCV_SHUTDOWN flag.
96551da177e4SLinus Torvalds 	 */
9656d46e416cSXin Long 	if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) {
9657cbabf463SYafang Shao 		inet_sk_set_state(newsk, SCTP_SS_CLOSED);
96581da177e4SLinus Torvalds 		newsk->sk_shutdown |= RCV_SHUTDOWN;
9659d46e416cSXin Long 	} else {
9660cbabf463SYafang Shao 		inet_sk_set_state(newsk, SCTP_SS_ESTABLISHED);
9661d46e416cSXin Long 	}
9662d46e416cSXin Long 
9663048ed4b6Swangweidong 	release_sock(newsk);
966489664c62SXin Long 
966589664c62SXin Long 	return 0;
96661da177e4SLinus Torvalds }
96671da177e4SLinus Torvalds 
96684d93df0aSNeil Horman 
96691da177e4SLinus Torvalds /* This proto struct describes the ULP interface for SCTP.  */
96701da177e4SLinus Torvalds struct proto sctp_prot = {
96711da177e4SLinus Torvalds 	.name        =	"SCTP",
96721da177e4SLinus Torvalds 	.owner       =	THIS_MODULE,
96731da177e4SLinus Torvalds 	.close       =	sctp_close,
96741da177e4SLinus Torvalds 	.disconnect  =	sctp_disconnect,
96751da177e4SLinus Torvalds 	.accept      =	sctp_accept,
96761da177e4SLinus Torvalds 	.ioctl       =	sctp_ioctl,
96771da177e4SLinus Torvalds 	.init        =	sctp_init_sock,
96781da177e4SLinus Torvalds 	.destroy     =	sctp_destroy_sock,
96791da177e4SLinus Torvalds 	.shutdown    =	sctp_shutdown,
96801da177e4SLinus Torvalds 	.setsockopt  =	sctp_setsockopt,
96811da177e4SLinus Torvalds 	.getsockopt  =	sctp_getsockopt,
96822598619eSAlexander Mikhalitsyn 	.bpf_bypass_getsockopt	= sctp_bpf_bypass_getsockopt,
96831da177e4SLinus Torvalds 	.sendmsg     =	sctp_sendmsg,
96841da177e4SLinus Torvalds 	.recvmsg     =	sctp_recvmsg,
96851da177e4SLinus Torvalds 	.bind        =	sctp_bind,
9686c0425a42SChristoph Hellwig 	.bind_add    =  sctp_bind_add,
96871da177e4SLinus Torvalds 	.backlog_rcv =	sctp_backlog_rcv,
96881da177e4SLinus Torvalds 	.hash        =	sctp_hash,
96891da177e4SLinus Torvalds 	.unhash      =	sctp_unhash,
969063dfb793SXin Long 	.no_autobind =	true,
96911da177e4SLinus Torvalds 	.obj_size    =  sizeof(struct sctp_sock),
9692ab9ee8e3SDavid Windsor 	.useroffset  =  offsetof(struct sctp_sock, subscribe),
9693ab9ee8e3SDavid Windsor 	.usersize    =  offsetof(struct sctp_sock, initmsg) -
9694ab9ee8e3SDavid Windsor 				offsetof(struct sctp_sock, subscribe) +
9695ab9ee8e3SDavid Windsor 				sizeof_field(struct sctp_sock, initmsg),
96964d93df0aSNeil Horman 	.sysctl_mem  =  sysctl_sctp_mem,
96974d93df0aSNeil Horman 	.sysctl_rmem =  sysctl_sctp_rmem,
96984d93df0aSNeil Horman 	.sysctl_wmem =  sysctl_sctp_wmem,
96994d93df0aSNeil Horman 	.memory_pressure = &sctp_memory_pressure,
97004d93df0aSNeil Horman 	.enter_memory_pressure = sctp_enter_memory_pressure,
97010defbb0aSEric Dumazet 
97024d93df0aSNeil Horman 	.memory_allocated = &sctp_memory_allocated,
97030defbb0aSEric Dumazet 	.per_cpu_fw_alloc = &sctp_memory_per_cpu_fw_alloc,
97040defbb0aSEric Dumazet 
97055f31886fSPavel Emelyanov 	.sockets_allocated = &sctp_sockets_allocated,
97061da177e4SLinus Torvalds };
97071da177e4SLinus Torvalds 
9708dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
97098295b6d9SEric Dumazet 
sctp_v6_destruct_sock(struct sock * sk)97106431b0f6SKuniyuki Iwashima static void sctp_v6_destruct_sock(struct sock *sk)
9711602dd62dSEric Dumazet {
97126431b0f6SKuniyuki Iwashima 	sctp_destruct_common(sk);
97136431b0f6SKuniyuki Iwashima 	inet6_sock_destruct(sk);
97146431b0f6SKuniyuki Iwashima }
97156431b0f6SKuniyuki Iwashima 
sctp_v6_init_sock(struct sock * sk)97166431b0f6SKuniyuki Iwashima static int sctp_v6_init_sock(struct sock *sk)
97176431b0f6SKuniyuki Iwashima {
97186431b0f6SKuniyuki Iwashima 	int ret = sctp_init_sock(sk);
97196431b0f6SKuniyuki Iwashima 
97206431b0f6SKuniyuki Iwashima 	if (!ret)
97216431b0f6SKuniyuki Iwashima 		sk->sk_destruct = sctp_v6_destruct_sock;
97226431b0f6SKuniyuki Iwashima 
97236431b0f6SKuniyuki Iwashima 	return ret;
9724602dd62dSEric Dumazet }
9725602dd62dSEric Dumazet 
97261da177e4SLinus Torvalds struct proto sctpv6_prot = {
97271da177e4SLinus Torvalds 	.name		= "SCTPv6",
97281da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
97291da177e4SLinus Torvalds 	.close		= sctp_close,
97301da177e4SLinus Torvalds 	.disconnect	= sctp_disconnect,
97311da177e4SLinus Torvalds 	.accept		= sctp_accept,
97321da177e4SLinus Torvalds 	.ioctl		= sctp_ioctl,
97336431b0f6SKuniyuki Iwashima 	.init		= sctp_v6_init_sock,
97346431b0f6SKuniyuki Iwashima 	.destroy	= sctp_destroy_sock,
97351da177e4SLinus Torvalds 	.shutdown	= sctp_shutdown,
97361da177e4SLinus Torvalds 	.setsockopt	= sctp_setsockopt,
97371da177e4SLinus Torvalds 	.getsockopt	= sctp_getsockopt,
97382598619eSAlexander Mikhalitsyn 	.bpf_bypass_getsockopt	= sctp_bpf_bypass_getsockopt,
97391da177e4SLinus Torvalds 	.sendmsg	= sctp_sendmsg,
97401da177e4SLinus Torvalds 	.recvmsg	= sctp_recvmsg,
97411da177e4SLinus Torvalds 	.bind		= sctp_bind,
9742c0425a42SChristoph Hellwig 	.bind_add	= sctp_bind_add,
97431da177e4SLinus Torvalds 	.backlog_rcv	= sctp_backlog_rcv,
97441da177e4SLinus Torvalds 	.hash		= sctp_hash,
97451da177e4SLinus Torvalds 	.unhash		= sctp_unhash,
974663dfb793SXin Long 	.no_autobind	= true,
97471da177e4SLinus Torvalds 	.obj_size	= sizeof(struct sctp6_sock),
9748f5f80e32SEric Dumazet 	.ipv6_pinfo_offset = offsetof(struct sctp6_sock, inet6),
9749ab9ee8e3SDavid Windsor 	.useroffset	= offsetof(struct sctp6_sock, sctp.subscribe),
9750ab9ee8e3SDavid Windsor 	.usersize	= offsetof(struct sctp6_sock, sctp.initmsg) -
9751ab9ee8e3SDavid Windsor 				offsetof(struct sctp6_sock, sctp.subscribe) +
9752ab9ee8e3SDavid Windsor 				sizeof_field(struct sctp6_sock, sctp.initmsg),
97534d93df0aSNeil Horman 	.sysctl_mem	= sysctl_sctp_mem,
97544d93df0aSNeil Horman 	.sysctl_rmem	= sysctl_sctp_rmem,
97554d93df0aSNeil Horman 	.sysctl_wmem	= sysctl_sctp_wmem,
97564d93df0aSNeil Horman 	.memory_pressure = &sctp_memory_pressure,
97574d93df0aSNeil Horman 	.enter_memory_pressure = sctp_enter_memory_pressure,
97580defbb0aSEric Dumazet 
97594d93df0aSNeil Horman 	.memory_allocated = &sctp_memory_allocated,
97600defbb0aSEric Dumazet 	.per_cpu_fw_alloc = &sctp_memory_per_cpu_fw_alloc,
97610defbb0aSEric Dumazet 
97625f31886fSPavel Emelyanov 	.sockets_allocated = &sctp_sockets_allocated,
97631da177e4SLinus Torvalds };
9764dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */
9765