xref: /openbmc/linux/net/sctp/socket.c (revision 0b49a65c77d8a4864e1d524dc51c6a4b8a6e1585)
147505b8bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
260c778b2SVlad Yasevich /* SCTP kernel implementation
31da177e4SLinus Torvalds  * (C) Copyright IBM Corp. 2001, 2004
41da177e4SLinus Torvalds  * Copyright (c) 1999-2000 Cisco, Inc.
51da177e4SLinus Torvalds  * Copyright (c) 1999-2001 Motorola, Inc.
61da177e4SLinus Torvalds  * Copyright (c) 2001-2003 Intel Corp.
71da177e4SLinus Torvalds  * Copyright (c) 2001-2002 Nokia, Inc.
81da177e4SLinus Torvalds  * Copyright (c) 2001 La Monte H.P. Yarroll
91da177e4SLinus Torvalds  *
1060c778b2SVlad Yasevich  * This file is part of the SCTP kernel implementation
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * These functions interface with the sockets layer to implement the
131da177e4SLinus Torvalds  * SCTP Extensions for the Sockets API.
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  * Note that the descriptions from the specification are USER level
161da177e4SLinus Torvalds  * functions--this file is the functions which populate the struct proto
171da177e4SLinus Torvalds  * for SCTP which is the BOTTOM of the sockets interface.
181da177e4SLinus Torvalds  *
191da177e4SLinus Torvalds  * Please send any bug reports or fixes you make to the
201da177e4SLinus Torvalds  * email address(es):
2191705c61SDaniel Borkmann  *    lksctp developers <linux-sctp@vger.kernel.org>
221da177e4SLinus Torvalds  *
231da177e4SLinus Torvalds  * Written or modified by:
241da177e4SLinus Torvalds  *    La Monte H.P. Yarroll <piggy@acm.org>
251da177e4SLinus Torvalds  *    Narasimha Budihal     <narsi@refcode.org>
261da177e4SLinus Torvalds  *    Karl Knutson          <karl@athena.chicago.il.us>
271da177e4SLinus Torvalds  *    Jon Grimm             <jgrimm@us.ibm.com>
281da177e4SLinus Torvalds  *    Xingang Guo           <xingang.guo@intel.com>
291da177e4SLinus Torvalds  *    Daisy Chang           <daisyc@us.ibm.com>
301da177e4SLinus Torvalds  *    Sridhar Samudrala     <samudrala@us.ibm.com>
311da177e4SLinus Torvalds  *    Inaky Perez-Gonzalez  <inaky.gonzalez@intel.com>
321da177e4SLinus Torvalds  *    Ardelle Fan	    <ardelle.fan@intel.com>
331da177e4SLinus Torvalds  *    Ryan Layer	    <rmlayer@us.ibm.com>
341da177e4SLinus Torvalds  *    Anup Pemmaiah         <pemmaiah@cc.usu.edu>
351da177e4SLinus Torvalds  *    Kevin Gao             <kevin.gao@intel.com>
361da177e4SLinus Torvalds  */
371da177e4SLinus Torvalds 
38145ce502SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
39145ce502SJoe Perches 
405821c769SHerbert Xu #include <crypto/hash.h>
411da177e4SLinus Torvalds #include <linux/types.h>
421da177e4SLinus Torvalds #include <linux/kernel.h>
431da177e4SLinus Torvalds #include <linux/wait.h>
441da177e4SLinus Torvalds #include <linux/time.h>
453f07c014SIngo Molnar #include <linux/sched/signal.h>
461da177e4SLinus Torvalds #include <linux/ip.h>
474fc268d2SRandy Dunlap #include <linux/capability.h>
481da177e4SLinus Torvalds #include <linux/fcntl.h>
491da177e4SLinus Torvalds #include <linux/poll.h>
501da177e4SLinus Torvalds #include <linux/init.h>
515a0e3ad6STejun Heo #include <linux/slab.h>
5256b31d1cSAl Viro #include <linux/file.h>
53ffd59393SDaniel Borkmann #include <linux/compat.h>
540eb71a9dSNeilBrown #include <linux/rhashtable.h>
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds #include <net/ip.h>
571da177e4SLinus Torvalds #include <net/icmp.h>
581da177e4SLinus Torvalds #include <net/route.h>
591da177e4SLinus Torvalds #include <net/ipv6.h>
601da177e4SLinus Torvalds #include <net/inet_common.h>
618465a5fcSNeil Horman #include <net/busy_poll.h>
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds #include <linux/socket.h> /* for sa_family_t */
64bc3b2d7fSPaul Gortmaker #include <linux/export.h>
651da177e4SLinus Torvalds #include <net/sock.h>
661da177e4SLinus Torvalds #include <net/sctp/sctp.h>
671da177e4SLinus Torvalds #include <net/sctp/sm.h>
6813aa8770SMarcelo Ricardo Leitner #include <net/sctp/stream_sched.h>
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds /* Forward declarations for internal helper functions. */
71cd305c74SXin Long static bool sctp_writeable(struct sock *sk);
721da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb);
73cea0cc80SXin Long static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
74a0ff6600SXin Long 				size_t msg_len);
751da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p);
761da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
771da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo);
781da177e4SLinus Torvalds static void sctp_wait_for_close(struct sock *sk, long timeo);
790a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk);
801da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
811da177e4SLinus Torvalds 					union sctp_addr *addr, int len);
821da177e4SLinus Torvalds static int sctp_bindx_add(struct sock *, struct sockaddr *, int);
831da177e4SLinus Torvalds static int sctp_bindx_rem(struct sock *, struct sockaddr *, int);
841da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int);
851da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int);
861da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc,
871da177e4SLinus Torvalds 			    struct sctp_chunk *chunk);
881da177e4SLinus Torvalds static int sctp_do_bind(struct sock *, union sctp_addr *, int);
891da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk);
9089664c62SXin Long static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
91b7ef2618SXin Long 			     struct sctp_association *assoc,
92b7ef2618SXin Long 			     enum sctp_socket_type type);
931da177e4SLinus Torvalds 
9406044751SEric Dumazet static unsigned long sctp_memory_pressure;
958d987e5cSEric Dumazet static atomic_long_t sctp_memory_allocated;
961748376bSEric Dumazet struct percpu_counter sctp_sockets_allocated;
974d93df0aSNeil Horman 
985c52ba17SPavel Emelyanov static void sctp_enter_memory_pressure(struct sock *sk)
994d93df0aSNeil Horman {
1004d93df0aSNeil Horman 	sctp_memory_pressure = 1;
1014d93df0aSNeil Horman }
1024d93df0aSNeil Horman 
1034d93df0aSNeil Horman 
1041da177e4SLinus Torvalds /* Get the sndbuf space available at the time on the association.  */
1051da177e4SLinus Torvalds static inline int sctp_wspace(struct sctp_association *asoc)
1061da177e4SLinus Torvalds {
107cd305c74SXin Long 	struct sock *sk = asoc->base.sk;
1081da177e4SLinus Torvalds 
109cd305c74SXin Long 	return asoc->ep->sndbuf_policy ? sk->sk_sndbuf - asoc->sndbuf_used
110cd305c74SXin Long 				       : sk_stream_wspace(sk);
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds /* Increment the used sndbuf space count of the corresponding association by
1141da177e4SLinus Torvalds  * the size of the outgoing data chunk.
1151da177e4SLinus Torvalds  * Also, set the skb destructor for sndbuf accounting later.
1161da177e4SLinus Torvalds  *
1171da177e4SLinus Torvalds  * Since it is always 1-1 between chunk and skb, and also a new skb is always
1181da177e4SLinus Torvalds  * allocated for chunk bundling in sctp_packet_transmit(), we can use the
1191da177e4SLinus Torvalds  * destructor in the data chunk skb for the purpose of the sndbuf space
1201da177e4SLinus Torvalds  * tracking.
1211da177e4SLinus Torvalds  */
1221da177e4SLinus Torvalds static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds 	struct sctp_association *asoc = chunk->asoc;
1251da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	/* The sndbuf space is tracked per association.  */
1281da177e4SLinus Torvalds 	sctp_association_hold(asoc);
1291da177e4SLinus Torvalds 
1301b1e0bc9SXin Long 	if (chunk->shkey)
1311b1e0bc9SXin Long 		sctp_auth_shkey_hold(chunk->shkey);
1321b1e0bc9SXin Long 
1334eb701dfSNeil Horman 	skb_set_owner_w(chunk->skb, sk);
1344eb701dfSNeil Horman 
1351da177e4SLinus Torvalds 	chunk->skb->destructor = sctp_wfree;
1361da177e4SLinus Torvalds 	/* Save the chunk pointer in skb for sctp_wfree to use later.  */
137f869c912SDaniel Borkmann 	skb_shinfo(chunk->skb)->destructor_arg = chunk;
1381da177e4SLinus Torvalds 
13914afee4bSReshetova, Elena 	refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
140605c0ac1SXin Long 	asoc->sndbuf_used += chunk->skb->truesize + sizeof(struct sctp_chunk);
141605c0ac1SXin Long 	sk->sk_wmem_queued += chunk->skb->truesize + sizeof(struct sctp_chunk);
1423ab224beSHideo Aoki 	sk_mem_charge(sk, chunk->skb->truesize);
1431da177e4SLinus Torvalds }
1441da177e4SLinus Torvalds 
145d04adf1bSXin Long static void sctp_clear_owner_w(struct sctp_chunk *chunk)
146d04adf1bSXin Long {
147d04adf1bSXin Long 	skb_orphan(chunk->skb);
148d04adf1bSXin Long }
149d04adf1bSXin Long 
1505c3e82feSQiujun Huang #define traverse_and_process()	\
1515c3e82feSQiujun Huang do {				\
1525c3e82feSQiujun Huang 	msg = chunk->msg;	\
1535c3e82feSQiujun Huang 	if (msg == prev_msg)	\
1545c3e82feSQiujun Huang 		continue;	\
1555c3e82feSQiujun Huang 	list_for_each_entry(c, &msg->chunks, frag_list) {	\
1565c3e82feSQiujun Huang 		if ((clear && asoc->base.sk == c->skb->sk) ||	\
1575c3e82feSQiujun Huang 		    (!clear && asoc->base.sk != c->skb->sk))	\
1585c3e82feSQiujun Huang 			cb(c);	\
1595c3e82feSQiujun Huang 	}			\
1605c3e82feSQiujun Huang 	prev_msg = msg;		\
1615c3e82feSQiujun Huang } while (0)
1625c3e82feSQiujun Huang 
163d04adf1bSXin Long static void sctp_for_each_tx_datachunk(struct sctp_association *asoc,
1645c3e82feSQiujun Huang 				       bool clear,
165d04adf1bSXin Long 				       void (*cb)(struct sctp_chunk *))
166d04adf1bSXin Long 
167d04adf1bSXin Long {
1685c3e82feSQiujun Huang 	struct sctp_datamsg *msg, *prev_msg = NULL;
169d04adf1bSXin Long 	struct sctp_outq *q = &asoc->outqueue;
1705c3e82feSQiujun Huang 	struct sctp_chunk *chunk, *c;
171d04adf1bSXin Long 	struct sctp_transport *t;
172d04adf1bSXin Long 
173d04adf1bSXin Long 	list_for_each_entry(t, &asoc->peer.transport_addr_list, transports)
174d04adf1bSXin Long 		list_for_each_entry(chunk, &t->transmitted, transmitted_list)
1755c3e82feSQiujun Huang 			traverse_and_process();
176d04adf1bSXin Long 
177a8dd3979SXin Long 	list_for_each_entry(chunk, &q->retransmit, transmitted_list)
1785c3e82feSQiujun Huang 		traverse_and_process();
179d04adf1bSXin Long 
180a8dd3979SXin Long 	list_for_each_entry(chunk, &q->sacked, transmitted_list)
1815c3e82feSQiujun Huang 		traverse_and_process();
182d04adf1bSXin Long 
183a8dd3979SXin Long 	list_for_each_entry(chunk, &q->abandoned, transmitted_list)
1845c3e82feSQiujun Huang 		traverse_and_process();
185d04adf1bSXin Long 
186d04adf1bSXin Long 	list_for_each_entry(chunk, &q->out_chunk_list, list)
1875c3e82feSQiujun Huang 		traverse_and_process();
188d04adf1bSXin Long }
189d04adf1bSXin Long 
19013228238SXin Long static void sctp_for_each_rx_skb(struct sctp_association *asoc, struct sock *sk,
19113228238SXin Long 				 void (*cb)(struct sk_buff *, struct sock *))
19213228238SXin Long 
19313228238SXin Long {
19413228238SXin Long 	struct sk_buff *skb, *tmp;
19513228238SXin Long 
19613228238SXin Long 	sctp_skb_for_each(skb, &asoc->ulpq.lobby, tmp)
19713228238SXin Long 		cb(skb, sk);
19813228238SXin Long 
19913228238SXin Long 	sctp_skb_for_each(skb, &asoc->ulpq.reasm, tmp)
20013228238SXin Long 		cb(skb, sk);
20113228238SXin Long 
20213228238SXin Long 	sctp_skb_for_each(skb, &asoc->ulpq.reasm_uo, tmp)
20313228238SXin Long 		cb(skb, sk);
20413228238SXin Long }
20513228238SXin Long 
2061da177e4SLinus Torvalds /* Verify that this is a valid address. */
2071da177e4SLinus Torvalds static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
2081da177e4SLinus Torvalds 				   int len)
2091da177e4SLinus Torvalds {
2101da177e4SLinus Torvalds 	struct sctp_af *af;
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	/* Verify basic sockaddr. */
2131da177e4SLinus Torvalds 	af = sctp_sockaddr_af(sctp_sk(sk), addr, len);
2141da177e4SLinus Torvalds 	if (!af)
2151da177e4SLinus Torvalds 		return -EINVAL;
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	/* Is this a valid SCTP address?  */
2185636bef7SVlad Yasevich 	if (!af->addr_valid(addr, sctp_sk(sk), NULL))
2191da177e4SLinus Torvalds 		return -EINVAL;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr)))
2221da177e4SLinus Torvalds 		return -EINVAL;
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds 	return 0;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds /* Look up the association by its id.  If this is not a UDP-style
2281da177e4SLinus Torvalds  * socket, the ID field is always ignored.
2291da177e4SLinus Torvalds  */
2301da177e4SLinus Torvalds struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
2311da177e4SLinus Torvalds {
2321da177e4SLinus Torvalds 	struct sctp_association *asoc = NULL;
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 	/* If this is not a UDP-style socket, assoc id should be ignored. */
2351da177e4SLinus Torvalds 	if (!sctp_style(sk, UDP)) {
2361da177e4SLinus Torvalds 		/* Return NULL if the socket state is not ESTABLISHED. It
2371da177e4SLinus Torvalds 		 * could be a TCP-style listening socket or a socket which
2381da177e4SLinus Torvalds 		 * hasn't yet called connect() to establish an association.
2391da177e4SLinus Torvalds 		 */
240e5b13f34SMarcelo Ricardo Leitner 		if (!sctp_sstate(sk, ESTABLISHED) && !sctp_sstate(sk, CLOSING))
2411da177e4SLinus Torvalds 			return NULL;
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 		/* Get the first and the only association from the list. */
2441da177e4SLinus Torvalds 		if (!list_empty(&sctp_sk(sk)->ep->asocs))
2451da177e4SLinus Torvalds 			asoc = list_entry(sctp_sk(sk)->ep->asocs.next,
2461da177e4SLinus Torvalds 					  struct sctp_association, asocs);
2471da177e4SLinus Torvalds 		return asoc;
2481da177e4SLinus Torvalds 	}
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	/* Otherwise this is a UDP-style socket. */
25180df2704SXin Long 	if (id <= SCTP_ALL_ASSOC)
2521da177e4SLinus Torvalds 		return NULL;
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	spin_lock_bh(&sctp_assocs_id_lock);
2551da177e4SLinus Torvalds 	asoc = (struct sctp_association *)idr_find(&sctp_assocs_id, (int)id);
256b336decaSMarcelo Ricardo Leitner 	if (asoc && (asoc->base.sk != sk || asoc->base.dead))
257b336decaSMarcelo Ricardo Leitner 		asoc = NULL;
2581da177e4SLinus Torvalds 	spin_unlock_bh(&sctp_assocs_id_lock);
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	return asoc;
2611da177e4SLinus Torvalds }
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds /* Look up the transport from an address and an assoc id. If both address and
2641da177e4SLinus Torvalds  * id are specified, the associations matching the address and the id should be
2651da177e4SLinus Torvalds  * the same.
2661da177e4SLinus Torvalds  */
2671da177e4SLinus Torvalds static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
2681da177e4SLinus Torvalds 					      struct sockaddr_storage *addr,
2691da177e4SLinus Torvalds 					      sctp_assoc_t id)
2701da177e4SLinus Torvalds {
2711da177e4SLinus Torvalds 	struct sctp_association *addr_asoc = NULL, *id_asoc = NULL;
2726f29a130SXin Long 	struct sctp_af *af = sctp_get_af_specific(addr->ss_family);
2731da177e4SLinus Torvalds 	union sctp_addr *laddr = (union sctp_addr *)addr;
2746f29a130SXin Long 	struct sctp_transport *transport;
2756f29a130SXin Long 
276912964eaSXin Long 	if (!af || sctp_verify_addr(sk, laddr, af->sockaddr_len))
2776f29a130SXin Long 		return NULL;
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep,
280cd4ff034SAl Viro 					       laddr,
2811da177e4SLinus Torvalds 					       &transport);
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	if (!addr_asoc)
2841da177e4SLinus Torvalds 		return NULL;
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	id_asoc = sctp_id2assoc(sk, id);
2871da177e4SLinus Torvalds 	if (id_asoc && (id_asoc != addr_asoc))
2881da177e4SLinus Torvalds 		return NULL;
2891da177e4SLinus Torvalds 
290299ee123SJason Gunthorpe 	sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk),
2911da177e4SLinus Torvalds 						(union sctp_addr *)addr);
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 	return transport;
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds /* API 3.1.2 bind() - UDP Style Syntax
2971da177e4SLinus Torvalds  * The syntax of bind() is,
2981da177e4SLinus Torvalds  *
2991da177e4SLinus Torvalds  *   ret = bind(int sd, struct sockaddr *addr, int addrlen);
3001da177e4SLinus Torvalds  *
3011da177e4SLinus Torvalds  *   sd      - the socket descriptor returned by socket().
3021da177e4SLinus Torvalds  *   addr    - the address structure (struct sockaddr_in or struct
3031da177e4SLinus Torvalds  *             sockaddr_in6 [RFC 2553]),
3041da177e4SLinus Torvalds  *   addr_len - the size of the address structure.
3051da177e4SLinus Torvalds  */
306dda91928SDaniel Borkmann static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len)
3071da177e4SLinus Torvalds {
3081da177e4SLinus Torvalds 	int retval = 0;
3091da177e4SLinus Torvalds 
310048ed4b6Swangweidong 	lock_sock(sk);
3111da177e4SLinus Torvalds 
312bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addr:%p, addr_len:%d\n", __func__, sk,
313bb33381dSDaniel Borkmann 		 addr, addr_len);
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	/* Disallow binding twice. */
3161da177e4SLinus Torvalds 	if (!sctp_sk(sk)->ep->base.bind_addr.port)
3173f7a87d2SFrank Filz 		retval = sctp_do_bind(sk, (union sctp_addr *)addr,
3181da177e4SLinus Torvalds 				      addr_len);
3191da177e4SLinus Torvalds 	else
3201da177e4SLinus Torvalds 		retval = -EINVAL;
3211da177e4SLinus Torvalds 
322048ed4b6Swangweidong 	release_sock(sk);
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 	return retval;
3251da177e4SLinus Torvalds }
3261da177e4SLinus Torvalds 
3278e2ef6abSMao Wenan static int sctp_get_port_local(struct sock *, union sctp_addr *);
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds /* Verify this is a valid sockaddr. */
3301da177e4SLinus Torvalds static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
3311da177e4SLinus Torvalds 					union sctp_addr *addr, int len)
3321da177e4SLinus Torvalds {
3331da177e4SLinus Torvalds 	struct sctp_af *af;
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	/* Check minimum size.  */
3361da177e4SLinus Torvalds 	if (len < sizeof (struct sockaddr))
3371da177e4SLinus Torvalds 		return NULL;
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	if (!opt->pf->af_supported(addr->sa.sa_family, opt))
3401da177e4SLinus Torvalds 		return NULL;
341c5006b8aSXin Long 
34281e98370SEric Dumazet 	if (addr->sa.sa_family == AF_INET6) {
34381e98370SEric Dumazet 		if (len < SIN6_LEN_RFC2133)
34481e98370SEric Dumazet 			return NULL;
345c5006b8aSXin Long 		/* V4 mapped address are really of AF_INET family */
34681e98370SEric Dumazet 		if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
347c5006b8aSXin Long 		    !opt->pf->af_supported(AF_INET, opt))
348c5006b8aSXin Long 			return NULL;
34981e98370SEric Dumazet 	}
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds 	/* If we get this far, af is valid. */
3521da177e4SLinus Torvalds 	af = sctp_get_af_specific(addr->sa.sa_family);
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 	if (len < af->sockaddr_len)
3551da177e4SLinus Torvalds 		return NULL;
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	return af;
3581da177e4SLinus Torvalds }
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds /* Bind a local address either to an endpoint or to an association.  */
361dda91928SDaniel Borkmann static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
3621da177e4SLinus Torvalds {
3633594698aSEric W. Biederman 	struct net *net = sock_net(sk);
3641da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
3651da177e4SLinus Torvalds 	struct sctp_endpoint *ep = sp->ep;
3661da177e4SLinus Torvalds 	struct sctp_bind_addr *bp = &ep->base.bind_addr;
3671da177e4SLinus Torvalds 	struct sctp_af *af;
3681da177e4SLinus Torvalds 	unsigned short snum;
3691da177e4SLinus Torvalds 	int ret = 0;
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	/* Common sockaddr verification. */
3721da177e4SLinus Torvalds 	af = sctp_sockaddr_af(sp, addr, len);
3733f7a87d2SFrank Filz 	if (!af) {
374bb33381dSDaniel Borkmann 		pr_debug("%s: sk:%p, newaddr:%p, len:%d EINVAL\n",
375bb33381dSDaniel Borkmann 			 __func__, sk, addr, len);
3761da177e4SLinus Torvalds 		return -EINVAL;
3773f7a87d2SFrank Filz 	}
3783f7a87d2SFrank Filz 
3793f7a87d2SFrank Filz 	snum = ntohs(addr->v4.sin_port);
3803f7a87d2SFrank Filz 
381bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, new addr:%pISc, port:%d, new port:%d, len:%d\n",
382bb33381dSDaniel Borkmann 		 __func__, sk, &addr->sa, bp->port, snum, len);
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds 	/* PF specific bind() address verification. */
3851da177e4SLinus Torvalds 	if (!sp->pf->bind_verify(sp, addr))
3861da177e4SLinus Torvalds 		return -EADDRNOTAVAIL;
3871da177e4SLinus Torvalds 
3888b358056SVlad Yasevich 	/* We must either be unbound, or bind to the same port.
3898b358056SVlad Yasevich 	 * It's OK to allow 0 ports if we are already bound.
3908b358056SVlad Yasevich 	 * We'll just inhert an already bound port in this case
3918b358056SVlad Yasevich 	 */
3928b358056SVlad Yasevich 	if (bp->port) {
3938b358056SVlad Yasevich 		if (!snum)
3948b358056SVlad Yasevich 			snum = bp->port;
3958b358056SVlad Yasevich 		else if (snum != bp->port) {
396bb33381dSDaniel Borkmann 			pr_debug("%s: new port %d doesn't match existing port "
397bb33381dSDaniel Borkmann 				 "%d\n", __func__, snum, bp->port);
3981da177e4SLinus Torvalds 			return -EINVAL;
3991da177e4SLinus Torvalds 		}
4008b358056SVlad Yasevich 	}
4011da177e4SLinus Torvalds 
40282f31ebfSMaciej Żenczykowski 	if (snum && inet_port_requires_bind_service(net, snum) &&
4033594698aSEric W. Biederman 	    !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
4041da177e4SLinus Torvalds 		return -EACCES;
4051da177e4SLinus Torvalds 
4064e54064eSVlad Yasevich 	/* See if the address matches any of the addresses we may have
4074e54064eSVlad Yasevich 	 * already bound before checking against other endpoints.
4084e54064eSVlad Yasevich 	 */
4094e54064eSVlad Yasevich 	if (sctp_bind_addr_match(bp, addr, sp))
4104e54064eSVlad Yasevich 		return -EINVAL;
4114e54064eSVlad Yasevich 
4121da177e4SLinus Torvalds 	/* Make sure we are allowed to bind here.
4131da177e4SLinus Torvalds 	 * The function sctp_get_port_local() does duplicate address
4141da177e4SLinus Torvalds 	 * detection.
4151da177e4SLinus Torvalds 	 */
4162772b495SVlad Yasevich 	addr->v4.sin_port = htons(snum);
417e0e4b8deSMao Wenan 	if (sctp_get_port_local(sk, addr))
4181da177e4SLinus Torvalds 		return -EADDRINUSE;
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 	/* Refresh ephemeral port.  */
4211da177e4SLinus Torvalds 	if (!bp->port)
422c720c7e8SEric Dumazet 		bp->port = inet_sk(sk)->inet_num;
4231da177e4SLinus Torvalds 
424559cf710SVlad Yasevich 	/* Add the address to the bind address list.
425559cf710SVlad Yasevich 	 * Use GFP_ATOMIC since BHs will be disabled.
426559cf710SVlad Yasevich 	 */
427133800d1SMarcelo Ricardo Leitner 	ret = sctp_add_bind_addr(bp, addr, af->sockaddr_len,
428133800d1SMarcelo Ricardo Leitner 				 SCTP_ADDR_SRC, GFP_ATOMIC);
4291da177e4SLinus Torvalds 
43029b99f54SMao Wenan 	if (ret) {
43129b99f54SMao Wenan 		sctp_put_port(sk);
43229b99f54SMao Wenan 		return ret;
43329b99f54SMao Wenan 	}
4341da177e4SLinus Torvalds 	/* Copy back into socket for getsockname() use. */
435c720c7e8SEric Dumazet 	inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
436299ee123SJason Gunthorpe 	sp->pf->to_sk_saddr(addr, sk);
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds 	return ret;
4391da177e4SLinus Torvalds }
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds  /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks
4421da177e4SLinus Torvalds  *
4431da177e4SLinus Torvalds  * R1) One and only one ASCONF Chunk MAY be in transit and unacknowledged
4441da177e4SLinus Torvalds  * at any one time.  If a sender, after sending an ASCONF chunk, decides
4451da177e4SLinus Torvalds  * it needs to transfer another ASCONF Chunk, it MUST wait until the
4461da177e4SLinus Torvalds  * ASCONF-ACK Chunk returns from the previous ASCONF Chunk before sending a
4471da177e4SLinus Torvalds  * subsequent ASCONF. Note this restriction binds each side, so at any
4481da177e4SLinus Torvalds  * time two ASCONF may be in-transit on any given association (one sent
4491da177e4SLinus Torvalds  * from each endpoint).
4501da177e4SLinus Torvalds  */
4511da177e4SLinus Torvalds static int sctp_send_asconf(struct sctp_association *asoc,
4521da177e4SLinus Torvalds 			    struct sctp_chunk *chunk)
4531da177e4SLinus Torvalds {
4541da177e4SLinus Torvalds 	int retval = 0;
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 	/* If there is an outstanding ASCONF chunk, queue it for later
4571da177e4SLinus Torvalds 	 * transmission.
4581da177e4SLinus Torvalds 	 */
4591da177e4SLinus Torvalds 	if (asoc->addip_last_asconf) {
46079af02c2SDavid S. Miller 		list_add_tail(&chunk->list, &asoc->addip_chunk_list);
4611da177e4SLinus Torvalds 		goto out;
4621da177e4SLinus Torvalds 	}
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 	/* Hold the chunk until an ASCONF_ACK is received. */
4651da177e4SLinus Torvalds 	sctp_chunk_hold(chunk);
4664e7696d9SXin Long 	retval = sctp_primitive_ASCONF(asoc->base.net, asoc, chunk);
4671da177e4SLinus Torvalds 	if (retval)
4681da177e4SLinus Torvalds 		sctp_chunk_free(chunk);
4691da177e4SLinus Torvalds 	else
4701da177e4SLinus Torvalds 		asoc->addip_last_asconf = chunk;
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds out:
4731da177e4SLinus Torvalds 	return retval;
4741da177e4SLinus Torvalds }
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds /* Add a list of addresses as bind addresses to local endpoint or
4771da177e4SLinus Torvalds  * association.
4781da177e4SLinus Torvalds  *
4791da177e4SLinus Torvalds  * Basically run through each address specified in the addrs/addrcnt
4801da177e4SLinus Torvalds  * array/length pair, determine if it is IPv6 or IPv4 and call
4811da177e4SLinus Torvalds  * sctp_do_bind() on it.
4821da177e4SLinus Torvalds  *
4831da177e4SLinus Torvalds  * If any of them fails, then the operation will be reversed and the
4841da177e4SLinus Torvalds  * ones that were added will be removed.
4851da177e4SLinus Torvalds  *
4861da177e4SLinus Torvalds  * Only sctp_setsockopt_bindx() is supposed to call this function.
4871da177e4SLinus Torvalds  */
48804675210Ssebastian@breakpoint.cc static int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt)
4891da177e4SLinus Torvalds {
4901da177e4SLinus Torvalds 	int cnt;
4911da177e4SLinus Torvalds 	int retval = 0;
4921da177e4SLinus Torvalds 	void *addr_buf;
4931da177e4SLinus Torvalds 	struct sockaddr *sa_addr;
4941da177e4SLinus Torvalds 	struct sctp_af *af;
4951da177e4SLinus Torvalds 
496bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n", __func__, sk,
497bb33381dSDaniel Borkmann 		 addrs, addrcnt);
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds 	addr_buf = addrs;
5001da177e4SLinus Torvalds 	for (cnt = 0; cnt < addrcnt; cnt++) {
5011da177e4SLinus Torvalds 		/* The list may contain either IPv4 or IPv6 address;
5021da177e4SLinus Torvalds 		 * determine the address length for walking thru the list.
5031da177e4SLinus Torvalds 		 */
504ea110733SJoe Perches 		sa_addr = addr_buf;
5051da177e4SLinus Torvalds 		af = sctp_get_af_specific(sa_addr->sa_family);
5061da177e4SLinus Torvalds 		if (!af) {
5071da177e4SLinus Torvalds 			retval = -EINVAL;
5081da177e4SLinus Torvalds 			goto err_bindx_add;
5091da177e4SLinus Torvalds 		}
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 		retval = sctp_do_bind(sk, (union sctp_addr *)sa_addr,
5121da177e4SLinus Torvalds 				      af->sockaddr_len);
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 		addr_buf += af->sockaddr_len;
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds err_bindx_add:
5171da177e4SLinus Torvalds 		if (retval < 0) {
5181da177e4SLinus Torvalds 			/* Failed. Cleanup the ones that have been added */
5191da177e4SLinus Torvalds 			if (cnt > 0)
5201da177e4SLinus Torvalds 				sctp_bindx_rem(sk, addrs, cnt);
5211da177e4SLinus Torvalds 			return retval;
5221da177e4SLinus Torvalds 		}
5231da177e4SLinus Torvalds 	}
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds 	return retval;
5261da177e4SLinus Torvalds }
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds /* Send an ASCONF chunk with Add IP address parameters to all the peers of the
5291da177e4SLinus Torvalds  * associations that are part of the endpoint indicating that a list of local
5301da177e4SLinus Torvalds  * addresses are added to the endpoint.
5311da177e4SLinus Torvalds  *
5321da177e4SLinus Torvalds  * If any of the addresses is already in the bind address list of the
5331da177e4SLinus Torvalds  * association, we do not send the chunk for that association.  But it will not
5341da177e4SLinus Torvalds  * affect other associations.
5351da177e4SLinus Torvalds  *
5361da177e4SLinus Torvalds  * Only sctp_setsockopt_bindx() is supposed to call this function.
5371da177e4SLinus Torvalds  */
5381da177e4SLinus Torvalds static int sctp_send_asconf_add_ip(struct sock		*sk,
5391da177e4SLinus Torvalds 				   struct sockaddr	*addrs,
5401da177e4SLinus Torvalds 				   int 			addrcnt)
5411da177e4SLinus Torvalds {
5421da177e4SLinus Torvalds 	struct sctp_sock		*sp;
5431da177e4SLinus Torvalds 	struct sctp_endpoint		*ep;
5441da177e4SLinus Torvalds 	struct sctp_association		*asoc;
5451da177e4SLinus Torvalds 	struct sctp_bind_addr		*bp;
5461da177e4SLinus Torvalds 	struct sctp_chunk		*chunk;
5471da177e4SLinus Torvalds 	struct sctp_sockaddr_entry	*laddr;
5481da177e4SLinus Torvalds 	union sctp_addr			*addr;
549dc022a98SSridhar Samudrala 	union sctp_addr			saveaddr;
5501da177e4SLinus Torvalds 	void				*addr_buf;
5511da177e4SLinus Torvalds 	struct sctp_af			*af;
5521da177e4SLinus Torvalds 	struct list_head		*p;
5531da177e4SLinus Torvalds 	int 				i;
5541da177e4SLinus Torvalds 	int 				retval = 0;
5551da177e4SLinus Torvalds 
5561da177e4SLinus Torvalds 	sp = sctp_sk(sk);
5571da177e4SLinus Torvalds 	ep = sp->ep;
5581da177e4SLinus Torvalds 
5594e27428fSXin Long 	if (!ep->asconf_enable)
5604e27428fSXin Long 		return retval;
5614e27428fSXin Long 
562bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
5630dc47877SHarvey Harrison 		 __func__, sk, addrs, addrcnt);
5641da177e4SLinus Torvalds 
5659dbc15f0SRobert P. J. Day 	list_for_each_entry(asoc, &ep->asocs, asocs) {
5661da177e4SLinus Torvalds 		if (!asoc->peer.asconf_capable)
5671da177e4SLinus Torvalds 			continue;
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 		if (asoc->peer.addip_disabled_mask & SCTP_PARAM_ADD_IP)
5701da177e4SLinus Torvalds 			continue;
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds 		if (!sctp_state(asoc, ESTABLISHED))
5731da177e4SLinus Torvalds 			continue;
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 		/* Check if any address in the packed array of addresses is
5761da177e4SLinus Torvalds 		 * in the bind address list of the association. If so,
5771da177e4SLinus Torvalds 		 * do not send the asconf chunk to its peer, but continue with
5781da177e4SLinus Torvalds 		 * other associations.
5791da177e4SLinus Torvalds 		 */
5801da177e4SLinus Torvalds 		addr_buf = addrs;
5811da177e4SLinus Torvalds 		for (i = 0; i < addrcnt; i++) {
582ea110733SJoe Perches 			addr = addr_buf;
5831da177e4SLinus Torvalds 			af = sctp_get_af_specific(addr->v4.sin_family);
5841da177e4SLinus Torvalds 			if (!af) {
5851da177e4SLinus Torvalds 				retval = -EINVAL;
5861da177e4SLinus Torvalds 				goto out;
5871da177e4SLinus Torvalds 			}
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds 			if (sctp_assoc_lookup_laddr(asoc, addr))
5901da177e4SLinus Torvalds 				break;
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds 			addr_buf += af->sockaddr_len;
5931da177e4SLinus Torvalds 		}
5941da177e4SLinus Torvalds 		if (i < addrcnt)
5951da177e4SLinus Torvalds 			continue;
5961da177e4SLinus Torvalds 
597559cf710SVlad Yasevich 		/* Use the first valid address in bind addr list of
598559cf710SVlad Yasevich 		 * association as Address Parameter of ASCONF CHUNK.
5991da177e4SLinus Torvalds 		 */
6001da177e4SLinus Torvalds 		bp = &asoc->base.bind_addr;
6011da177e4SLinus Torvalds 		p = bp->address_list.next;
6021da177e4SLinus Torvalds 		laddr = list_entry(p, struct sctp_sockaddr_entry, list);
6035ae955cfSAl Viro 		chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs,
6041da177e4SLinus Torvalds 						   addrcnt, SCTP_PARAM_ADD_IP);
6051da177e4SLinus Torvalds 		if (!chunk) {
6061da177e4SLinus Torvalds 			retval = -ENOMEM;
6071da177e4SLinus Torvalds 			goto out;
6081da177e4SLinus Torvalds 		}
6091da177e4SLinus Torvalds 
610dc022a98SSridhar Samudrala 		/* Add the new addresses to the bind address list with
611dc022a98SSridhar Samudrala 		 * use_as_src set to 0.
6121da177e4SLinus Torvalds 		 */
613dc022a98SSridhar Samudrala 		addr_buf = addrs;
614dc022a98SSridhar Samudrala 		for (i = 0; i < addrcnt; i++) {
615ea110733SJoe Perches 			addr = addr_buf;
616dc022a98SSridhar Samudrala 			af = sctp_get_af_specific(addr->v4.sin_family);
617dc022a98SSridhar Samudrala 			memcpy(&saveaddr, addr, af->sockaddr_len);
618f57d96b2SVlad Yasevich 			retval = sctp_add_bind_addr(bp, &saveaddr,
619133800d1SMarcelo Ricardo Leitner 						    sizeof(saveaddr),
620f57d96b2SVlad Yasevich 						    SCTP_ADDR_NEW, GFP_ATOMIC);
621dc022a98SSridhar Samudrala 			addr_buf += af->sockaddr_len;
622dc022a98SSridhar Samudrala 		}
6238a07eb0aSMichio Honda 		if (asoc->src_out_of_asoc_ok) {
6248a07eb0aSMichio Honda 			struct sctp_transport *trans;
6258a07eb0aSMichio Honda 
6268a07eb0aSMichio Honda 			list_for_each_entry(trans,
6278a07eb0aSMichio Honda 			    &asoc->peer.transport_addr_list, transports) {
6288a07eb0aSMichio Honda 				trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
6298a07eb0aSMichio Honda 				    2*asoc->pathmtu, 4380));
6308a07eb0aSMichio Honda 				trans->ssthresh = asoc->peer.i.a_rwnd;
6318a07eb0aSMichio Honda 				trans->rto = asoc->rto_initial;
632196d6759SMichele Baldessari 				sctp_max_rto(asoc, trans);
6338a07eb0aSMichio Honda 				trans->rtt = trans->srtt = trans->rttvar = 0;
6346e91b578SMarcelo Ricardo Leitner 				/* Clear the source and route cache */
6358a07eb0aSMichio Honda 				sctp_transport_route(trans, NULL,
6368a07eb0aSMichio Honda 						     sctp_sk(asoc->base.sk));
6378a07eb0aSMichio Honda 			}
6388a07eb0aSMichio Honda 		}
6398a07eb0aSMichio Honda 		retval = sctp_send_asconf(asoc, chunk);
6401da177e4SLinus Torvalds 	}
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds out:
6431da177e4SLinus Torvalds 	return retval;
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds /* Remove a list of addresses from bind addresses list.  Do not remove the
6471da177e4SLinus Torvalds  * last address.
6481da177e4SLinus Torvalds  *
6491da177e4SLinus Torvalds  * Basically run through each address specified in the addrs/addrcnt
6501da177e4SLinus Torvalds  * array/length pair, determine if it is IPv6 or IPv4 and call
6511da177e4SLinus Torvalds  * sctp_del_bind() on it.
6521da177e4SLinus Torvalds  *
6531da177e4SLinus Torvalds  * If any of them fails, then the operation will be reversed and the
6541da177e4SLinus Torvalds  * ones that were removed will be added back.
6551da177e4SLinus Torvalds  *
6561da177e4SLinus Torvalds  * At least one address has to be left; if only one address is
6571da177e4SLinus Torvalds  * available, the operation will return -EBUSY.
6581da177e4SLinus Torvalds  *
6591da177e4SLinus Torvalds  * Only sctp_setsockopt_bindx() is supposed to call this function.
6601da177e4SLinus Torvalds  */
66104675210Ssebastian@breakpoint.cc static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
6621da177e4SLinus Torvalds {
6631da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
6641da177e4SLinus Torvalds 	struct sctp_endpoint *ep = sp->ep;
6651da177e4SLinus Torvalds 	int cnt;
6661da177e4SLinus Torvalds 	struct sctp_bind_addr *bp = &ep->base.bind_addr;
6671da177e4SLinus Torvalds 	int retval = 0;
6681da177e4SLinus Torvalds 	void *addr_buf;
669c9a08505SAl Viro 	union sctp_addr *sa_addr;
6701da177e4SLinus Torvalds 	struct sctp_af *af;
6711da177e4SLinus Torvalds 
672bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
673bb33381dSDaniel Borkmann 		 __func__, sk, addrs, addrcnt);
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds 	addr_buf = addrs;
6761da177e4SLinus Torvalds 	for (cnt = 0; cnt < addrcnt; cnt++) {
6771da177e4SLinus Torvalds 		/* If the bind address list is empty or if there is only one
6781da177e4SLinus Torvalds 		 * bind address, there is nothing more to be removed (we need
6791da177e4SLinus Torvalds 		 * at least one address here).
6801da177e4SLinus Torvalds 		 */
6811da177e4SLinus Torvalds 		if (list_empty(&bp->address_list) ||
6821da177e4SLinus Torvalds 		    (sctp_list_single_entry(&bp->address_list))) {
6831da177e4SLinus Torvalds 			retval = -EBUSY;
6841da177e4SLinus Torvalds 			goto err_bindx_rem;
6851da177e4SLinus Torvalds 		}
6861da177e4SLinus Torvalds 
687ea110733SJoe Perches 		sa_addr = addr_buf;
688c9a08505SAl Viro 		af = sctp_get_af_specific(sa_addr->sa.sa_family);
6891da177e4SLinus Torvalds 		if (!af) {
6901da177e4SLinus Torvalds 			retval = -EINVAL;
6911da177e4SLinus Torvalds 			goto err_bindx_rem;
6921da177e4SLinus Torvalds 		}
6930304ff8aSPaolo Galtieri 
6940304ff8aSPaolo Galtieri 		if (!af->addr_valid(sa_addr, sp, NULL)) {
6950304ff8aSPaolo Galtieri 			retval = -EADDRNOTAVAIL;
6960304ff8aSPaolo Galtieri 			goto err_bindx_rem;
6970304ff8aSPaolo Galtieri 		}
6980304ff8aSPaolo Galtieri 
699ee9cbacaSVlad Yasevich 		if (sa_addr->v4.sin_port &&
700ee9cbacaSVlad Yasevich 		    sa_addr->v4.sin_port != htons(bp->port)) {
7011da177e4SLinus Torvalds 			retval = -EINVAL;
7021da177e4SLinus Torvalds 			goto err_bindx_rem;
7031da177e4SLinus Torvalds 		}
7041da177e4SLinus Torvalds 
705ee9cbacaSVlad Yasevich 		if (!sa_addr->v4.sin_port)
706ee9cbacaSVlad Yasevich 			sa_addr->v4.sin_port = htons(bp->port);
707ee9cbacaSVlad Yasevich 
7081da177e4SLinus Torvalds 		/* FIXME - There is probably a need to check if sk->sk_saddr and
7091da177e4SLinus Torvalds 		 * sk->sk_rcv_addr are currently set to one of the addresses to
7101da177e4SLinus Torvalds 		 * be removed. This is something which needs to be looked into
7111da177e4SLinus Torvalds 		 * when we are fixing the outstanding issues with multi-homing
7121da177e4SLinus Torvalds 		 * socket routing and failover schemes. Refer to comments in
7131da177e4SLinus Torvalds 		 * sctp_do_bind(). -daisy
7141da177e4SLinus Torvalds 		 */
7150ed90fb0SVlad Yasevich 		retval = sctp_del_bind_addr(bp, sa_addr);
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 		addr_buf += af->sockaddr_len;
7181da177e4SLinus Torvalds err_bindx_rem:
7191da177e4SLinus Torvalds 		if (retval < 0) {
7201da177e4SLinus Torvalds 			/* Failed. Add the ones that has been removed back */
7211da177e4SLinus Torvalds 			if (cnt > 0)
7221da177e4SLinus Torvalds 				sctp_bindx_add(sk, addrs, cnt);
7231da177e4SLinus Torvalds 			return retval;
7241da177e4SLinus Torvalds 		}
7251da177e4SLinus Torvalds 	}
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 	return retval;
7281da177e4SLinus Torvalds }
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds /* Send an ASCONF chunk with Delete IP address parameters to all the peers of
7311da177e4SLinus Torvalds  * the associations that are part of the endpoint indicating that a list of
7321da177e4SLinus Torvalds  * local addresses are removed from the endpoint.
7331da177e4SLinus Torvalds  *
7341da177e4SLinus Torvalds  * If any of the addresses is already in the bind address list of the
7351da177e4SLinus Torvalds  * association, we do not send the chunk for that association.  But it will not
7361da177e4SLinus Torvalds  * affect other associations.
7371da177e4SLinus Torvalds  *
7381da177e4SLinus Torvalds  * Only sctp_setsockopt_bindx() is supposed to call this function.
7391da177e4SLinus Torvalds  */
7401da177e4SLinus Torvalds static int sctp_send_asconf_del_ip(struct sock		*sk,
7411da177e4SLinus Torvalds 				   struct sockaddr	*addrs,
7421da177e4SLinus Torvalds 				   int			addrcnt)
7431da177e4SLinus Torvalds {
7441da177e4SLinus Torvalds 	struct sctp_sock	*sp;
7451da177e4SLinus Torvalds 	struct sctp_endpoint	*ep;
7461da177e4SLinus Torvalds 	struct sctp_association	*asoc;
747dc022a98SSridhar Samudrala 	struct sctp_transport	*transport;
7481da177e4SLinus Torvalds 	struct sctp_bind_addr	*bp;
7491da177e4SLinus Torvalds 	struct sctp_chunk	*chunk;
7501da177e4SLinus Torvalds 	union sctp_addr		*laddr;
7511da177e4SLinus Torvalds 	void			*addr_buf;
7521da177e4SLinus Torvalds 	struct sctp_af		*af;
753dc022a98SSridhar Samudrala 	struct sctp_sockaddr_entry *saddr;
7541da177e4SLinus Torvalds 	int 			i;
7551da177e4SLinus Torvalds 	int 			retval = 0;
7568a07eb0aSMichio Honda 	int			stored = 0;
7571da177e4SLinus Torvalds 
7588a07eb0aSMichio Honda 	chunk = NULL;
7591da177e4SLinus Torvalds 	sp = sctp_sk(sk);
7601da177e4SLinus Torvalds 	ep = sp->ep;
7611da177e4SLinus Torvalds 
7624e27428fSXin Long 	if (!ep->asconf_enable)
7634e27428fSXin Long 		return retval;
7644e27428fSXin Long 
765bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, addrs:%p, addrcnt:%d\n",
7660dc47877SHarvey Harrison 		 __func__, sk, addrs, addrcnt);
7671da177e4SLinus Torvalds 
7689dbc15f0SRobert P. J. Day 	list_for_each_entry(asoc, &ep->asocs, asocs) {
7691da177e4SLinus Torvalds 
7701da177e4SLinus Torvalds 		if (!asoc->peer.asconf_capable)
7711da177e4SLinus Torvalds 			continue;
7721da177e4SLinus Torvalds 
7731da177e4SLinus Torvalds 		if (asoc->peer.addip_disabled_mask & SCTP_PARAM_DEL_IP)
7741da177e4SLinus Torvalds 			continue;
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds 		if (!sctp_state(asoc, ESTABLISHED))
7771da177e4SLinus Torvalds 			continue;
7781da177e4SLinus Torvalds 
7791da177e4SLinus Torvalds 		/* Check if any address in the packed array of addresses is
7801da177e4SLinus Torvalds 		 * not present in the bind address list of the association.
7811da177e4SLinus Torvalds 		 * If so, do not send the asconf chunk to its peer, but
7821da177e4SLinus Torvalds 		 * continue with other associations.
7831da177e4SLinus Torvalds 		 */
7841da177e4SLinus Torvalds 		addr_buf = addrs;
7851da177e4SLinus Torvalds 		for (i = 0; i < addrcnt; i++) {
786ea110733SJoe Perches 			laddr = addr_buf;
7871da177e4SLinus Torvalds 			af = sctp_get_af_specific(laddr->v4.sin_family);
7881da177e4SLinus Torvalds 			if (!af) {
7891da177e4SLinus Torvalds 				retval = -EINVAL;
7901da177e4SLinus Torvalds 				goto out;
7911da177e4SLinus Torvalds 			}
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds 			if (!sctp_assoc_lookup_laddr(asoc, laddr))
7941da177e4SLinus Torvalds 				break;
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds 			addr_buf += af->sockaddr_len;
7971da177e4SLinus Torvalds 		}
7981da177e4SLinus Torvalds 		if (i < addrcnt)
7991da177e4SLinus Torvalds 			continue;
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds 		/* Find one address in the association's bind address list
8021da177e4SLinus Torvalds 		 * that is not in the packed array of addresses. This is to
8031da177e4SLinus Torvalds 		 * make sure that we do not delete all the addresses in the
8041da177e4SLinus Torvalds 		 * association.
8051da177e4SLinus Torvalds 		 */
8061da177e4SLinus Torvalds 		bp = &asoc->base.bind_addr;
8071da177e4SLinus Torvalds 		laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
8081da177e4SLinus Torvalds 					       addrcnt, sp);
8098a07eb0aSMichio Honda 		if ((laddr == NULL) && (addrcnt == 1)) {
8108a07eb0aSMichio Honda 			if (asoc->asconf_addr_del_pending)
8111da177e4SLinus Torvalds 				continue;
8128a07eb0aSMichio Honda 			asoc->asconf_addr_del_pending =
8138a07eb0aSMichio Honda 			    kzalloc(sizeof(union sctp_addr), GFP_ATOMIC);
8146d65e5eeSMichio Honda 			if (asoc->asconf_addr_del_pending == NULL) {
8156d65e5eeSMichio Honda 				retval = -ENOMEM;
8166d65e5eeSMichio Honda 				goto out;
8176d65e5eeSMichio Honda 			}
8188a07eb0aSMichio Honda 			asoc->asconf_addr_del_pending->sa.sa_family =
8198a07eb0aSMichio Honda 				    addrs->sa_family;
8208a07eb0aSMichio Honda 			asoc->asconf_addr_del_pending->v4.sin_port =
8218a07eb0aSMichio Honda 				    htons(bp->port);
8228a07eb0aSMichio Honda 			if (addrs->sa_family == AF_INET) {
8238a07eb0aSMichio Honda 				struct sockaddr_in *sin;
8248a07eb0aSMichio Honda 
8258a07eb0aSMichio Honda 				sin = (struct sockaddr_in *)addrs;
8268a07eb0aSMichio Honda 				asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr;
8278a07eb0aSMichio Honda 			} else if (addrs->sa_family == AF_INET6) {
8288a07eb0aSMichio Honda 				struct sockaddr_in6 *sin6;
8298a07eb0aSMichio Honda 
8308a07eb0aSMichio Honda 				sin6 = (struct sockaddr_in6 *)addrs;
8314e3fd7a0SAlexey Dobriyan 				asoc->asconf_addr_del_pending->v6.sin6_addr = sin6->sin6_addr;
8328a07eb0aSMichio Honda 			}
833bb33381dSDaniel Borkmann 
834bb33381dSDaniel Borkmann 			pr_debug("%s: keep the last address asoc:%p %pISc at %p\n",
835bb33381dSDaniel Borkmann 				 __func__, asoc, &asoc->asconf_addr_del_pending->sa,
8368a07eb0aSMichio Honda 				 asoc->asconf_addr_del_pending);
837bb33381dSDaniel Borkmann 
8388a07eb0aSMichio Honda 			asoc->src_out_of_asoc_ok = 1;
8398a07eb0aSMichio Honda 			stored = 1;
8408a07eb0aSMichio Honda 			goto skip_mkasconf;
8418a07eb0aSMichio Honda 		}
8421da177e4SLinus Torvalds 
84388362ad8SDaniel Borkmann 		if (laddr == NULL)
84488362ad8SDaniel Borkmann 			return -EINVAL;
84588362ad8SDaniel Borkmann 
846559cf710SVlad Yasevich 		/* We do not need RCU protection throughout this loop
847559cf710SVlad Yasevich 		 * because this is done under a socket lock from the
848559cf710SVlad Yasevich 		 * setsockopt call.
849559cf710SVlad Yasevich 		 */
8501da177e4SLinus Torvalds 		chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt,
8511da177e4SLinus Torvalds 						   SCTP_PARAM_DEL_IP);
8521da177e4SLinus Torvalds 		if (!chunk) {
8531da177e4SLinus Torvalds 			retval = -ENOMEM;
8541da177e4SLinus Torvalds 			goto out;
8551da177e4SLinus Torvalds 		}
8561da177e4SLinus Torvalds 
8578a07eb0aSMichio Honda skip_mkasconf:
858dc022a98SSridhar Samudrala 		/* Reset use_as_src flag for the addresses in the bind address
859dc022a98SSridhar Samudrala 		 * list that are to be deleted.
8601da177e4SLinus Torvalds 		 */
861dc022a98SSridhar Samudrala 		addr_buf = addrs;
862dc022a98SSridhar Samudrala 		for (i = 0; i < addrcnt; i++) {
863ea110733SJoe Perches 			laddr = addr_buf;
864dc022a98SSridhar Samudrala 			af = sctp_get_af_specific(laddr->v4.sin_family);
865559cf710SVlad Yasevich 			list_for_each_entry(saddr, &bp->address_list, list) {
8665f242a13SAl Viro 				if (sctp_cmp_addr_exact(&saddr->a, laddr))
867f57d96b2SVlad Yasevich 					saddr->state = SCTP_ADDR_DEL;
868dc022a98SSridhar Samudrala 			}
869dc022a98SSridhar Samudrala 			addr_buf += af->sockaddr_len;
870dc022a98SSridhar Samudrala 		}
871dc022a98SSridhar Samudrala 
872dc022a98SSridhar Samudrala 		/* Update the route and saddr entries for all the transports
873dc022a98SSridhar Samudrala 		 * as some of the addresses in the bind address list are
874dc022a98SSridhar Samudrala 		 * about to be deleted and cannot be used as source addresses.
875dc022a98SSridhar Samudrala 		 */
8769dbc15f0SRobert P. J. Day 		list_for_each_entry(transport, &asoc->peer.transport_addr_list,
8779dbc15f0SRobert P. J. Day 					transports) {
878dc022a98SSridhar Samudrala 			sctp_transport_route(transport, NULL,
879dc022a98SSridhar Samudrala 					     sctp_sk(asoc->base.sk));
880dc022a98SSridhar Samudrala 		}
881dc022a98SSridhar Samudrala 
8828a07eb0aSMichio Honda 		if (stored)
8838a07eb0aSMichio Honda 			/* We don't need to transmit ASCONF */
8848a07eb0aSMichio Honda 			continue;
885dc022a98SSridhar Samudrala 		retval = sctp_send_asconf(asoc, chunk);
8861da177e4SLinus Torvalds 	}
8871da177e4SLinus Torvalds out:
8881da177e4SLinus Torvalds 	return retval;
8891da177e4SLinus Torvalds }
8901da177e4SLinus Torvalds 
8919f7d653bSMichio Honda /* set addr events to assocs in the endpoint.  ep and addr_wq must be locked */
8929f7d653bSMichio Honda int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw)
8939f7d653bSMichio Honda {
8949f7d653bSMichio Honda 	struct sock *sk = sctp_opt2sk(sp);
8959f7d653bSMichio Honda 	union sctp_addr *addr;
8969f7d653bSMichio Honda 	struct sctp_af *af;
8979f7d653bSMichio Honda 
8989f7d653bSMichio Honda 	/* It is safe to write port space in caller. */
8999f7d653bSMichio Honda 	addr = &addrw->a;
9009f7d653bSMichio Honda 	addr->v4.sin_port = htons(sp->ep->base.bind_addr.port);
9019f7d653bSMichio Honda 	af = sctp_get_af_specific(addr->sa.sa_family);
9029f7d653bSMichio Honda 	if (!af)
9039f7d653bSMichio Honda 		return -EINVAL;
9049f7d653bSMichio Honda 	if (sctp_verify_addr(sk, addr, af->sockaddr_len))
9059f7d653bSMichio Honda 		return -EINVAL;
9069f7d653bSMichio Honda 
9079f7d653bSMichio Honda 	if (addrw->state == SCTP_ADDR_NEW)
9089f7d653bSMichio Honda 		return sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1);
9099f7d653bSMichio Honda 	else
9109f7d653bSMichio Honda 		return sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1);
9119f7d653bSMichio Honda }
9129f7d653bSMichio Honda 
9131da177e4SLinus Torvalds /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt()
9141da177e4SLinus Torvalds  *
9151da177e4SLinus Torvalds  * API 8.1
9161da177e4SLinus Torvalds  * int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt,
9171da177e4SLinus Torvalds  *                int flags);
9181da177e4SLinus Torvalds  *
9191da177e4SLinus Torvalds  * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
9201da177e4SLinus Torvalds  * If the sd is an IPv6 socket, the addresses passed can either be IPv4
9211da177e4SLinus Torvalds  * or IPv6 addresses.
9221da177e4SLinus Torvalds  *
9231da177e4SLinus Torvalds  * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see
9241da177e4SLinus Torvalds  * Section 3.1.2 for this usage.
9251da177e4SLinus Torvalds  *
9261da177e4SLinus Torvalds  * addrs is a pointer to an array of one or more socket addresses. Each
9271da177e4SLinus Torvalds  * address is contained in its appropriate structure (i.e. struct
9281da177e4SLinus Torvalds  * sockaddr_in or struct sockaddr_in6) the family of the address type
92923c435f7SVille Nuorvala  * must be used to distinguish the address length (note that this
9301da177e4SLinus Torvalds  * representation is termed a "packed array" of addresses). The caller
9311da177e4SLinus Torvalds  * specifies the number of addresses in the array with addrcnt.
9321da177e4SLinus Torvalds  *
9331da177e4SLinus Torvalds  * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns
9341da177e4SLinus Torvalds  * -1, and sets errno to the appropriate error code.
9351da177e4SLinus Torvalds  *
9361da177e4SLinus Torvalds  * For SCTP, the port given in each socket address must be the same, or
9371da177e4SLinus Torvalds  * sctp_bindx() will fail, setting errno to EINVAL.
9381da177e4SLinus Torvalds  *
9391da177e4SLinus Torvalds  * The flags parameter is formed from the bitwise OR of zero or more of
9401da177e4SLinus Torvalds  * the following currently defined flags:
9411da177e4SLinus Torvalds  *
9421da177e4SLinus Torvalds  * SCTP_BINDX_ADD_ADDR
9431da177e4SLinus Torvalds  *
9441da177e4SLinus Torvalds  * SCTP_BINDX_REM_ADDR
9451da177e4SLinus Torvalds  *
9461da177e4SLinus Torvalds  * SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the
9471da177e4SLinus Torvalds  * association, and SCTP_BINDX_REM_ADDR directs SCTP to remove the given
9481da177e4SLinus Torvalds  * addresses from the association. The two flags are mutually exclusive;
9491da177e4SLinus Torvalds  * if both are given, sctp_bindx() will fail with EINVAL. A caller may
9501da177e4SLinus Torvalds  * not remove all addresses from an association; sctp_bindx() will
9511da177e4SLinus Torvalds  * reject such an attempt with EINVAL.
9521da177e4SLinus Torvalds  *
9531da177e4SLinus Torvalds  * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate
9541da177e4SLinus Torvalds  * additional addresses with an endpoint after calling bind().  Or use
9551da177e4SLinus Torvalds  * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening
9561da177e4SLinus Torvalds  * socket is associated with so that no new association accepted will be
9571da177e4SLinus Torvalds  * associated with those addresses. If the endpoint supports dynamic
9581da177e4SLinus Torvalds  * address a SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR may cause a
9591da177e4SLinus Torvalds  * endpoint to send the appropriate message to the peer to change the
9601da177e4SLinus Torvalds  * peers address lists.
9611da177e4SLinus Torvalds  *
9621da177e4SLinus Torvalds  * Adding and removing addresses from a connected association is
9631da177e4SLinus Torvalds  * optional functionality. Implementations that do not support this
9641da177e4SLinus Torvalds  * functionality should return EOPNOTSUPP.
9651da177e4SLinus Torvalds  *
9661da177e4SLinus Torvalds  * Basically do nothing but copying the addresses from user to kernel
9671da177e4SLinus Torvalds  * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk.
9683f7a87d2SFrank Filz  * This is used for tunneling the sctp_bindx() request through sctp_setsockopt()
9693f7a87d2SFrank Filz  * from userspace.
9701da177e4SLinus Torvalds  *
9711da177e4SLinus Torvalds  * On exit there is no need to do sockfd_put(), sys_setsockopt() does
9721da177e4SLinus Torvalds  * it.
9731da177e4SLinus Torvalds  *
9741da177e4SLinus Torvalds  * sk        The sk of the socket
97505bfd366SChristoph Hellwig  * addrs     The pointer to the addresses
9761da177e4SLinus Torvalds  * addrssize Size of the addrs buffer
9771da177e4SLinus Torvalds  * op        Operation to perform (add or remove, see the flags of
9781da177e4SLinus Torvalds  *           sctp_bindx)
9791da177e4SLinus Torvalds  *
9801da177e4SLinus Torvalds  * Returns 0 if ok, <0 errno code on error.
9811da177e4SLinus Torvalds  */
9828c7517f5SChristoph Hellwig static int sctp_setsockopt_bindx(struct sock *sk, struct sockaddr *addrs,
9838c7517f5SChristoph Hellwig 				 int addrs_size, int op)
9841da177e4SLinus Torvalds {
9851da177e4SLinus Torvalds 	int err;
9861da177e4SLinus Torvalds 	int addrcnt = 0;
9871da177e4SLinus Torvalds 	int walk_size = 0;
9881da177e4SLinus Torvalds 	struct sockaddr *sa_addr;
98905bfd366SChristoph Hellwig 	void *addr_buf = addrs;
9901da177e4SLinus Torvalds 	struct sctp_af *af;
9911da177e4SLinus Torvalds 
992bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p addrs:%p addrs_size:%d opt:%d\n",
9938c7517f5SChristoph Hellwig 		 __func__, sk, addr_buf, addrs_size, op);
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds 	if (unlikely(addrs_size <= 0))
9961da177e4SLinus Torvalds 		return -EINVAL;
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds 	/* Walk through the addrs buffer and count the number of addresses. */
9991da177e4SLinus Torvalds 	while (walk_size < addrs_size) {
100005bfd366SChristoph Hellwig 		if (walk_size + sizeof(sa_family_t) > addrs_size)
1001d7e0d19aSDan Rosenberg 			return -EINVAL;
1002d7e0d19aSDan Rosenberg 
1003ea110733SJoe Perches 		sa_addr = addr_buf;
10041da177e4SLinus Torvalds 		af = sctp_get_af_specific(sa_addr->sa_family);
10051da177e4SLinus Torvalds 
10061da177e4SLinus Torvalds 		/* If the address family is not supported or if this address
10071da177e4SLinus Torvalds 		 * causes the address buffer to overflow return EINVAL.
10081da177e4SLinus Torvalds 		 */
100905bfd366SChristoph Hellwig 		if (!af || (walk_size + af->sockaddr_len) > addrs_size)
10101da177e4SLinus Torvalds 			return -EINVAL;
10111da177e4SLinus Torvalds 		addrcnt++;
10121da177e4SLinus Torvalds 		addr_buf += af->sockaddr_len;
10131da177e4SLinus Torvalds 		walk_size += af->sockaddr_len;
10141da177e4SLinus Torvalds 	}
10151da177e4SLinus Torvalds 
10161da177e4SLinus Torvalds 	/* Do the work. */
10171da177e4SLinus Torvalds 	switch (op) {
10181da177e4SLinus Torvalds 	case SCTP_BINDX_ADD_ADDR:
10192277c7cdSRichard Haines 		/* Allow security module to validate bindx addresses. */
10202277c7cdSRichard Haines 		err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_BINDX_ADD,
102105bfd366SChristoph Hellwig 						 addrs, addrs_size);
10222277c7cdSRichard Haines 		if (err)
102305bfd366SChristoph Hellwig 			return err;
102405bfd366SChristoph Hellwig 		err = sctp_bindx_add(sk, addrs, addrcnt);
10251da177e4SLinus Torvalds 		if (err)
102605bfd366SChristoph Hellwig 			return err;
102705bfd366SChristoph Hellwig 		return sctp_send_asconf_add_ip(sk, addrs, addrcnt);
10281da177e4SLinus Torvalds 	case SCTP_BINDX_REM_ADDR:
102905bfd366SChristoph Hellwig 		err = sctp_bindx_rem(sk, addrs, addrcnt);
10301da177e4SLinus Torvalds 		if (err)
103105bfd366SChristoph Hellwig 			return err;
103205bfd366SChristoph Hellwig 		return sctp_send_asconf_del_ip(sk, addrs, addrcnt);
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds 	default:
103505bfd366SChristoph Hellwig 		return -EINVAL;
103605bfd366SChristoph Hellwig 	}
10373ff50b79SStephen Hemminger }
10381da177e4SLinus Torvalds 
1039c0425a42SChristoph Hellwig static int sctp_bind_add(struct sock *sk, struct sockaddr *addrs,
1040c0425a42SChristoph Hellwig 		int addrlen)
1041c0425a42SChristoph Hellwig {
1042c0425a42SChristoph Hellwig 	int err;
1043c0425a42SChristoph Hellwig 
1044c0425a42SChristoph Hellwig 	lock_sock(sk);
10458c7517f5SChristoph Hellwig 	err = sctp_setsockopt_bindx(sk, addrs, addrlen, SCTP_BINDX_ADD_ADDR);
1046c0425a42SChristoph Hellwig 	release_sock(sk);
1047c0425a42SChristoph Hellwig 	return err;
1048c0425a42SChristoph Hellwig }
1049c0425a42SChristoph Hellwig 
1050f26f9951SXin Long static int sctp_connect_new_asoc(struct sctp_endpoint *ep,
1051f26f9951SXin Long 				 const union sctp_addr *daddr,
1052f26f9951SXin Long 				 const struct sctp_initmsg *init,
1053f26f9951SXin Long 				 struct sctp_transport **tp)
1054f26f9951SXin Long {
1055f26f9951SXin Long 	struct sctp_association *asoc;
1056f26f9951SXin Long 	struct sock *sk = ep->base.sk;
1057f26f9951SXin Long 	struct net *net = sock_net(sk);
1058f26f9951SXin Long 	enum sctp_scope scope;
1059f26f9951SXin Long 	int err;
1060f26f9951SXin Long 
1061f26f9951SXin Long 	if (sctp_endpoint_is_peeled_off(ep, daddr))
1062f26f9951SXin Long 		return -EADDRNOTAVAIL;
1063f26f9951SXin Long 
1064f26f9951SXin Long 	if (!ep->base.bind_addr.port) {
1065f26f9951SXin Long 		if (sctp_autobind(sk))
1066f26f9951SXin Long 			return -EAGAIN;
1067f26f9951SXin Long 	} else {
106882f31ebfSMaciej Żenczykowski 		if (inet_port_requires_bind_service(net, ep->base.bind_addr.port) &&
1069f26f9951SXin Long 		    !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
1070f26f9951SXin Long 			return -EACCES;
1071f26f9951SXin Long 	}
1072f26f9951SXin Long 
1073f26f9951SXin Long 	scope = sctp_scope(daddr);
1074f26f9951SXin Long 	asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
1075f26f9951SXin Long 	if (!asoc)
1076f26f9951SXin Long 		return -ENOMEM;
1077f26f9951SXin Long 
1078f26f9951SXin Long 	err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL);
1079f26f9951SXin Long 	if (err < 0)
1080f26f9951SXin Long 		goto free;
1081f26f9951SXin Long 
1082f26f9951SXin Long 	*tp = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN);
1083f26f9951SXin Long 	if (!*tp) {
1084f26f9951SXin Long 		err = -ENOMEM;
1085f26f9951SXin Long 		goto free;
1086f26f9951SXin Long 	}
1087f26f9951SXin Long 
1088f26f9951SXin Long 	if (!init)
1089f26f9951SXin Long 		return 0;
1090f26f9951SXin Long 
1091f26f9951SXin Long 	if (init->sinit_num_ostreams) {
1092f26f9951SXin Long 		__u16 outcnt = init->sinit_num_ostreams;
1093f26f9951SXin Long 
1094f26f9951SXin Long 		asoc->c.sinit_num_ostreams = outcnt;
1095f26f9951SXin Long 		/* outcnt has been changed, need to re-init stream */
1096f26f9951SXin Long 		err = sctp_stream_init(&asoc->stream, outcnt, 0, GFP_KERNEL);
1097f26f9951SXin Long 		if (err)
1098f26f9951SXin Long 			goto free;
1099f26f9951SXin Long 	}
1100f26f9951SXin Long 
1101f26f9951SXin Long 	if (init->sinit_max_instreams)
1102f26f9951SXin Long 		asoc->c.sinit_max_instreams = init->sinit_max_instreams;
1103f26f9951SXin Long 
1104f26f9951SXin Long 	if (init->sinit_max_attempts)
1105f26f9951SXin Long 		asoc->max_init_attempts = init->sinit_max_attempts;
1106f26f9951SXin Long 
1107f26f9951SXin Long 	if (init->sinit_max_init_timeo)
1108f26f9951SXin Long 		asoc->max_init_timeo =
1109f26f9951SXin Long 			msecs_to_jiffies(init->sinit_max_init_timeo);
1110f26f9951SXin Long 
1111f26f9951SXin Long 	return 0;
1112f26f9951SXin Long free:
1113f26f9951SXin Long 	sctp_association_free(asoc);
1114f26f9951SXin Long 	return err;
1115f26f9951SXin Long }
1116f26f9951SXin Long 
1117a64e59c7SXin Long static int sctp_connect_add_peer(struct sctp_association *asoc,
1118a64e59c7SXin Long 				 union sctp_addr *daddr, int addr_len)
1119a64e59c7SXin Long {
1120a64e59c7SXin Long 	struct sctp_endpoint *ep = asoc->ep;
1121a64e59c7SXin Long 	struct sctp_association *old;
1122a64e59c7SXin Long 	struct sctp_transport *t;
1123a64e59c7SXin Long 	int err;
1124a64e59c7SXin Long 
1125a64e59c7SXin Long 	err = sctp_verify_addr(ep->base.sk, daddr, addr_len);
1126a64e59c7SXin Long 	if (err)
1127a64e59c7SXin Long 		return err;
1128a64e59c7SXin Long 
1129a64e59c7SXin Long 	old = sctp_endpoint_lookup_assoc(ep, daddr, &t);
1130a64e59c7SXin Long 	if (old && old != asoc)
1131a64e59c7SXin Long 		return old->state >= SCTP_STATE_ESTABLISHED ? -EISCONN
1132a64e59c7SXin Long 							    : -EALREADY;
1133a64e59c7SXin Long 
1134a64e59c7SXin Long 	if (sctp_endpoint_is_peeled_off(ep, daddr))
1135a64e59c7SXin Long 		return -EADDRNOTAVAIL;
1136a64e59c7SXin Long 
1137a64e59c7SXin Long 	t = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL, SCTP_UNKNOWN);
1138a64e59c7SXin Long 	if (!t)
1139a64e59c7SXin Long 		return -ENOMEM;
1140a64e59c7SXin Long 
1141a64e59c7SXin Long 	return 0;
1142a64e59c7SXin Long }
1143a64e59c7SXin Long 
11443f7a87d2SFrank Filz /* __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, int addrs_size)
11453f7a87d2SFrank Filz  *
11463f7a87d2SFrank Filz  * Common routine for handling connect() and sctp_connectx().
11473f7a87d2SFrank Filz  * Connect will come in with just a single address.
11483f7a87d2SFrank Filz  */
1149dd8378b3SXin Long static int __sctp_connect(struct sock *sk, struct sockaddr *kaddrs,
1150dd8378b3SXin Long 			  int addrs_size, int flags, sctp_assoc_t *assoc_id)
11513f7a87d2SFrank Filz {
1152dd8378b3SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
1153dd8378b3SXin Long 	struct sctp_endpoint *ep = sp->ep;
11543f7a87d2SFrank Filz 	struct sctp_transport *transport;
1155a64e59c7SXin Long 	struct sctp_association *asoc;
1156dd8378b3SXin Long 	void *addr_buf = kaddrs;
1157dd8378b3SXin Long 	union sctp_addr *daddr;
1158299ee123SJason Gunthorpe 	struct sctp_af *af;
1159dd8378b3SXin Long 	int walk_size, err;
1160dd8378b3SXin Long 	long timeo;
1161299ee123SJason Gunthorpe 
1162dd8378b3SXin Long 	if (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING) ||
1163dd8378b3SXin Long 	    (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)))
1164dd8378b3SXin Long 		return -EISCONN;
1165d7e0d19aSDan Rosenberg 
1166dd8378b3SXin Long 	daddr = addr_buf;
1167dd8378b3SXin Long 	af = sctp_get_af_specific(daddr->sa.sa_family);
1168dd8378b3SXin Long 	if (!af || af->sockaddr_len > addrs_size)
1169dd8378b3SXin Long 		return -EINVAL;
11703f7a87d2SFrank Filz 
1171dd8378b3SXin Long 	err = sctp_verify_addr(sk, daddr, af->sockaddr_len);
11723f7a87d2SFrank Filz 	if (err)
1173dd8378b3SXin Long 		return err;
11743f7a87d2SFrank Filz 
1175dd8378b3SXin Long 	asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
1176dd8378b3SXin Long 	if (asoc)
1177dd8378b3SXin Long 		return asoc->state >= SCTP_STATE_ESTABLISHED ? -EISCONN
1178dd8378b3SXin Long 							     : -EALREADY;
11793f7a87d2SFrank Filz 
1180f26f9951SXin Long 	err = sctp_connect_new_asoc(ep, daddr, NULL, &transport);
1181f26f9951SXin Long 	if (err)
1182f26f9951SXin Long 		return err;
1183f26f9951SXin Long 	asoc = transport->asoc;
1184409b95afSVlad Yasevich 
1185dd8378b3SXin Long 	addr_buf += af->sockaddr_len;
1186dd8378b3SXin Long 	walk_size = af->sockaddr_len;
1187dd8378b3SXin Long 	while (walk_size < addrs_size) {
1188dd8378b3SXin Long 		err = -EINVAL;
1189dd8378b3SXin Long 		if (walk_size + sizeof(sa_family_t) > addrs_size)
1190dd8378b3SXin Long 			goto out_free;
1191dd8378b3SXin Long 
1192dd8378b3SXin Long 		daddr = addr_buf;
1193dd8378b3SXin Long 		af = sctp_get_af_specific(daddr->sa.sa_family);
1194dd8378b3SXin Long 		if (!af || af->sockaddr_len + walk_size > addrs_size)
1195dd8378b3SXin Long 			goto out_free;
1196dd8378b3SXin Long 
1197dd8378b3SXin Long 		if (asoc->peer.port != ntohs(daddr->v4.sin_port))
1198dd8378b3SXin Long 			goto out_free;
1199dd8378b3SXin Long 
1200a64e59c7SXin Long 		err = sctp_connect_add_peer(asoc, daddr, af->sockaddr_len);
1201dd8378b3SXin Long 		if (err)
1202dd8378b3SXin Long 			goto out_free;
1203dd8378b3SXin Long 
12043f7a87d2SFrank Filz 		addr_buf  += af->sockaddr_len;
12053f7a87d2SFrank Filz 		walk_size += af->sockaddr_len;
12063f7a87d2SFrank Filz 	}
12073f7a87d2SFrank Filz 
1208c6ba68a2SVlad Yasevich 	/* In case the user of sctp_connectx() wants an association
1209c6ba68a2SVlad Yasevich 	 * id back, assign one now.
1210c6ba68a2SVlad Yasevich 	 */
1211c6ba68a2SVlad Yasevich 	if (assoc_id) {
1212c6ba68a2SVlad Yasevich 		err = sctp_assoc_set_id(asoc, GFP_KERNEL);
1213c6ba68a2SVlad Yasevich 		if (err < 0)
1214c6ba68a2SVlad Yasevich 			goto out_free;
1215c6ba68a2SVlad Yasevich 	}
1216c6ba68a2SVlad Yasevich 
1217f26f9951SXin Long 	err = sctp_primitive_ASSOCIATE(sock_net(sk), asoc, NULL);
1218dd8378b3SXin Long 	if (err < 0)
12193f7a87d2SFrank Filz 		goto out_free;
12203f7a87d2SFrank Filz 
12213f7a87d2SFrank Filz 	/* Initialize sk's dport and daddr for getpeername() */
1222c720c7e8SEric Dumazet 	inet_sk(sk)->inet_dport = htons(asoc->peer.port);
1223dd8378b3SXin Long 	sp->pf->to_sk_daddr(daddr, sk);
12248de8c873SSridhar Samudrala 	sk->sk_err = 0;
12253f7a87d2SFrank Filz 
12267233bc84SMarcelo Ricardo Leitner 	if (assoc_id)
122788a0a948SVlad Yasevich 		*assoc_id = asoc->assoc_id;
12282277c7cdSRichard Haines 
1229dd8378b3SXin Long 	timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
1230dd8378b3SXin Long 	return sctp_wait_for_connect(asoc, &timeo);
12313f7a87d2SFrank Filz 
12323f7a87d2SFrank Filz out_free:
1233bb33381dSDaniel Borkmann 	pr_debug("%s: took out_free path with asoc:%p kaddrs:%p err:%d\n",
1234bb33381dSDaniel Borkmann 		 __func__, asoc, kaddrs, err);
12353f7a87d2SFrank Filz 	sctp_association_free(asoc);
12363f7a87d2SFrank Filz 	return err;
12373f7a87d2SFrank Filz }
12383f7a87d2SFrank Filz 
12393f7a87d2SFrank Filz /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt()
12403f7a87d2SFrank Filz  *
12413f7a87d2SFrank Filz  * API 8.9
124288a0a948SVlad Yasevich  * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
124388a0a948SVlad Yasevich  * 			sctp_assoc_t *asoc);
12443f7a87d2SFrank Filz  *
12453f7a87d2SFrank Filz  * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
12463f7a87d2SFrank Filz  * If the sd is an IPv6 socket, the addresses passed can either be IPv4
12473f7a87d2SFrank Filz  * or IPv6 addresses.
12483f7a87d2SFrank Filz  *
12493f7a87d2SFrank Filz  * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see
12503f7a87d2SFrank Filz  * Section 3.1.2 for this usage.
12513f7a87d2SFrank Filz  *
12523f7a87d2SFrank Filz  * addrs is a pointer to an array of one or more socket addresses. Each
12533f7a87d2SFrank Filz  * address is contained in its appropriate structure (i.e. struct
12543f7a87d2SFrank Filz  * sockaddr_in or struct sockaddr_in6) the family of the address type
12553f7a87d2SFrank Filz  * must be used to distengish the address length (note that this
12563f7a87d2SFrank Filz  * representation is termed a "packed array" of addresses). The caller
12573f7a87d2SFrank Filz  * specifies the number of addresses in the array with addrcnt.
12583f7a87d2SFrank Filz  *
125988a0a948SVlad Yasevich  * On success, sctp_connectx() returns 0. It also sets the assoc_id to
126088a0a948SVlad Yasevich  * the association id of the new association.  On failure, sctp_connectx()
126188a0a948SVlad Yasevich  * returns -1, and sets errno to the appropriate error code.  The assoc_id
126288a0a948SVlad Yasevich  * is not touched by the kernel.
12633f7a87d2SFrank Filz  *
12643f7a87d2SFrank Filz  * For SCTP, the port given in each socket address must be the same, or
12653f7a87d2SFrank Filz  * sctp_connectx() will fail, setting errno to EINVAL.
12663f7a87d2SFrank Filz  *
12673f7a87d2SFrank Filz  * An application can use sctp_connectx to initiate an association with
12683f7a87d2SFrank Filz  * an endpoint that is multi-homed.  Much like sctp_bindx() this call
12693f7a87d2SFrank Filz  * allows a caller to specify multiple addresses at which a peer can be
12703f7a87d2SFrank Filz  * reached.  The way the SCTP stack uses the list of addresses to set up
127125985edcSLucas De Marchi  * the association is implementation dependent.  This function only
12723f7a87d2SFrank Filz  * specifies that the stack will try to make use of all the addresses in
12733f7a87d2SFrank Filz  * the list when needed.
12743f7a87d2SFrank Filz  *
12753f7a87d2SFrank Filz  * Note that the list of addresses passed in is only used for setting up
12763f7a87d2SFrank Filz  * the association.  It does not necessarily equal the set of addresses
12773f7a87d2SFrank Filz  * the peer uses for the resulting association.  If the caller wants to
12783f7a87d2SFrank Filz  * find out the set of peer addresses, it must use sctp_getpaddrs() to
12793f7a87d2SFrank Filz  * retrieve them after the association has been set up.
12803f7a87d2SFrank Filz  *
12813f7a87d2SFrank Filz  * Basically do nothing but copying the addresses from user to kernel
12823f7a87d2SFrank Filz  * land and invoking either sctp_connectx(). This is used for tunneling
12833f7a87d2SFrank Filz  * the sctp_connectx() request through sctp_setsockopt() from userspace.
12843f7a87d2SFrank Filz  *
12853f7a87d2SFrank Filz  * On exit there is no need to do sockfd_put(), sys_setsockopt() does
12863f7a87d2SFrank Filz  * it.
12873f7a87d2SFrank Filz  *
12883f7a87d2SFrank Filz  * sk        The sk of the socket
1289ce5b2f89SChristoph Hellwig  * addrs     The pointer to the addresses
12903f7a87d2SFrank Filz  * addrssize Size of the addrs buffer
12913f7a87d2SFrank Filz  *
129288a0a948SVlad Yasevich  * Returns >=0 if ok, <0 errno code on error.
12933f7a87d2SFrank Filz  */
1294ce5b2f89SChristoph Hellwig static int __sctp_setsockopt_connectx(struct sock *sk, struct sockaddr *kaddrs,
1295ce5b2f89SChristoph Hellwig 				      int addrs_size, sctp_assoc_t *assoc_id)
12963f7a87d2SFrank Filz {
1297644fbdeaSXin Long 	int err = 0, flags = 0;
12983f7a87d2SFrank Filz 
1299bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
1300ce5b2f89SChristoph Hellwig 		 __func__, sk, kaddrs, addrs_size);
13013f7a87d2SFrank Filz 
1302f40f1177SXin Long 	/* make sure the 1st addr's sa_family is accessible later */
1303f40f1177SXin Long 	if (unlikely(addrs_size < sizeof(sa_family_t)))
13043f7a87d2SFrank Filz 		return -EINVAL;
13053f7a87d2SFrank Filz 
13062277c7cdSRichard Haines 	/* Allow security module to validate connectx addresses. */
13072277c7cdSRichard Haines 	err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX,
13082277c7cdSRichard Haines 					 (struct sockaddr *)kaddrs,
13092277c7cdSRichard Haines 					  addrs_size);
13102277c7cdSRichard Haines 	if (err)
1311ce5b2f89SChristoph Hellwig 		return err;
13122277c7cdSRichard Haines 
1313644fbdeaSXin Long 	/* in-kernel sockets don't generally have a file allocated to them
1314644fbdeaSXin Long 	 * if all they do is call sock_create_kern().
1315644fbdeaSXin Long 	 */
1316644fbdeaSXin Long 	if (sk->sk_socket->file)
1317644fbdeaSXin Long 		flags = sk->sk_socket->file->f_flags;
1318644fbdeaSXin Long 
1319ce5b2f89SChristoph Hellwig 	return __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
13203f7a87d2SFrank Filz }
13213f7a87d2SFrank Filz 
132288a0a948SVlad Yasevich /*
132388a0a948SVlad Yasevich  * This is an older interface.  It's kept for backward compatibility
132488a0a948SVlad Yasevich  * to the option that doesn't provide association id.
132588a0a948SVlad Yasevich  */
1326dda91928SDaniel Borkmann static int sctp_setsockopt_connectx_old(struct sock *sk,
1327ce5b2f89SChristoph Hellwig 					struct sockaddr *kaddrs,
132888a0a948SVlad Yasevich 					int addrs_size)
132988a0a948SVlad Yasevich {
1330ce5b2f89SChristoph Hellwig 	return __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, NULL);
133188a0a948SVlad Yasevich }
133288a0a948SVlad Yasevich 
133388a0a948SVlad Yasevich /*
133488a0a948SVlad Yasevich  * New interface for the API.  The since the API is done with a socket
133588a0a948SVlad Yasevich  * option, to make it simple we feed back the association id is as a return
133688a0a948SVlad Yasevich  * indication to the call.  Error is always negative and association id is
133788a0a948SVlad Yasevich  * always positive.
133888a0a948SVlad Yasevich  */
1339dda91928SDaniel Borkmann static int sctp_setsockopt_connectx(struct sock *sk,
1340ce5b2f89SChristoph Hellwig 				    struct sockaddr *kaddrs,
134188a0a948SVlad Yasevich 				    int addrs_size)
134288a0a948SVlad Yasevich {
134388a0a948SVlad Yasevich 	sctp_assoc_t assoc_id = 0;
134488a0a948SVlad Yasevich 	int err = 0;
134588a0a948SVlad Yasevich 
1346ce5b2f89SChristoph Hellwig 	err = __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, &assoc_id);
134788a0a948SVlad Yasevich 
134888a0a948SVlad Yasevich 	if (err)
134988a0a948SVlad Yasevich 		return err;
135088a0a948SVlad Yasevich 	else
135188a0a948SVlad Yasevich 		return assoc_id;
135288a0a948SVlad Yasevich }
135388a0a948SVlad Yasevich 
1354c6ba68a2SVlad Yasevich /*
1355f9c67811SVlad Yasevich  * New (hopefully final) interface for the API.
1356f9c67811SVlad Yasevich  * We use the sctp_getaddrs_old structure so that use-space library
1357ffd59393SDaniel Borkmann  * can avoid any unnecessary allocations. The only different part
1358f9c67811SVlad Yasevich  * is that we store the actual length of the address buffer into the
1359f9c67811SVlad Yasevich  * addrs_num structure member. That way we can re-use the existing
1360f9c67811SVlad Yasevich  * code.
1361c6ba68a2SVlad Yasevich  */
1362ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT
1363ffd59393SDaniel Borkmann struct compat_sctp_getaddrs_old {
1364ffd59393SDaniel Borkmann 	sctp_assoc_t	assoc_id;
1365ffd59393SDaniel Borkmann 	s32		addr_num;
1366ffd59393SDaniel Borkmann 	compat_uptr_t	addrs;		/* struct sockaddr * */
1367ffd59393SDaniel Borkmann };
1368ffd59393SDaniel Borkmann #endif
1369ffd59393SDaniel Borkmann 
1370dda91928SDaniel Borkmann static int sctp_getsockopt_connectx3(struct sock *sk, int len,
1371c6ba68a2SVlad Yasevich 				     char __user *optval,
1372c6ba68a2SVlad Yasevich 				     int __user *optlen)
1373c6ba68a2SVlad Yasevich {
1374f9c67811SVlad Yasevich 	struct sctp_getaddrs_old param;
1375c6ba68a2SVlad Yasevich 	sctp_assoc_t assoc_id = 0;
1376ce5b2f89SChristoph Hellwig 	struct sockaddr *kaddrs;
1377c6ba68a2SVlad Yasevich 	int err = 0;
1378c6ba68a2SVlad Yasevich 
1379ffd59393SDaniel Borkmann #ifdef CONFIG_COMPAT
138096c0e0a9SAndy Lutomirski 	if (in_compat_syscall()) {
1381ffd59393SDaniel Borkmann 		struct compat_sctp_getaddrs_old param32;
1382c6ba68a2SVlad Yasevich 
1383ffd59393SDaniel Borkmann 		if (len < sizeof(param32))
1384ffd59393SDaniel Borkmann 			return -EINVAL;
1385ffd59393SDaniel Borkmann 		if (copy_from_user(&param32, optval, sizeof(param32)))
1386f9c67811SVlad Yasevich 			return -EFAULT;
1387f9c67811SVlad Yasevich 
1388ffd59393SDaniel Borkmann 		param.assoc_id = param32.assoc_id;
1389ffd59393SDaniel Borkmann 		param.addr_num = param32.addr_num;
1390ffd59393SDaniel Borkmann 		param.addrs = compat_ptr(param32.addrs);
1391ffd59393SDaniel Borkmann 	} else
1392ffd59393SDaniel Borkmann #endif
1393ffd59393SDaniel Borkmann 	{
1394ffd59393SDaniel Borkmann 		if (len < sizeof(param))
1395ffd59393SDaniel Borkmann 			return -EINVAL;
1396ffd59393SDaniel Borkmann 		if (copy_from_user(&param, optval, sizeof(param)))
1397ffd59393SDaniel Borkmann 			return -EFAULT;
1398ffd59393SDaniel Borkmann 	}
1399c6ba68a2SVlad Yasevich 
1400ce5b2f89SChristoph Hellwig 	kaddrs = memdup_user(param.addrs, param.addr_num);
1401ce5b2f89SChristoph Hellwig 	if (IS_ERR(kaddrs))
1402ce5b2f89SChristoph Hellwig 		return PTR_ERR(kaddrs);
1403ce5b2f89SChristoph Hellwig 
1404ce5b2f89SChristoph Hellwig 	err = __sctp_setsockopt_connectx(sk, kaddrs, param.addr_num, &assoc_id);
1405ce5b2f89SChristoph Hellwig 	kfree(kaddrs);
1406c6ba68a2SVlad Yasevich 	if (err == 0 || err == -EINPROGRESS) {
1407c6ba68a2SVlad Yasevich 		if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
1408c6ba68a2SVlad Yasevich 			return -EFAULT;
1409c6ba68a2SVlad Yasevich 		if (put_user(sizeof(assoc_id), optlen))
1410c6ba68a2SVlad Yasevich 			return -EFAULT;
1411c6ba68a2SVlad Yasevich 	}
1412c6ba68a2SVlad Yasevich 
1413c6ba68a2SVlad Yasevich 	return err;
1414c6ba68a2SVlad Yasevich }
1415c6ba68a2SVlad Yasevich 
14161da177e4SLinus Torvalds /* API 3.1.4 close() - UDP Style Syntax
14171da177e4SLinus Torvalds  * Applications use close() to perform graceful shutdown (as described in
14181da177e4SLinus Torvalds  * Section 10.1 of [SCTP]) on ALL the associations currently represented
14191da177e4SLinus Torvalds  * by a UDP-style socket.
14201da177e4SLinus Torvalds  *
14211da177e4SLinus Torvalds  * The syntax is
14221da177e4SLinus Torvalds  *
14231da177e4SLinus Torvalds  *   ret = close(int sd);
14241da177e4SLinus Torvalds  *
14251da177e4SLinus Torvalds  *   sd      - the socket descriptor of the associations to be closed.
14261da177e4SLinus Torvalds  *
14271da177e4SLinus Torvalds  * To gracefully shutdown a specific association represented by the
14281da177e4SLinus Torvalds  * UDP-style socket, an application should use the sendmsg() call,
14291da177e4SLinus Torvalds  * passing no user data, but including the appropriate flag in the
14301da177e4SLinus Torvalds  * ancillary data (see Section xxxx).
14311da177e4SLinus Torvalds  *
14321da177e4SLinus Torvalds  * If sd in the close() call is a branched-off socket representing only
14331da177e4SLinus Torvalds  * one association, the shutdown is performed on that association only.
14341da177e4SLinus Torvalds  *
14351da177e4SLinus Torvalds  * 4.1.6 close() - TCP Style Syntax
14361da177e4SLinus Torvalds  *
14371da177e4SLinus Torvalds  * Applications use close() to gracefully close down an association.
14381da177e4SLinus Torvalds  *
14391da177e4SLinus Torvalds  * The syntax is:
14401da177e4SLinus Torvalds  *
14411da177e4SLinus Torvalds  *    int close(int sd);
14421da177e4SLinus Torvalds  *
14431da177e4SLinus Torvalds  *      sd      - the socket descriptor of the association to be closed.
14441da177e4SLinus Torvalds  *
14451da177e4SLinus Torvalds  * After an application calls close() on a socket descriptor, no further
14461da177e4SLinus Torvalds  * socket operations will succeed on that descriptor.
14471da177e4SLinus Torvalds  *
14481da177e4SLinus Torvalds  * API 7.1.4 SO_LINGER
14491da177e4SLinus Torvalds  *
14501da177e4SLinus Torvalds  * An application using the TCP-style socket can use this option to
14511da177e4SLinus Torvalds  * perform the SCTP ABORT primitive.  The linger option structure is:
14521da177e4SLinus Torvalds  *
14531da177e4SLinus Torvalds  *  struct  linger {
14541da177e4SLinus Torvalds  *     int     l_onoff;                // option on/off
14551da177e4SLinus Torvalds  *     int     l_linger;               // linger time
14561da177e4SLinus Torvalds  * };
14571da177e4SLinus Torvalds  *
14581da177e4SLinus Torvalds  * To enable the option, set l_onoff to 1.  If the l_linger value is set
14591da177e4SLinus Torvalds  * to 0, calling close() is the same as the ABORT primitive.  If the
14601da177e4SLinus Torvalds  * value is set to a negative value, the setsockopt() call will return
14611da177e4SLinus Torvalds  * an error.  If the value is set to a positive value linger_time, the
14621da177e4SLinus Torvalds  * close() can be blocked for at most linger_time ms.  If the graceful
14631da177e4SLinus Torvalds  * shutdown phase does not finish during this period, close() will
14641da177e4SLinus Torvalds  * return but the graceful shutdown phase continues in the system.
14651da177e4SLinus Torvalds  */
1466dda91928SDaniel Borkmann static void sctp_close(struct sock *sk, long timeout)
14671da177e4SLinus Torvalds {
146855e26eb9SEric W. Biederman 	struct net *net = sock_net(sk);
14691da177e4SLinus Torvalds 	struct sctp_endpoint *ep;
14701da177e4SLinus Torvalds 	struct sctp_association *asoc;
14711da177e4SLinus Torvalds 	struct list_head *pos, *temp;
1472cd4fcc70SThomas Graf 	unsigned int data_was_unread;
14731da177e4SLinus Torvalds 
1474bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout);
14751da177e4SLinus Torvalds 
14766dfe4b97SXin Long 	lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
14771da177e4SLinus Torvalds 	sk->sk_shutdown = SHUTDOWN_MASK;
1478cbabf463SYafang Shao 	inet_sk_set_state(sk, SCTP_SS_CLOSING);
14791da177e4SLinus Torvalds 
14801da177e4SLinus Torvalds 	ep = sctp_sk(sk)->ep;
14811da177e4SLinus Torvalds 
1482cd4fcc70SThomas Graf 	/* Clean up any skbs sitting on the receive queue.  */
1483cd4fcc70SThomas Graf 	data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue);
1484cd4fcc70SThomas Graf 	data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);
1485cd4fcc70SThomas Graf 
148661c9fed4SVladislav Yasevich 	/* Walk all associations on an endpoint.  */
14871da177e4SLinus Torvalds 	list_for_each_safe(pos, temp, &ep->asocs) {
14881da177e4SLinus Torvalds 		asoc = list_entry(pos, struct sctp_association, asocs);
14891da177e4SLinus Torvalds 
14901da177e4SLinus Torvalds 		if (sctp_style(sk, TCP)) {
14911da177e4SLinus Torvalds 			/* A closed association can still be in the list if
14921da177e4SLinus Torvalds 			 * it belongs to a TCP-style listening socket that is
14931da177e4SLinus Torvalds 			 * not yet accepted. If so, free it. If not, send an
14941da177e4SLinus Torvalds 			 * ABORT or SHUTDOWN based on the linger options.
14951da177e4SLinus Torvalds 			 */
14961da177e4SLinus Torvalds 			if (sctp_state(asoc, CLOSED)) {
14971da177e4SLinus Torvalds 				sctp_association_free(asoc);
1498b89498a1SVladislav Yasevich 				continue;
1499b89498a1SVladislav Yasevich 			}
1500b89498a1SVladislav Yasevich 		}
15011da177e4SLinus Torvalds 
1502cd4fcc70SThomas Graf 		if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) ||
1503cd4fcc70SThomas Graf 		    !skb_queue_empty(&asoc->ulpq.reasm) ||
150413228238SXin Long 		    !skb_queue_empty(&asoc->ulpq.reasm_uo) ||
1505cd4fcc70SThomas Graf 		    (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) {
1506b9ac8672SSridhar Samudrala 			struct sctp_chunk *chunk;
1507b9ac8672SSridhar Samudrala 
1508b9ac8672SSridhar Samudrala 			chunk = sctp_make_abort_user(asoc, NULL, 0);
150955e26eb9SEric W. Biederman 			sctp_primitive_ABORT(net, asoc, chunk);
1510b9ac8672SSridhar Samudrala 		} else
151155e26eb9SEric W. Biederman 			sctp_primitive_SHUTDOWN(net, asoc, NULL);
15121da177e4SLinus Torvalds 	}
15131da177e4SLinus Torvalds 
15141da177e4SLinus Torvalds 	/* On a TCP-style socket, block for at most linger_time if set. */
15151da177e4SLinus Torvalds 	if (sctp_style(sk, TCP) && timeout)
15161da177e4SLinus Torvalds 		sctp_wait_for_close(sk, timeout);
15171da177e4SLinus Torvalds 
15181da177e4SLinus Torvalds 	/* This will run the backlog queue.  */
1519048ed4b6Swangweidong 	release_sock(sk);
15201da177e4SLinus Torvalds 
15211da177e4SLinus Torvalds 	/* Supposedly, no process has access to the socket, but
15221da177e4SLinus Torvalds 	 * the net layers still may.
15232d45a02dSMarcelo Ricardo Leitner 	 * Also, sctp_destroy_sock() needs to be called with addr_wq_lock
15242d45a02dSMarcelo Ricardo Leitner 	 * held and that should be grabbed before socket lock.
15251da177e4SLinus Torvalds 	 */
15262d45a02dSMarcelo Ricardo Leitner 	spin_lock_bh(&net->sctp.addr_wq_lock);
15276dfe4b97SXin Long 	bh_lock_sock_nested(sk);
15281da177e4SLinus Torvalds 
15291da177e4SLinus Torvalds 	/* Hold the sock, since sk_common_release() will put sock_put()
15301da177e4SLinus Torvalds 	 * and we have just a little more cleanup.
15311da177e4SLinus Torvalds 	 */
15321da177e4SLinus Torvalds 	sock_hold(sk);
15331da177e4SLinus Torvalds 	sk_common_release(sk);
15341da177e4SLinus Torvalds 
15355bc1d1b4Swangweidong 	bh_unlock_sock(sk);
15362d45a02dSMarcelo Ricardo Leitner 	spin_unlock_bh(&net->sctp.addr_wq_lock);
15371da177e4SLinus Torvalds 
15381da177e4SLinus Torvalds 	sock_put(sk);
15391da177e4SLinus Torvalds 
15401da177e4SLinus Torvalds 	SCTP_DBG_OBJCNT_DEC(sock);
15411da177e4SLinus Torvalds }
15421da177e4SLinus Torvalds 
15431da177e4SLinus Torvalds /* Handle EPIPE error. */
15441da177e4SLinus Torvalds static int sctp_error(struct sock *sk, int flags, int err)
15451da177e4SLinus Torvalds {
15461da177e4SLinus Torvalds 	if (err == -EPIPE)
15471da177e4SLinus Torvalds 		err = sock_error(sk) ? : -EPIPE;
15481da177e4SLinus Torvalds 	if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
15491da177e4SLinus Torvalds 		send_sig(SIGPIPE, current, 0);
15501da177e4SLinus Torvalds 	return err;
15511da177e4SLinus Torvalds }
15521da177e4SLinus Torvalds 
15531da177e4SLinus Torvalds /* API 3.1.3 sendmsg() - UDP Style Syntax
15541da177e4SLinus Torvalds  *
15551da177e4SLinus Torvalds  * An application uses sendmsg() and recvmsg() calls to transmit data to
15561da177e4SLinus Torvalds  * and receive data from its peer.
15571da177e4SLinus Torvalds  *
15581da177e4SLinus Torvalds  *  ssize_t sendmsg(int socket, const struct msghdr *message,
15591da177e4SLinus Torvalds  *                  int flags);
15601da177e4SLinus Torvalds  *
15611da177e4SLinus Torvalds  *  socket  - the socket descriptor of the endpoint.
15621da177e4SLinus Torvalds  *  message - pointer to the msghdr structure which contains a single
15631da177e4SLinus Torvalds  *            user message and possibly some ancillary data.
15641da177e4SLinus Torvalds  *
15651da177e4SLinus Torvalds  *            See Section 5 for complete description of the data
15661da177e4SLinus Torvalds  *            structures.
15671da177e4SLinus Torvalds  *
15681da177e4SLinus Torvalds  *  flags   - flags sent or received with the user message, see Section
15691da177e4SLinus Torvalds  *            5 for complete description of the flags.
15701da177e4SLinus Torvalds  *
15711da177e4SLinus Torvalds  * Note:  This function could use a rewrite especially when explicit
15721da177e4SLinus Torvalds  * connect support comes in.
15731da177e4SLinus Torvalds  */
15741da177e4SLinus Torvalds /* BUG:  We do not implement the equivalent of sk_stream_wait_memory(). */
15751da177e4SLinus Torvalds 
1576a05437acSXin Long static int sctp_msghdr_parse(const struct msghdr *msg,
1577a05437acSXin Long 			     struct sctp_cmsgs *cmsgs);
15781da177e4SLinus Torvalds 
1579204f817fSXin Long static int sctp_sendmsg_parse(struct sock *sk, struct sctp_cmsgs *cmsgs,
1580204f817fSXin Long 			      struct sctp_sndrcvinfo *srinfo,
1581204f817fSXin Long 			      const struct msghdr *msg, size_t msg_len)
1582204f817fSXin Long {
1583204f817fSXin Long 	__u16 sflags;
1584204f817fSXin Long 	int err;
1585204f817fSXin Long 
1586204f817fSXin Long 	if (sctp_sstate(sk, LISTENING) && sctp_style(sk, TCP))
1587204f817fSXin Long 		return -EPIPE;
1588204f817fSXin Long 
1589204f817fSXin Long 	if (msg_len > sk->sk_sndbuf)
1590204f817fSXin Long 		return -EMSGSIZE;
1591204f817fSXin Long 
1592204f817fSXin Long 	memset(cmsgs, 0, sizeof(*cmsgs));
1593204f817fSXin Long 	err = sctp_msghdr_parse(msg, cmsgs);
1594204f817fSXin Long 	if (err) {
1595204f817fSXin Long 		pr_debug("%s: msghdr parse err:%x\n", __func__, err);
1596204f817fSXin Long 		return err;
1597204f817fSXin Long 	}
1598204f817fSXin Long 
1599204f817fSXin Long 	memset(srinfo, 0, sizeof(*srinfo));
1600204f817fSXin Long 	if (cmsgs->srinfo) {
1601204f817fSXin Long 		srinfo->sinfo_stream = cmsgs->srinfo->sinfo_stream;
1602204f817fSXin Long 		srinfo->sinfo_flags = cmsgs->srinfo->sinfo_flags;
1603204f817fSXin Long 		srinfo->sinfo_ppid = cmsgs->srinfo->sinfo_ppid;
1604204f817fSXin Long 		srinfo->sinfo_context = cmsgs->srinfo->sinfo_context;
1605204f817fSXin Long 		srinfo->sinfo_assoc_id = cmsgs->srinfo->sinfo_assoc_id;
1606204f817fSXin Long 		srinfo->sinfo_timetolive = cmsgs->srinfo->sinfo_timetolive;
1607204f817fSXin Long 	}
1608204f817fSXin Long 
1609204f817fSXin Long 	if (cmsgs->sinfo) {
1610204f817fSXin Long 		srinfo->sinfo_stream = cmsgs->sinfo->snd_sid;
1611204f817fSXin Long 		srinfo->sinfo_flags = cmsgs->sinfo->snd_flags;
1612204f817fSXin Long 		srinfo->sinfo_ppid = cmsgs->sinfo->snd_ppid;
1613204f817fSXin Long 		srinfo->sinfo_context = cmsgs->sinfo->snd_context;
1614204f817fSXin Long 		srinfo->sinfo_assoc_id = cmsgs->sinfo->snd_assoc_id;
1615204f817fSXin Long 	}
1616204f817fSXin Long 
1617ed63afb8SXin Long 	if (cmsgs->prinfo) {
1618ed63afb8SXin Long 		srinfo->sinfo_timetolive = cmsgs->prinfo->pr_value;
1619ed63afb8SXin Long 		SCTP_PR_SET_POLICY(srinfo->sinfo_flags,
1620ed63afb8SXin Long 				   cmsgs->prinfo->pr_policy);
1621ed63afb8SXin Long 	}
1622ed63afb8SXin Long 
1623204f817fSXin Long 	sflags = srinfo->sinfo_flags;
1624204f817fSXin Long 	if (!sflags && msg_len)
1625204f817fSXin Long 		return 0;
1626204f817fSXin Long 
1627204f817fSXin Long 	if (sctp_style(sk, TCP) && (sflags & (SCTP_EOF | SCTP_ABORT)))
1628204f817fSXin Long 		return -EINVAL;
1629204f817fSXin Long 
1630204f817fSXin Long 	if (((sflags & SCTP_EOF) && msg_len > 0) ||
1631204f817fSXin Long 	    (!(sflags & (SCTP_EOF | SCTP_ABORT)) && msg_len == 0))
1632204f817fSXin Long 		return -EINVAL;
1633204f817fSXin Long 
1634204f817fSXin Long 	if ((sflags & SCTP_ADDR_OVER) && !msg->msg_name)
1635204f817fSXin Long 		return -EINVAL;
1636204f817fSXin Long 
1637204f817fSXin Long 	return 0;
1638204f817fSXin Long }
1639204f817fSXin Long 
16402bfd80f9SXin Long static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
16412bfd80f9SXin Long 				 struct sctp_cmsgs *cmsgs,
16422bfd80f9SXin Long 				 union sctp_addr *daddr,
16432bfd80f9SXin Long 				 struct sctp_transport **tp)
16442bfd80f9SXin Long {
16452bfd80f9SXin Long 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
16462bfd80f9SXin Long 	struct sctp_association *asoc;
16472c0dbaa0SXin Long 	struct cmsghdr *cmsg;
16484be4139fSXin Long 	__be32 flowinfo = 0;
16499eda2d2dSLinus Torvalds 	struct sctp_af *af;
1650d98985ddSWei Yongjun 	int err;
16512bfd80f9SXin Long 
16522bfd80f9SXin Long 	*tp = NULL;
16532bfd80f9SXin Long 
16542bfd80f9SXin Long 	if (sflags & (SCTP_EOF | SCTP_ABORT))
16552bfd80f9SXin Long 		return -EINVAL;
16562bfd80f9SXin Long 
16572bfd80f9SXin Long 	if (sctp_style(sk, TCP) && (sctp_sstate(sk, ESTABLISHED) ||
16582bfd80f9SXin Long 				    sctp_sstate(sk, CLOSING)))
16592bfd80f9SXin Long 		return -EADDRNOTAVAIL;
16602bfd80f9SXin Long 
16612277c7cdSRichard Haines 	/* Label connection socket for first association 1-to-many
16622277c7cdSRichard Haines 	 * style for client sequence socket()->sendmsg(). This
16632277c7cdSRichard Haines 	 * needs to be done before sctp_assoc_add_peer() as that will
16642277c7cdSRichard Haines 	 * set up the initial packet that needs to account for any
16652277c7cdSRichard Haines 	 * security ip options (CIPSO/CALIPSO) added to the packet.
16662277c7cdSRichard Haines 	 */
16679eda2d2dSLinus Torvalds 	af = sctp_get_af_specific(daddr->sa.sa_family);
16689eda2d2dSLinus Torvalds 	if (!af)
16699eda2d2dSLinus Torvalds 		return -EINVAL;
16702277c7cdSRichard Haines 	err = security_sctp_bind_connect(sk, SCTP_SENDMSG_CONNECT,
16719eda2d2dSLinus Torvalds 					 (struct sockaddr *)daddr,
16722277c7cdSRichard Haines 					 af->sockaddr_len);
16732277c7cdSRichard Haines 	if (err < 0)
16749eda2d2dSLinus Torvalds 		return err;
16752277c7cdSRichard Haines 
1676f26f9951SXin Long 	err = sctp_connect_new_asoc(ep, daddr, cmsgs->init, tp);
16772bfd80f9SXin Long 	if (err)
1678f26f9951SXin Long 		return err;
1679f26f9951SXin Long 	asoc = (*tp)->asoc;
16802bfd80f9SXin Long 
16812c0dbaa0SXin Long 	if (!cmsgs->addrs_msg)
16822c0dbaa0SXin Long 		return 0;
16832c0dbaa0SXin Long 
16844be4139fSXin Long 	if (daddr->sa.sa_family == AF_INET6)
16854be4139fSXin Long 		flowinfo = daddr->v6.sin6_flowinfo;
16864be4139fSXin Long 
16872c0dbaa0SXin Long 	/* sendv addr list parse */
16882c0dbaa0SXin Long 	for_each_cmsghdr(cmsg, cmsgs->addrs_msg) {
16892c0dbaa0SXin Long 		union sctp_addr _daddr;
16902c0dbaa0SXin Long 		int dlen;
16912c0dbaa0SXin Long 
16922c0dbaa0SXin Long 		if (cmsg->cmsg_level != IPPROTO_SCTP ||
16932c0dbaa0SXin Long 		    (cmsg->cmsg_type != SCTP_DSTADDRV4 &&
16942c0dbaa0SXin Long 		     cmsg->cmsg_type != SCTP_DSTADDRV6))
16952c0dbaa0SXin Long 			continue;
16962c0dbaa0SXin Long 
16972c0dbaa0SXin Long 		daddr = &_daddr;
16982c0dbaa0SXin Long 		memset(daddr, 0, sizeof(*daddr));
16992c0dbaa0SXin Long 		dlen = cmsg->cmsg_len - sizeof(struct cmsghdr);
17002c0dbaa0SXin Long 		if (cmsg->cmsg_type == SCTP_DSTADDRV4) {
1701d98985ddSWei Yongjun 			if (dlen < sizeof(struct in_addr)) {
1702d98985ddSWei Yongjun 				err = -EINVAL;
17032c0dbaa0SXin Long 				goto free;
1704d98985ddSWei Yongjun 			}
17052c0dbaa0SXin Long 
17062c0dbaa0SXin Long 			dlen = sizeof(struct in_addr);
17072c0dbaa0SXin Long 			daddr->v4.sin_family = AF_INET;
17082c0dbaa0SXin Long 			daddr->v4.sin_port = htons(asoc->peer.port);
17092c0dbaa0SXin Long 			memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen);
17102c0dbaa0SXin Long 		} else {
1711d98985ddSWei Yongjun 			if (dlen < sizeof(struct in6_addr)) {
1712d98985ddSWei Yongjun 				err = -EINVAL;
17132c0dbaa0SXin Long 				goto free;
1714d98985ddSWei Yongjun 			}
17152c0dbaa0SXin Long 
17162c0dbaa0SXin Long 			dlen = sizeof(struct in6_addr);
17174be4139fSXin Long 			daddr->v6.sin6_flowinfo = flowinfo;
17182c0dbaa0SXin Long 			daddr->v6.sin6_family = AF_INET6;
17192c0dbaa0SXin Long 			daddr->v6.sin6_port = htons(asoc->peer.port);
17202c0dbaa0SXin Long 			memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen);
17212c0dbaa0SXin Long 		}
1722a64e59c7SXin Long 
1723a64e59c7SXin Long 		err = sctp_connect_add_peer(asoc, daddr, sizeof(*daddr));
17242c0dbaa0SXin Long 		if (err)
17252c0dbaa0SXin Long 			goto free;
17262c0dbaa0SXin Long 	}
17272c0dbaa0SXin Long 
17282bfd80f9SXin Long 	return 0;
17292bfd80f9SXin Long 
17302bfd80f9SXin Long free:
17312bfd80f9SXin Long 	sctp_association_free(asoc);
17322bfd80f9SXin Long 	return err;
17332bfd80f9SXin Long }
17342bfd80f9SXin Long 
1735c2666de1SXin Long static int sctp_sendmsg_check_sflags(struct sctp_association *asoc,
1736c2666de1SXin Long 				     __u16 sflags, struct msghdr *msg,
1737c2666de1SXin Long 				     size_t msg_len)
1738c2666de1SXin Long {
1739c2666de1SXin Long 	struct sock *sk = asoc->base.sk;
1740c2666de1SXin Long 	struct net *net = sock_net(sk);
1741c2666de1SXin Long 
1742c2666de1SXin Long 	if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP))
1743c2666de1SXin Long 		return -EPIPE;
1744c2666de1SXin Long 
174549102805SXin Long 	if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP) &&
174649102805SXin Long 	    !sctp_state(asoc, ESTABLISHED))
174749102805SXin Long 		return 0;
174849102805SXin Long 
1749c2666de1SXin Long 	if (sflags & SCTP_EOF) {
1750c2666de1SXin Long 		pr_debug("%s: shutting down association:%p\n", __func__, asoc);
1751c2666de1SXin Long 		sctp_primitive_SHUTDOWN(net, asoc, NULL);
1752c2666de1SXin Long 
1753c2666de1SXin Long 		return 0;
1754c2666de1SXin Long 	}
1755c2666de1SXin Long 
1756c2666de1SXin Long 	if (sflags & SCTP_ABORT) {
1757c2666de1SXin Long 		struct sctp_chunk *chunk;
1758c2666de1SXin Long 
1759c2666de1SXin Long 		chunk = sctp_make_abort_user(asoc, msg, msg_len);
1760c2666de1SXin Long 		if (!chunk)
1761c2666de1SXin Long 			return -ENOMEM;
1762c2666de1SXin Long 
1763c2666de1SXin Long 		pr_debug("%s: aborting association:%p\n", __func__, asoc);
1764c2666de1SXin Long 		sctp_primitive_ABORT(net, asoc, chunk);
1765901efe12SXin Long 		iov_iter_revert(&msg->msg_iter, msg_len);
1766c2666de1SXin Long 
1767c2666de1SXin Long 		return 0;
1768c2666de1SXin Long 	}
1769c2666de1SXin Long 
1770c2666de1SXin Long 	return 1;
1771c2666de1SXin Long }
1772c2666de1SXin Long 
1773f84af331SXin Long static int sctp_sendmsg_to_asoc(struct sctp_association *asoc,
1774f84af331SXin Long 				struct msghdr *msg, size_t msg_len,
1775f84af331SXin Long 				struct sctp_transport *transport,
1776f84af331SXin Long 				struct sctp_sndrcvinfo *sinfo)
1777f84af331SXin Long {
1778f84af331SXin Long 	struct sock *sk = asoc->base.sk;
177963d01330SMarcelo Ricardo Leitner 	struct sctp_sock *sp = sctp_sk(sk);
1780f84af331SXin Long 	struct net *net = sock_net(sk);
1781f84af331SXin Long 	struct sctp_datamsg *datamsg;
1782f84af331SXin Long 	bool wait_connect = false;
1783f84af331SXin Long 	struct sctp_chunk *chunk;
1784f84af331SXin Long 	long timeo;
1785f84af331SXin Long 	int err;
1786f84af331SXin Long 
1787f84af331SXin Long 	if (sinfo->sinfo_stream >= asoc->stream.outcnt) {
1788f84af331SXin Long 		err = -EINVAL;
1789f84af331SXin Long 		goto err;
1790f84af331SXin Long 	}
1791f84af331SXin Long 
179205364ca0SKonstantin Khorenko 	if (unlikely(!SCTP_SO(&asoc->stream, sinfo->sinfo_stream)->ext)) {
1793f84af331SXin Long 		err = sctp_stream_init_ext(&asoc->stream, sinfo->sinfo_stream);
1794f84af331SXin Long 		if (err)
1795f84af331SXin Long 			goto err;
1796f84af331SXin Long 	}
1797f84af331SXin Long 
179863d01330SMarcelo Ricardo Leitner 	if (sp->disable_fragments && msg_len > asoc->frag_point) {
1799f84af331SXin Long 		err = -EMSGSIZE;
1800f84af331SXin Long 		goto err;
1801f84af331SXin Long 	}
1802f84af331SXin Long 
18032521680eSMarcelo Ricardo Leitner 	if (asoc->pmtu_pending) {
180463d01330SMarcelo Ricardo Leitner 		if (sp->param_flags & SPP_PMTUD_ENABLE)
18052521680eSMarcelo Ricardo Leitner 			sctp_assoc_sync_pmtu(asoc);
18062521680eSMarcelo Ricardo Leitner 		asoc->pmtu_pending = 0;
18072521680eSMarcelo Ricardo Leitner 	}
18080aee4c25SNeil Horman 
1809cd305c74SXin Long 	if (sctp_wspace(asoc) < (int)msg_len)
18100aee4c25SNeil Horman 		sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc));
18110aee4c25SNeil Horman 
18121033990aSXin Long 	if (sk_under_memory_pressure(sk))
18131033990aSXin Long 		sk_mem_reclaim(sk);
18141033990aSXin Long 
18151033990aSXin Long 	if (sctp_wspace(asoc) <= 0 || !sk_wmem_schedule(sk, msg_len)) {
18160aee4c25SNeil Horman 		timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
18170aee4c25SNeil Horman 		err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len);
18180aee4c25SNeil Horman 		if (err)
18190aee4c25SNeil Horman 			goto err;
18200aee4c25SNeil Horman 	}
18210aee4c25SNeil Horman 
1822f84af331SXin Long 	if (sctp_state(asoc, CLOSED)) {
1823f84af331SXin Long 		err = sctp_primitive_ASSOCIATE(net, asoc, NULL);
1824f84af331SXin Long 		if (err)
1825f84af331SXin Long 			goto err;
1826f84af331SXin Long 
1827e55f4b8bSXin Long 		if (asoc->ep->intl_enable) {
1828f84af331SXin Long 			timeo = sock_sndtimeo(sk, 0);
1829f84af331SXin Long 			err = sctp_wait_for_connect(asoc, &timeo);
1830c863850cSXin Long 			if (err) {
1831c863850cSXin Long 				err = -ESRCH;
1832f84af331SXin Long 				goto err;
1833c863850cSXin Long 			}
1834f84af331SXin Long 		} else {
1835f84af331SXin Long 			wait_connect = true;
1836f84af331SXin Long 		}
1837f84af331SXin Long 
1838f84af331SXin Long 		pr_debug("%s: we associated primitively\n", __func__);
1839f84af331SXin Long 	}
1840f84af331SXin Long 
1841f84af331SXin Long 	datamsg = sctp_datamsg_from_user(asoc, sinfo, &msg->msg_iter);
1842f84af331SXin Long 	if (IS_ERR(datamsg)) {
1843f84af331SXin Long 		err = PTR_ERR(datamsg);
1844f84af331SXin Long 		goto err;
1845f84af331SXin Long 	}
1846f84af331SXin Long 
1847f84af331SXin Long 	asoc->force_delay = !!(msg->msg_flags & MSG_MORE);
1848f84af331SXin Long 
1849f84af331SXin Long 	list_for_each_entry(chunk, &datamsg->chunks, frag_list) {
1850f84af331SXin Long 		sctp_chunk_hold(chunk);
1851f84af331SXin Long 		sctp_set_owner_w(chunk);
1852f84af331SXin Long 		chunk->transport = transport;
1853f84af331SXin Long 	}
1854f84af331SXin Long 
1855f84af331SXin Long 	err = sctp_primitive_SEND(net, asoc, datamsg);
1856f84af331SXin Long 	if (err) {
1857f84af331SXin Long 		sctp_datamsg_free(datamsg);
1858f84af331SXin Long 		goto err;
1859f84af331SXin Long 	}
1860f84af331SXin Long 
1861f84af331SXin Long 	pr_debug("%s: we sent primitively\n", __func__);
1862f84af331SXin Long 
1863f84af331SXin Long 	sctp_datamsg_put(datamsg);
1864f84af331SXin Long 
1865f84af331SXin Long 	if (unlikely(wait_connect)) {
1866f84af331SXin Long 		timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
1867f84af331SXin Long 		sctp_wait_for_connect(asoc, &timeo);
1868f84af331SXin Long 	}
1869f84af331SXin Long 
1870f84af331SXin Long 	err = msg_len;
1871f84af331SXin Long 
1872f84af331SXin Long err:
1873f84af331SXin Long 	return err;
1874f84af331SXin Long }
1875f84af331SXin Long 
1876becef9b1SXin Long static union sctp_addr *sctp_sendmsg_get_daddr(struct sock *sk,
1877becef9b1SXin Long 					       const struct msghdr *msg,
1878becef9b1SXin Long 					       struct sctp_cmsgs *cmsgs)
1879becef9b1SXin Long {
1880becef9b1SXin Long 	union sctp_addr *daddr = NULL;
1881becef9b1SXin Long 	int err;
1882becef9b1SXin Long 
1883becef9b1SXin Long 	if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) {
1884becef9b1SXin Long 		int len = msg->msg_namelen;
1885becef9b1SXin Long 
1886becef9b1SXin Long 		if (len > sizeof(*daddr))
1887becef9b1SXin Long 			len = sizeof(*daddr);
1888becef9b1SXin Long 
1889becef9b1SXin Long 		daddr = (union sctp_addr *)msg->msg_name;
1890becef9b1SXin Long 
1891becef9b1SXin Long 		err = sctp_verify_addr(sk, daddr, len);
1892becef9b1SXin Long 		if (err)
1893becef9b1SXin Long 			return ERR_PTR(err);
1894becef9b1SXin Long 	}
1895becef9b1SXin Long 
1896becef9b1SXin Long 	return daddr;
1897becef9b1SXin Long }
1898becef9b1SXin Long 
1899d42cb06eSXin Long static void sctp_sendmsg_update_sinfo(struct sctp_association *asoc,
1900d42cb06eSXin Long 				      struct sctp_sndrcvinfo *sinfo,
1901d42cb06eSXin Long 				      struct sctp_cmsgs *cmsgs)
1902d42cb06eSXin Long {
1903d42cb06eSXin Long 	if (!cmsgs->srinfo && !cmsgs->sinfo) {
1904d42cb06eSXin Long 		sinfo->sinfo_stream = asoc->default_stream;
1905d42cb06eSXin Long 		sinfo->sinfo_ppid = asoc->default_ppid;
1906d42cb06eSXin Long 		sinfo->sinfo_context = asoc->default_context;
1907d42cb06eSXin Long 		sinfo->sinfo_assoc_id = sctp_assoc2id(asoc);
1908ed63afb8SXin Long 
1909ed63afb8SXin Long 		if (!cmsgs->prinfo)
1910ed63afb8SXin Long 			sinfo->sinfo_flags = asoc->default_flags;
1911d42cb06eSXin Long 	}
1912d42cb06eSXin Long 
1913ed63afb8SXin Long 	if (!cmsgs->srinfo && !cmsgs->prinfo)
1914d42cb06eSXin Long 		sinfo->sinfo_timetolive = asoc->default_timetolive;
19153ff547c0SXin Long 
19163ff547c0SXin Long 	if (cmsgs->authinfo) {
19173ff547c0SXin Long 		/* Reuse sinfo_tsn to indicate that authinfo was set and
19183ff547c0SXin Long 		 * sinfo_ssn to save the keyid on tx path.
19193ff547c0SXin Long 		 */
19203ff547c0SXin Long 		sinfo->sinfo_tsn = 1;
19213ff547c0SXin Long 		sinfo->sinfo_ssn = cmsgs->authinfo->auth_keynumber;
19223ff547c0SXin Long 	}
1923d42cb06eSXin Long }
1924d42cb06eSXin Long 
19251b784140SYing Xue static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
19261da177e4SLinus Torvalds {
1927204f817fSXin Long 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
19288e87c6ebSXin Long 	struct sctp_transport *transport = NULL;
1929204f817fSXin Long 	struct sctp_sndrcvinfo _sinfo, *sinfo;
1930ba59fb02SGreg Kroah-Hartman 	struct sctp_association *asoc, *tmp;
1931007b7e18SXin Long 	struct sctp_cmsgs cmsgs;
1932becef9b1SXin Long 	union sctp_addr *daddr;
1933007b7e18SXin Long 	bool new = false;
1934007b7e18SXin Long 	__u16 sflags;
193563b94938SGeir Ola Vaagland 	int err;
19361da177e4SLinus Torvalds 
1937204f817fSXin Long 	/* Parse and get snd_info */
1938204f817fSXin Long 	err = sctp_sendmsg_parse(sk, &cmsgs, &_sinfo, msg, msg_len);
1939204f817fSXin Long 	if (err)
1940007b7e18SXin Long 		goto out;
19411da177e4SLinus Torvalds 
1942204f817fSXin Long 	sinfo  = &_sinfo;
1943007b7e18SXin Long 	sflags = sinfo->sinfo_flags;
19441da177e4SLinus Torvalds 
1945becef9b1SXin Long 	/* Get daddr from msg */
1946becef9b1SXin Long 	daddr = sctp_sendmsg_get_daddr(sk, msg, &cmsgs);
1947becef9b1SXin Long 	if (IS_ERR(daddr)) {
1948becef9b1SXin Long 		err = PTR_ERR(daddr);
1949007b7e18SXin Long 		goto out;
19501da177e4SLinus Torvalds 	}
19511da177e4SLinus Torvalds 
1952048ed4b6Swangweidong 	lock_sock(sk);
19531da177e4SLinus Torvalds 
195449102805SXin Long 	/* SCTP_SENDALL process */
195549102805SXin Long 	if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) {
1956ba59fb02SGreg Kroah-Hartman 		list_for_each_entry_safe(asoc, tmp, &ep->asocs, asocs) {
195749102805SXin Long 			err = sctp_sendmsg_check_sflags(asoc, sflags, msg,
195849102805SXin Long 							msg_len);
195949102805SXin Long 			if (err == 0)
196049102805SXin Long 				continue;
196149102805SXin Long 			if (err < 0)
196249102805SXin Long 				goto out_unlock;
196349102805SXin Long 
196449102805SXin Long 			sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs);
196549102805SXin Long 
196649102805SXin Long 			err = sctp_sendmsg_to_asoc(asoc, msg, msg_len,
196749102805SXin Long 						   NULL, sinfo);
196849102805SXin Long 			if (err < 0)
196949102805SXin Long 				goto out_unlock;
197049102805SXin Long 
197149102805SXin Long 			iov_iter_revert(&msg->msg_iter, err);
197249102805SXin Long 		}
197349102805SXin Long 
197449102805SXin Long 		goto out_unlock;
197549102805SXin Long 	}
197649102805SXin Long 
19770a3920d2SXin Long 	/* Get and check or create asoc */
1978becef9b1SXin Long 	if (daddr) {
1979becef9b1SXin Long 		asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
19801da177e4SLinus Torvalds 		if (asoc) {
19810a3920d2SXin Long 			err = sctp_sendmsg_check_sflags(asoc, sflags, msg,
19820a3920d2SXin Long 							msg_len);
1983c2666de1SXin Long 			if (err <= 0)
19841da177e4SLinus Torvalds 				goto out_unlock;
19850a3920d2SXin Long 		} else {
1986007b7e18SXin Long 			err = sctp_sendmsg_new_asoc(sk, sflags, &cmsgs, daddr,
19872bfd80f9SXin Long 						    &transport);
1988625637bfSXin Long 			if (err)
19892bfd80f9SXin Long 				goto out_unlock;
19901da177e4SLinus Torvalds 
19912bfd80f9SXin Long 			asoc = transport->asoc;
1992007b7e18SXin Long 			new = true;
19931da177e4SLinus Torvalds 		}
19941da177e4SLinus Torvalds 
1995007b7e18SXin Long 		if (!sctp_style(sk, TCP) && !(sflags & SCTP_ADDR_OVER))
19968e87c6ebSXin Long 			transport = NULL;
19970a3920d2SXin Long 	} else {
19980a3920d2SXin Long 		asoc = sctp_id2assoc(sk, sinfo->sinfo_assoc_id);
19990a3920d2SXin Long 		if (!asoc) {
20000a3920d2SXin Long 			err = -EPIPE;
20010a3920d2SXin Long 			goto out_unlock;
20020a3920d2SXin Long 		}
20030a3920d2SXin Long 
20040a3920d2SXin Long 		err = sctp_sendmsg_check_sflags(asoc, sflags, msg, msg_len);
20050a3920d2SXin Long 		if (err <= 0)
20060a3920d2SXin Long 			goto out_unlock;
20070a3920d2SXin Long 	}
20088e87c6ebSXin Long 
2009d42cb06eSXin Long 	/* Update snd_info with the asoc */
2010d42cb06eSXin Long 	sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs);
20111da177e4SLinus Torvalds 
2012f84af331SXin Long 	/* Send msg to the asoc */
20138e87c6ebSXin Long 	err = sctp_sendmsg_to_asoc(asoc, msg, msg_len, transport, sinfo);
2014007b7e18SXin Long 	if (err < 0 && err != -ESRCH && new)
20151da177e4SLinus Torvalds 		sctp_association_free(asoc);
20168e87c6ebSXin Long 
20171da177e4SLinus Torvalds out_unlock:
2018048ed4b6Swangweidong 	release_sock(sk);
2019007b7e18SXin Long out:
2020f84af331SXin Long 	return sctp_error(sk, msg->msg_flags, err);
20211da177e4SLinus Torvalds }
20221da177e4SLinus Torvalds 
20231da177e4SLinus Torvalds /* This is an extended version of skb_pull() that removes the data from the
20241da177e4SLinus Torvalds  * start of a skb even when data is spread across the list of skb's in the
20251da177e4SLinus Torvalds  * frag_list. len specifies the total amount of data that needs to be removed.
20261da177e4SLinus Torvalds  * when 'len' bytes could be removed from the skb, it returns 0.
20271da177e4SLinus Torvalds  * If 'len' exceeds the total skb length,  it returns the no. of bytes that
20281da177e4SLinus Torvalds  * could not be removed.
20291da177e4SLinus Torvalds  */
20301da177e4SLinus Torvalds static int sctp_skb_pull(struct sk_buff *skb, int len)
20311da177e4SLinus Torvalds {
20321da177e4SLinus Torvalds 	struct sk_buff *list;
20331da177e4SLinus Torvalds 	int skb_len = skb_headlen(skb);
20341da177e4SLinus Torvalds 	int rlen;
20351da177e4SLinus Torvalds 
20361da177e4SLinus Torvalds 	if (len <= skb_len) {
20371da177e4SLinus Torvalds 		__skb_pull(skb, len);
20381da177e4SLinus Torvalds 		return 0;
20391da177e4SLinus Torvalds 	}
20401da177e4SLinus Torvalds 	len -= skb_len;
20411da177e4SLinus Torvalds 	__skb_pull(skb, skb_len);
20421da177e4SLinus Torvalds 
20431b003be3SDavid S. Miller 	skb_walk_frags(skb, list) {
20441da177e4SLinus Torvalds 		rlen = sctp_skb_pull(list, len);
20451da177e4SLinus Torvalds 		skb->len -= (len-rlen);
20461da177e4SLinus Torvalds 		skb->data_len -= (len-rlen);
20471da177e4SLinus Torvalds 
20481da177e4SLinus Torvalds 		if (!rlen)
20491da177e4SLinus Torvalds 			return 0;
20501da177e4SLinus Torvalds 
20511da177e4SLinus Torvalds 		len = rlen;
20521da177e4SLinus Torvalds 	}
20531da177e4SLinus Torvalds 
20541da177e4SLinus Torvalds 	return len;
20551da177e4SLinus Torvalds }
20561da177e4SLinus Torvalds 
20571da177e4SLinus Torvalds /* API 3.1.3  recvmsg() - UDP Style Syntax
20581da177e4SLinus Torvalds  *
20591da177e4SLinus Torvalds  *  ssize_t recvmsg(int socket, struct msghdr *message,
20601da177e4SLinus Torvalds  *                    int flags);
20611da177e4SLinus Torvalds  *
20621da177e4SLinus Torvalds  *  socket  - the socket descriptor of the endpoint.
20631da177e4SLinus Torvalds  *  message - pointer to the msghdr structure which contains a single
20641da177e4SLinus Torvalds  *            user message and possibly some ancillary data.
20651da177e4SLinus Torvalds  *
20661da177e4SLinus Torvalds  *            See Section 5 for complete description of the data
20671da177e4SLinus Torvalds  *            structures.
20681da177e4SLinus Torvalds  *
20691da177e4SLinus Torvalds  *  flags   - flags sent or received with the user message, see Section
20701da177e4SLinus Torvalds  *            5 for complete description of the flags.
20711da177e4SLinus Torvalds  */
20721b784140SYing Xue static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
20731b784140SYing Xue 			int noblock, int flags, int *addr_len)
20741da177e4SLinus Torvalds {
20751da177e4SLinus Torvalds 	struct sctp_ulpevent *event = NULL;
20761da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
20771f45f78fSMarcelo Ricardo Leitner 	struct sk_buff *skb, *head_skb;
20781da177e4SLinus Torvalds 	int copied;
20791da177e4SLinus Torvalds 	int err = 0;
20801da177e4SLinus Torvalds 	int skb_len;
20811da177e4SLinus Torvalds 
2082bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, msghdr:%p, len:%zd, noblock:%d, flags:0x%x, "
2083bb33381dSDaniel Borkmann 		 "addr_len:%p)\n", __func__, sk, msg, len, noblock, flags,
2084bb33381dSDaniel Borkmann 		 addr_len);
20851da177e4SLinus Torvalds 
2086048ed4b6Swangweidong 	lock_sock(sk);
20871da177e4SLinus Torvalds 
2088e5b13f34SMarcelo Ricardo Leitner 	if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED) &&
2089e0878694SXin Long 	    !sctp_sstate(sk, CLOSING) && !sctp_sstate(sk, CLOSED)) {
20901da177e4SLinus Torvalds 		err = -ENOTCONN;
20911da177e4SLinus Torvalds 		goto out;
20921da177e4SLinus Torvalds 	}
20931da177e4SLinus Torvalds 
20941da177e4SLinus Torvalds 	skb = sctp_skb_recv_datagram(sk, flags, noblock, &err);
20951da177e4SLinus Torvalds 	if (!skb)
20961da177e4SLinus Torvalds 		goto out;
20971da177e4SLinus Torvalds 
20981da177e4SLinus Torvalds 	/* Get the total length of the skb including any skb's in the
20991da177e4SLinus Torvalds 	 * frag_list.
21001da177e4SLinus Torvalds 	 */
21011da177e4SLinus Torvalds 	skb_len = skb->len;
21021da177e4SLinus Torvalds 
21031da177e4SLinus Torvalds 	copied = skb_len;
21041da177e4SLinus Torvalds 	if (copied > len)
21051da177e4SLinus Torvalds 		copied = len;
21061da177e4SLinus Torvalds 
210751f3d02bSDavid S. Miller 	err = skb_copy_datagram_msg(skb, 0, msg, copied);
21081da177e4SLinus Torvalds 
21091da177e4SLinus Torvalds 	event = sctp_skb2event(skb);
21101da177e4SLinus Torvalds 
21111da177e4SLinus Torvalds 	if (err)
21121da177e4SLinus Torvalds 		goto out_free;
21131da177e4SLinus Torvalds 
21141f45f78fSMarcelo Ricardo Leitner 	if (event->chunk && event->chunk->head_skb)
21151f45f78fSMarcelo Ricardo Leitner 		head_skb = event->chunk->head_skb;
21161f45f78fSMarcelo Ricardo Leitner 	else
21171f45f78fSMarcelo Ricardo Leitner 		head_skb = skb;
21181f45f78fSMarcelo Ricardo Leitner 	sock_recv_ts_and_drops(msg, sk, head_skb);
21191da177e4SLinus Torvalds 	if (sctp_ulpevent_is_notification(event)) {
21201da177e4SLinus Torvalds 		msg->msg_flags |= MSG_NOTIFICATION;
21211da177e4SLinus Torvalds 		sp->pf->event_msgname(event, msg->msg_name, addr_len);
21221da177e4SLinus Torvalds 	} else {
21231f45f78fSMarcelo Ricardo Leitner 		sp->pf->skb_msgname(head_skb, msg->msg_name, addr_len);
21241da177e4SLinus Torvalds 	}
21251da177e4SLinus Torvalds 
21262347c80fSGeir Ola Vaagland 	/* Check if we allow SCTP_NXTINFO. */
21272347c80fSGeir Ola Vaagland 	if (sp->recvnxtinfo)
21282347c80fSGeir Ola Vaagland 		sctp_ulpevent_read_nxtinfo(event, msg, sk);
21290d3a421dSGeir Ola Vaagland 	/* Check if we allow SCTP_RCVINFO. */
21300d3a421dSGeir Ola Vaagland 	if (sp->recvrcvinfo)
21310d3a421dSGeir Ola Vaagland 		sctp_ulpevent_read_rcvinfo(event, msg);
21321da177e4SLinus Torvalds 	/* Check if we allow SCTP_SNDRCVINFO. */
21332cc0eeb6SXin Long 	if (sctp_ulpevent_type_enabled(sp->subscribe, SCTP_DATA_IO_EVENT))
21341da177e4SLinus Torvalds 		sctp_ulpevent_read_sndrcvinfo(event, msg);
21350d3a421dSGeir Ola Vaagland 
21361da177e4SLinus Torvalds 	err = copied;
21371da177e4SLinus Torvalds 
21381da177e4SLinus Torvalds 	/* If skb's length exceeds the user's buffer, update the skb and
21391da177e4SLinus Torvalds 	 * push it back to the receive_queue so that the next call to
21401da177e4SLinus Torvalds 	 * recvmsg() will return the remaining data. Don't set MSG_EOR.
21411da177e4SLinus Torvalds 	 */
21421da177e4SLinus Torvalds 	if (skb_len > copied) {
21431da177e4SLinus Torvalds 		msg->msg_flags &= ~MSG_EOR;
21441da177e4SLinus Torvalds 		if (flags & MSG_PEEK)
21451da177e4SLinus Torvalds 			goto out_free;
21461da177e4SLinus Torvalds 		sctp_skb_pull(skb, copied);
21471da177e4SLinus Torvalds 		skb_queue_head(&sk->sk_receive_queue, skb);
21481da177e4SLinus Torvalds 
2149362d5204SDaniel Borkmann 		/* When only partial message is copied to the user, increase
2150362d5204SDaniel Borkmann 		 * rwnd by that amount. If all the data in the skb is read,
2151362d5204SDaniel Borkmann 		 * rwnd is updated when the event is freed.
2152362d5204SDaniel Borkmann 		 */
2153362d5204SDaniel Borkmann 		if (!sctp_ulpevent_is_notification(event))
2154362d5204SDaniel Borkmann 			sctp_assoc_rwnd_increase(event->asoc, copied);
21551da177e4SLinus Torvalds 		goto out;
21561da177e4SLinus Torvalds 	} else if ((event->msg_flags & MSG_NOTIFICATION) ||
21571da177e4SLinus Torvalds 		   (event->msg_flags & MSG_EOR))
21581da177e4SLinus Torvalds 		msg->msg_flags |= MSG_EOR;
21591da177e4SLinus Torvalds 	else
21601da177e4SLinus Torvalds 		msg->msg_flags &= ~MSG_EOR;
21611da177e4SLinus Torvalds 
21621da177e4SLinus Torvalds out_free:
21631da177e4SLinus Torvalds 	if (flags & MSG_PEEK) {
21641da177e4SLinus Torvalds 		/* Release the skb reference acquired after peeking the skb in
21651da177e4SLinus Torvalds 		 * sctp_skb_recv_datagram().
21661da177e4SLinus Torvalds 		 */
21671da177e4SLinus Torvalds 		kfree_skb(skb);
21681da177e4SLinus Torvalds 	} else {
21691da177e4SLinus Torvalds 		/* Free the event which includes releasing the reference to
21701da177e4SLinus Torvalds 		 * the owner of the skb, freeing the skb and updating the
21711da177e4SLinus Torvalds 		 * rwnd.
21721da177e4SLinus Torvalds 		 */
21731da177e4SLinus Torvalds 		sctp_ulpevent_free(event);
21741da177e4SLinus Torvalds 	}
21751da177e4SLinus Torvalds out:
2176048ed4b6Swangweidong 	release_sock(sk);
21771da177e4SLinus Torvalds 	return err;
21781da177e4SLinus Torvalds }
21791da177e4SLinus Torvalds 
21801da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
21811da177e4SLinus Torvalds  *
21821da177e4SLinus Torvalds  * This option is a on/off flag.  If enabled no SCTP message
21831da177e4SLinus Torvalds  * fragmentation will be performed.  Instead if a message being sent
21841da177e4SLinus Torvalds  * exceeds the current PMTU size, the message will NOT be sent and
21851da177e4SLinus Torvalds  * instead a error will be indicated to the user.
21861da177e4SLinus Torvalds  */
218710835825SChristoph Hellwig static int sctp_setsockopt_disable_fragments(struct sock *sk, int *val,
2188b7058842SDavid S. Miller 					     unsigned int optlen)
21891da177e4SLinus Torvalds {
21901da177e4SLinus Torvalds 	if (optlen < sizeof(int))
21911da177e4SLinus Torvalds 		return -EINVAL;
219210835825SChristoph Hellwig 	sctp_sk(sk)->disable_fragments = (*val == 0) ? 0 : 1;
21931da177e4SLinus Torvalds 	return 0;
21941da177e4SLinus Torvalds }
21951da177e4SLinus Torvalds 
2196a98d21a1SChristoph Hellwig static int sctp_setsockopt_events(struct sock *sk, __u8 *sn_type,
2197b7058842SDavid S. Miller 				  unsigned int optlen)
21981da177e4SLinus Torvalds {
21992cc0eeb6SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
2200a1e3a059SXin Long 	struct sctp_association *asoc;
22012cc0eeb6SXin Long 	int i;
220294912301SWei Yongjun 
22037e8616d8SVlad Yasevich 	if (optlen > sizeof(struct sctp_event_subscribe))
22041da177e4SLinus Torvalds 		return -EINVAL;
22052cc0eeb6SXin Long 
22062cc0eeb6SXin Long 	for (i = 0; i < optlen; i++)
22072cc0eeb6SXin Long 		sctp_ulpevent_type_set(&sp->subscribe, SCTP_SN_TYPE_BASE + i,
22082cc0eeb6SXin Long 				       sn_type[i]);
22092cc0eeb6SXin Long 
2210a1e3a059SXin Long 	list_for_each_entry(asoc, &sp->ep->asocs, asocs)
2211a1e3a059SXin Long 		asoc->subscribe = sctp_sk(sk)->subscribe;
2212a1e3a059SXin Long 
2213bbbea41dSDaniel Borkmann 	/* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT,
221494912301SWei Yongjun 	 * if there is no data to be sent or retransmit, the stack will
221594912301SWei Yongjun 	 * immediately send up this notification.
221694912301SWei Yongjun 	 */
22172cc0eeb6SXin Long 	if (sctp_ulpevent_type_enabled(sp->subscribe, SCTP_SENDER_DRY_EVENT)) {
22182cc0eeb6SXin Long 		struct sctp_ulpevent *event;
221994912301SWei Yongjun 
2220a1e3a059SXin Long 		asoc = sctp_id2assoc(sk, 0);
222194912301SWei Yongjun 		if (asoc && sctp_outq_is_empty(&asoc->outqueue)) {
222294912301SWei Yongjun 			event = sctp_ulpevent_make_sender_dry_event(asoc,
22232e83acb9SMarcelo Ricardo Leitner 					GFP_USER | __GFP_NOWARN);
222494912301SWei Yongjun 			if (!event)
222594912301SWei Yongjun 				return -ENOMEM;
222694912301SWei Yongjun 
22279162e0edSXin Long 			asoc->stream.si->enqueue_event(&asoc->ulpq, event);
222894912301SWei Yongjun 		}
222994912301SWei Yongjun 	}
223094912301SWei Yongjun 
22311da177e4SLinus Torvalds 	return 0;
22321da177e4SLinus Torvalds }
22331da177e4SLinus Torvalds 
22341da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE)
22351da177e4SLinus Torvalds  *
22361da177e4SLinus Torvalds  * This socket option is applicable to the UDP-style socket only.  When
22371da177e4SLinus Torvalds  * set it will cause associations that are idle for more than the
22381da177e4SLinus Torvalds  * specified number of seconds to automatically close.  An association
22391da177e4SLinus Torvalds  * being idle is defined an association that has NOT sent or received
22401da177e4SLinus Torvalds  * user data.  The special value of '0' indicates that no automatic
22411da177e4SLinus Torvalds  * close of any associations should be performed.  The option expects an
22421da177e4SLinus Torvalds  * integer defining the number of seconds of idle time before an
22431da177e4SLinus Torvalds  * association is closed.
22441da177e4SLinus Torvalds  */
2245*0b49a65cSChristoph Hellwig static int sctp_setsockopt_autoclose(struct sock *sk, u32 *optval,
2246b7058842SDavid S. Miller 				     unsigned int optlen)
22471da177e4SLinus Torvalds {
22481da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
22499f70f46bSNeil Horman 	struct net *net = sock_net(sk);
22501da177e4SLinus Torvalds 
22511da177e4SLinus Torvalds 	/* Applicable to UDP-style socket only */
22521da177e4SLinus Torvalds 	if (sctp_style(sk, TCP))
22531da177e4SLinus Torvalds 		return -EOPNOTSUPP;
22541da177e4SLinus Torvalds 	if (optlen != sizeof(int))
22551da177e4SLinus Torvalds 		return -EINVAL;
22561da177e4SLinus Torvalds 
2257*0b49a65cSChristoph Hellwig 	sp->autoclose = *optval;
22589f70f46bSNeil Horman 	if (sp->autoclose > net->sctp.max_autoclose)
22599f70f46bSNeil Horman 		sp->autoclose = net->sctp.max_autoclose;
22609f70f46bSNeil Horman 
22611da177e4SLinus Torvalds 	return 0;
22621da177e4SLinus Torvalds }
22631da177e4SLinus Torvalds 
22641da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS)
22651da177e4SLinus Torvalds  *
22661da177e4SLinus Torvalds  * Applications can enable or disable heartbeats for any peer address of
22671da177e4SLinus Torvalds  * an association, modify an address's heartbeat interval, force a
22681da177e4SLinus Torvalds  * heartbeat to be sent immediately, and adjust the address's maximum
22691da177e4SLinus Torvalds  * number of retransmissions sent before an address is considered
22701da177e4SLinus Torvalds  * unreachable.  The following structure is used to access and modify an
22711da177e4SLinus Torvalds  * address's parameters:
22721da177e4SLinus Torvalds  *
22731da177e4SLinus Torvalds  *  struct sctp_paddrparams {
22741da177e4SLinus Torvalds  *     sctp_assoc_t            spp_assoc_id;
22751da177e4SLinus Torvalds  *     struct sockaddr_storage spp_address;
22761da177e4SLinus Torvalds  *     uint32_t                spp_hbinterval;
22771da177e4SLinus Torvalds  *     uint16_t                spp_pathmaxrxt;
227852ccb8e9SFrank Filz  *     uint32_t                spp_pathmtu;
227952ccb8e9SFrank Filz  *     uint32_t                spp_sackdelay;
228052ccb8e9SFrank Filz  *     uint32_t                spp_flags;
22810b0dce7aSXin Long  *     uint32_t                spp_ipv6_flowlabel;
22820b0dce7aSXin Long  *     uint8_t                 spp_dscp;
22831da177e4SLinus Torvalds  * };
22841da177e4SLinus Torvalds  *
228552ccb8e9SFrank Filz  *   spp_assoc_id    - (one-to-many style socket) This is filled in the
228652ccb8e9SFrank Filz  *                     application, and identifies the association for
228752ccb8e9SFrank Filz  *                     this query.
22881da177e4SLinus Torvalds  *   spp_address     - This specifies which address is of interest.
22891da177e4SLinus Torvalds  *   spp_hbinterval  - This contains the value of the heartbeat interval,
229052ccb8e9SFrank Filz  *                     in milliseconds.  If a  value of zero
229152ccb8e9SFrank Filz  *                     is present in this field then no changes are to
229252ccb8e9SFrank Filz  *                     be made to this parameter.
22931da177e4SLinus Torvalds  *   spp_pathmaxrxt  - This contains the maximum number of
22941da177e4SLinus Torvalds  *                     retransmissions before this address shall be
229552ccb8e9SFrank Filz  *                     considered unreachable. If a  value of zero
229652ccb8e9SFrank Filz  *                     is present in this field then no changes are to
229752ccb8e9SFrank Filz  *                     be made to this parameter.
229852ccb8e9SFrank Filz  *   spp_pathmtu     - When Path MTU discovery is disabled the value
229952ccb8e9SFrank Filz  *                     specified here will be the "fixed" path mtu.
230052ccb8e9SFrank Filz  *                     Note that if the spp_address field is empty
230152ccb8e9SFrank Filz  *                     then all associations on this address will
230252ccb8e9SFrank Filz  *                     have this fixed path mtu set upon them.
230352ccb8e9SFrank Filz  *
230452ccb8e9SFrank Filz  *   spp_sackdelay   - When delayed sack is enabled, this value specifies
230552ccb8e9SFrank Filz  *                     the number of milliseconds that sacks will be delayed
230652ccb8e9SFrank Filz  *                     for. This value will apply to all addresses of an
230752ccb8e9SFrank Filz  *                     association if the spp_address field is empty. Note
230852ccb8e9SFrank Filz  *                     also, that if delayed sack is enabled and this
230952ccb8e9SFrank Filz  *                     value is set to 0, no change is made to the last
231052ccb8e9SFrank Filz  *                     recorded delayed sack timer value.
231152ccb8e9SFrank Filz  *
231252ccb8e9SFrank Filz  *   spp_flags       - These flags are used to control various features
231352ccb8e9SFrank Filz  *                     on an association. The flag field may contain
231452ccb8e9SFrank Filz  *                     zero or more of the following options.
231552ccb8e9SFrank Filz  *
231652ccb8e9SFrank Filz  *                     SPP_HB_ENABLE  - Enable heartbeats on the
231752ccb8e9SFrank Filz  *                     specified address. Note that if the address
231852ccb8e9SFrank Filz  *                     field is empty all addresses for the association
231952ccb8e9SFrank Filz  *                     have heartbeats enabled upon them.
232052ccb8e9SFrank Filz  *
232152ccb8e9SFrank Filz  *                     SPP_HB_DISABLE - Disable heartbeats on the
232252ccb8e9SFrank Filz  *                     speicifed address. Note that if the address
232352ccb8e9SFrank Filz  *                     field is empty all addresses for the association
232452ccb8e9SFrank Filz  *                     will have their heartbeats disabled. Note also
232552ccb8e9SFrank Filz  *                     that SPP_HB_ENABLE and SPP_HB_DISABLE are
232652ccb8e9SFrank Filz  *                     mutually exclusive, only one of these two should
232752ccb8e9SFrank Filz  *                     be specified. Enabling both fields will have
232852ccb8e9SFrank Filz  *                     undetermined results.
232952ccb8e9SFrank Filz  *
233052ccb8e9SFrank Filz  *                     SPP_HB_DEMAND - Request a user initiated heartbeat
233152ccb8e9SFrank Filz  *                     to be made immediately.
233252ccb8e9SFrank Filz  *
2333bdf3092aSVlad Yasevich  *                     SPP_HB_TIME_IS_ZERO - Specify's that the time for
2334bdf3092aSVlad Yasevich  *                     heartbeat delayis to be set to the value of 0
2335bdf3092aSVlad Yasevich  *                     milliseconds.
2336bdf3092aSVlad Yasevich  *
233752ccb8e9SFrank Filz  *                     SPP_PMTUD_ENABLE - This field will enable PMTU
233852ccb8e9SFrank Filz  *                     discovery upon the specified address. Note that
233952ccb8e9SFrank Filz  *                     if the address feild is empty then all addresses
234052ccb8e9SFrank Filz  *                     on the association are effected.
234152ccb8e9SFrank Filz  *
234252ccb8e9SFrank Filz  *                     SPP_PMTUD_DISABLE - This field will disable PMTU
234352ccb8e9SFrank Filz  *                     discovery upon the specified address. Note that
234452ccb8e9SFrank Filz  *                     if the address feild is empty then all addresses
234552ccb8e9SFrank Filz  *                     on the association are effected. Not also that
234652ccb8e9SFrank Filz  *                     SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually
234752ccb8e9SFrank Filz  *                     exclusive. Enabling both will have undetermined
234852ccb8e9SFrank Filz  *                     results.
234952ccb8e9SFrank Filz  *
235052ccb8e9SFrank Filz  *                     SPP_SACKDELAY_ENABLE - Setting this flag turns
235152ccb8e9SFrank Filz  *                     on delayed sack. The time specified in spp_sackdelay
235252ccb8e9SFrank Filz  *                     is used to specify the sack delay for this address. Note
235352ccb8e9SFrank Filz  *                     that if spp_address is empty then all addresses will
235452ccb8e9SFrank Filz  *                     enable delayed sack and take on the sack delay
235552ccb8e9SFrank Filz  *                     value specified in spp_sackdelay.
235652ccb8e9SFrank Filz  *                     SPP_SACKDELAY_DISABLE - Setting this flag turns
235752ccb8e9SFrank Filz  *                     off delayed sack. If the spp_address field is blank then
235852ccb8e9SFrank Filz  *                     delayed sack is disabled for the entire association. Note
235952ccb8e9SFrank Filz  *                     also that this field is mutually exclusive to
236052ccb8e9SFrank Filz  *                     SPP_SACKDELAY_ENABLE, setting both will have undefined
236152ccb8e9SFrank Filz  *                     results.
23620b0dce7aSXin Long  *
23630b0dce7aSXin Long  *                     SPP_IPV6_FLOWLABEL:  Setting this flag enables the
23640b0dce7aSXin Long  *                     setting of the IPV6 flow label value.  The value is
23650b0dce7aSXin Long  *                     contained in the spp_ipv6_flowlabel field.
23660b0dce7aSXin Long  *                     Upon retrieval, this flag will be set to indicate that
23670b0dce7aSXin Long  *                     the spp_ipv6_flowlabel field has a valid value returned.
23680b0dce7aSXin Long  *                     If a specific destination address is set (in the
23690b0dce7aSXin Long  *                     spp_address field), then the value returned is that of
23700b0dce7aSXin Long  *                     the address.  If just an association is specified (and
23710b0dce7aSXin Long  *                     no address), then the association's default flow label
23720b0dce7aSXin Long  *                     is returned.  If neither an association nor a destination
23730b0dce7aSXin Long  *                     is specified, then the socket's default flow label is
23740b0dce7aSXin Long  *                     returned.  For non-IPv6 sockets, this flag will be left
23750b0dce7aSXin Long  *                     cleared.
23760b0dce7aSXin Long  *
23770b0dce7aSXin Long  *                     SPP_DSCP:  Setting this flag enables the setting of the
23780b0dce7aSXin Long  *                     Differentiated Services Code Point (DSCP) value
23790b0dce7aSXin Long  *                     associated with either the association or a specific
23800b0dce7aSXin Long  *                     address.  The value is obtained in the spp_dscp field.
23810b0dce7aSXin Long  *                     Upon retrieval, this flag will be set to indicate that
23820b0dce7aSXin Long  *                     the spp_dscp field has a valid value returned.  If a
23830b0dce7aSXin Long  *                     specific destination address is set when called (in the
23840b0dce7aSXin Long  *                     spp_address field), then that specific destination
23850b0dce7aSXin Long  *                     address's DSCP value is returned.  If just an association
23860b0dce7aSXin Long  *                     is specified, then the association's default DSCP is
23870b0dce7aSXin Long  *                     returned.  If neither an association nor a destination is
23880b0dce7aSXin Long  *                     specified, then the socket's default DSCP is returned.
23890b0dce7aSXin Long  *
23900b0dce7aSXin Long  *   spp_ipv6_flowlabel
23910b0dce7aSXin Long  *                   - This field is used in conjunction with the
23920b0dce7aSXin Long  *                     SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label.
23930b0dce7aSXin Long  *                     The 20 least significant bits are used for the flow
23940b0dce7aSXin Long  *                     label.  This setting has precedence over any IPv6-layer
23950b0dce7aSXin Long  *                     setting.
23960b0dce7aSXin Long  *
23970b0dce7aSXin Long  *   spp_dscp        - This field is used in conjunction with the SPP_DSCP flag
23980b0dce7aSXin Long  *                     and contains the DSCP.  The 6 most significant bits are
23990b0dce7aSXin Long  *                     used for the DSCP.  This setting has precedence over any
24000b0dce7aSXin Long  *                     IPv4- or IPv6- layer setting.
24011da177e4SLinus Torvalds  */
240216164366SAdrian Bunk static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
240352ccb8e9SFrank Filz 				       struct sctp_transport   *trans,
240452ccb8e9SFrank Filz 				       struct sctp_association *asoc,
240552ccb8e9SFrank Filz 				       struct sctp_sock        *sp,
240652ccb8e9SFrank Filz 				       int                      hb_change,
240752ccb8e9SFrank Filz 				       int                      pmtud_change,
240852ccb8e9SFrank Filz 				       int                      sackdelay_change)
240952ccb8e9SFrank Filz {
241052ccb8e9SFrank Filz 	int error;
241152ccb8e9SFrank Filz 
241252ccb8e9SFrank Filz 	if (params->spp_flags & SPP_HB_DEMAND && trans) {
24134e7696d9SXin Long 		error = sctp_primitive_REQUESTHEARTBEAT(trans->asoc->base.net,
24144e7696d9SXin Long 							trans->asoc, trans);
241552ccb8e9SFrank Filz 		if (error)
241652ccb8e9SFrank Filz 			return error;
241752ccb8e9SFrank Filz 	}
241852ccb8e9SFrank Filz 
2419bdf3092aSVlad Yasevich 	/* Note that unless the spp_flag is set to SPP_HB_ENABLE the value of
2420bdf3092aSVlad Yasevich 	 * this field is ignored.  Note also that a value of zero indicates
2421bdf3092aSVlad Yasevich 	 * the current setting should be left unchanged.
2422bdf3092aSVlad Yasevich 	 */
2423bdf3092aSVlad Yasevich 	if (params->spp_flags & SPP_HB_ENABLE) {
2424bdf3092aSVlad Yasevich 
2425bdf3092aSVlad Yasevich 		/* Re-zero the interval if the SPP_HB_TIME_IS_ZERO is
2426bdf3092aSVlad Yasevich 		 * set.  This lets us use 0 value when this flag
2427bdf3092aSVlad Yasevich 		 * is set.
2428bdf3092aSVlad Yasevich 		 */
2429bdf3092aSVlad Yasevich 		if (params->spp_flags & SPP_HB_TIME_IS_ZERO)
2430bdf3092aSVlad Yasevich 			params->spp_hbinterval = 0;
2431bdf3092aSVlad Yasevich 
2432bdf3092aSVlad Yasevich 		if (params->spp_hbinterval ||
2433bdf3092aSVlad Yasevich 		    (params->spp_flags & SPP_HB_TIME_IS_ZERO)) {
243452ccb8e9SFrank Filz 			if (trans) {
2435bdf3092aSVlad Yasevich 				trans->hbinterval =
2436bdf3092aSVlad Yasevich 				    msecs_to_jiffies(params->spp_hbinterval);
243752ccb8e9SFrank Filz 			} else if (asoc) {
2438bdf3092aSVlad Yasevich 				asoc->hbinterval =
2439bdf3092aSVlad Yasevich 				    msecs_to_jiffies(params->spp_hbinterval);
244052ccb8e9SFrank Filz 			} else {
244152ccb8e9SFrank Filz 				sp->hbinterval = params->spp_hbinterval;
244252ccb8e9SFrank Filz 			}
244352ccb8e9SFrank Filz 		}
2444bdf3092aSVlad Yasevich 	}
244552ccb8e9SFrank Filz 
244652ccb8e9SFrank Filz 	if (hb_change) {
244752ccb8e9SFrank Filz 		if (trans) {
244852ccb8e9SFrank Filz 			trans->param_flags =
244952ccb8e9SFrank Filz 				(trans->param_flags & ~SPP_HB) | hb_change;
245052ccb8e9SFrank Filz 		} else if (asoc) {
245152ccb8e9SFrank Filz 			asoc->param_flags =
245252ccb8e9SFrank Filz 				(asoc->param_flags & ~SPP_HB) | hb_change;
245352ccb8e9SFrank Filz 		} else {
245452ccb8e9SFrank Filz 			sp->param_flags =
245552ccb8e9SFrank Filz 				(sp->param_flags & ~SPP_HB) | hb_change;
245652ccb8e9SFrank Filz 		}
245752ccb8e9SFrank Filz 	}
245852ccb8e9SFrank Filz 
2459bdf3092aSVlad Yasevich 	/* When Path MTU discovery is disabled the value specified here will
2460bdf3092aSVlad Yasevich 	 * be the "fixed" path mtu (i.e. the value of the spp_flags field must
2461bdf3092aSVlad Yasevich 	 * include the flag SPP_PMTUD_DISABLE for this field to have any
2462bdf3092aSVlad Yasevich 	 * effect).
2463bdf3092aSVlad Yasevich 	 */
2464bdf3092aSVlad Yasevich 	if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) {
246552ccb8e9SFrank Filz 		if (trans) {
246652ccb8e9SFrank Filz 			trans->pathmtu = params->spp_pathmtu;
24673ebfdf08SXin Long 			sctp_assoc_sync_pmtu(asoc);
246852ccb8e9SFrank Filz 		} else if (asoc) {
2469c4b2893dSMarcelo Ricardo Leitner 			sctp_assoc_set_pmtu(asoc, params->spp_pathmtu);
247052ccb8e9SFrank Filz 		} else {
247152ccb8e9SFrank Filz 			sp->pathmtu = params->spp_pathmtu;
247252ccb8e9SFrank Filz 		}
247352ccb8e9SFrank Filz 	}
247452ccb8e9SFrank Filz 
247552ccb8e9SFrank Filz 	if (pmtud_change) {
247652ccb8e9SFrank Filz 		if (trans) {
247752ccb8e9SFrank Filz 			int update = (trans->param_flags & SPP_PMTUD_DISABLE) &&
247852ccb8e9SFrank Filz 				(params->spp_flags & SPP_PMTUD_ENABLE);
247952ccb8e9SFrank Filz 			trans->param_flags =
248052ccb8e9SFrank Filz 				(trans->param_flags & ~SPP_PMTUD) | pmtud_change;
248152ccb8e9SFrank Filz 			if (update) {
24829914ae3cSVlad Yasevich 				sctp_transport_pmtu(trans, sctp_opt2sk(sp));
24833ebfdf08SXin Long 				sctp_assoc_sync_pmtu(asoc);
248452ccb8e9SFrank Filz 			}
248552ccb8e9SFrank Filz 		} else if (asoc) {
248652ccb8e9SFrank Filz 			asoc->param_flags =
248752ccb8e9SFrank Filz 				(asoc->param_flags & ~SPP_PMTUD) | pmtud_change;
248852ccb8e9SFrank Filz 		} else {
248952ccb8e9SFrank Filz 			sp->param_flags =
249052ccb8e9SFrank Filz 				(sp->param_flags & ~SPP_PMTUD) | pmtud_change;
249152ccb8e9SFrank Filz 		}
249252ccb8e9SFrank Filz 	}
249352ccb8e9SFrank Filz 
2494bdf3092aSVlad Yasevich 	/* Note that unless the spp_flag is set to SPP_SACKDELAY_ENABLE the
2495bdf3092aSVlad Yasevich 	 * value of this field is ignored.  Note also that a value of zero
2496bdf3092aSVlad Yasevich 	 * indicates the current setting should be left unchanged.
2497bdf3092aSVlad Yasevich 	 */
2498bdf3092aSVlad Yasevich 	if ((params->spp_flags & SPP_SACKDELAY_ENABLE) && params->spp_sackdelay) {
249952ccb8e9SFrank Filz 		if (trans) {
250052ccb8e9SFrank Filz 			trans->sackdelay =
250152ccb8e9SFrank Filz 				msecs_to_jiffies(params->spp_sackdelay);
250252ccb8e9SFrank Filz 		} else if (asoc) {
250352ccb8e9SFrank Filz 			asoc->sackdelay =
250452ccb8e9SFrank Filz 				msecs_to_jiffies(params->spp_sackdelay);
250552ccb8e9SFrank Filz 		} else {
250652ccb8e9SFrank Filz 			sp->sackdelay = params->spp_sackdelay;
250752ccb8e9SFrank Filz 		}
250852ccb8e9SFrank Filz 	}
250952ccb8e9SFrank Filz 
251052ccb8e9SFrank Filz 	if (sackdelay_change) {
251152ccb8e9SFrank Filz 		if (trans) {
251252ccb8e9SFrank Filz 			trans->param_flags =
251352ccb8e9SFrank Filz 				(trans->param_flags & ~SPP_SACKDELAY) |
251452ccb8e9SFrank Filz 				sackdelay_change;
251552ccb8e9SFrank Filz 		} else if (asoc) {
251652ccb8e9SFrank Filz 			asoc->param_flags =
251752ccb8e9SFrank Filz 				(asoc->param_flags & ~SPP_SACKDELAY) |
251852ccb8e9SFrank Filz 				sackdelay_change;
251952ccb8e9SFrank Filz 		} else {
252052ccb8e9SFrank Filz 			sp->param_flags =
252152ccb8e9SFrank Filz 				(sp->param_flags & ~SPP_SACKDELAY) |
252252ccb8e9SFrank Filz 				sackdelay_change;
252352ccb8e9SFrank Filz 		}
252452ccb8e9SFrank Filz 	}
252552ccb8e9SFrank Filz 
252637051f73SAndrei Pelinescu-Onciul 	/* Note that a value of zero indicates the current setting should be
252737051f73SAndrei Pelinescu-Onciul 	   left unchanged.
2528bdf3092aSVlad Yasevich 	 */
252937051f73SAndrei Pelinescu-Onciul 	if (params->spp_pathmaxrxt) {
253052ccb8e9SFrank Filz 		if (trans) {
253152ccb8e9SFrank Filz 			trans->pathmaxrxt = params->spp_pathmaxrxt;
253252ccb8e9SFrank Filz 		} else if (asoc) {
253352ccb8e9SFrank Filz 			asoc->pathmaxrxt = params->spp_pathmaxrxt;
253452ccb8e9SFrank Filz 		} else {
253552ccb8e9SFrank Filz 			sp->pathmaxrxt = params->spp_pathmaxrxt;
253652ccb8e9SFrank Filz 		}
253752ccb8e9SFrank Filz 	}
253852ccb8e9SFrank Filz 
25390b0dce7aSXin Long 	if (params->spp_flags & SPP_IPV6_FLOWLABEL) {
2540741880e1SXin Long 		if (trans) {
2541741880e1SXin Long 			if (trans->ipaddr.sa.sa_family == AF_INET6) {
25420b0dce7aSXin Long 				trans->flowlabel = params->spp_ipv6_flowlabel &
25430b0dce7aSXin Long 						   SCTP_FLOWLABEL_VAL_MASK;
25440b0dce7aSXin Long 				trans->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
2545741880e1SXin Long 			}
25460b0dce7aSXin Long 		} else if (asoc) {
2547af8a2b8bSXin Long 			struct sctp_transport *t;
2548af8a2b8bSXin Long 
2549af8a2b8bSXin Long 			list_for_each_entry(t, &asoc->peer.transport_addr_list,
25500b0dce7aSXin Long 					    transports) {
2551af8a2b8bSXin Long 				if (t->ipaddr.sa.sa_family != AF_INET6)
25520b0dce7aSXin Long 					continue;
2553af8a2b8bSXin Long 				t->flowlabel = params->spp_ipv6_flowlabel &
25540b0dce7aSXin Long 					       SCTP_FLOWLABEL_VAL_MASK;
2555af8a2b8bSXin Long 				t->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
25560b0dce7aSXin Long 			}
25570b0dce7aSXin Long 			asoc->flowlabel = params->spp_ipv6_flowlabel &
25580b0dce7aSXin Long 					  SCTP_FLOWLABEL_VAL_MASK;
25590b0dce7aSXin Long 			asoc->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
25600b0dce7aSXin Long 		} else if (sctp_opt2sk(sp)->sk_family == AF_INET6) {
25610b0dce7aSXin Long 			sp->flowlabel = params->spp_ipv6_flowlabel &
25620b0dce7aSXin Long 					SCTP_FLOWLABEL_VAL_MASK;
25630b0dce7aSXin Long 			sp->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
25640b0dce7aSXin Long 		}
25650b0dce7aSXin Long 	}
25660b0dce7aSXin Long 
25670b0dce7aSXin Long 	if (params->spp_flags & SPP_DSCP) {
25680b0dce7aSXin Long 		if (trans) {
25690b0dce7aSXin Long 			trans->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK;
25700b0dce7aSXin Long 			trans->dscp |= SCTP_DSCP_SET_MASK;
25710b0dce7aSXin Long 		} else if (asoc) {
2572af8a2b8bSXin Long 			struct sctp_transport *t;
2573af8a2b8bSXin Long 
2574af8a2b8bSXin Long 			list_for_each_entry(t, &asoc->peer.transport_addr_list,
25750b0dce7aSXin Long 					    transports) {
2576af8a2b8bSXin Long 				t->dscp = params->spp_dscp &
25770b0dce7aSXin Long 					  SCTP_DSCP_VAL_MASK;
2578af8a2b8bSXin Long 				t->dscp |= SCTP_DSCP_SET_MASK;
25790b0dce7aSXin Long 			}
25800b0dce7aSXin Long 			asoc->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK;
25810b0dce7aSXin Long 			asoc->dscp |= SCTP_DSCP_SET_MASK;
25820b0dce7aSXin Long 		} else {
25830b0dce7aSXin Long 			sp->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK;
25840b0dce7aSXin Long 			sp->dscp |= SCTP_DSCP_SET_MASK;
25850b0dce7aSXin Long 		}
25860b0dce7aSXin Long 	}
25870b0dce7aSXin Long 
258852ccb8e9SFrank Filz 	return 0;
258952ccb8e9SFrank Filz }
259052ccb8e9SFrank Filz 
25911da177e4SLinus Torvalds static int sctp_setsockopt_peer_addr_params(struct sock *sk,
2592b7058842SDavid S. Miller 					    char __user *optval,
2593b7058842SDavid S. Miller 					    unsigned int optlen)
25941da177e4SLinus Torvalds {
25951da177e4SLinus Torvalds 	struct sctp_paddrparams  params;
259652ccb8e9SFrank Filz 	struct sctp_transport   *trans = NULL;
259752ccb8e9SFrank Filz 	struct sctp_association *asoc = NULL;
259852ccb8e9SFrank Filz 	struct sctp_sock        *sp = sctp_sk(sk);
25991da177e4SLinus Torvalds 	int error;
260052ccb8e9SFrank Filz 	int hb_change, pmtud_change, sackdelay_change;
26011da177e4SLinus Torvalds 
26020b0dce7aSXin Long 	if (optlen == sizeof(params)) {
26031da177e4SLinus Torvalds 		if (copy_from_user(&params, optval, optlen))
26041da177e4SLinus Torvalds 			return -EFAULT;
26050b0dce7aSXin Long 	} else if (optlen == ALIGN(offsetof(struct sctp_paddrparams,
26060b0dce7aSXin Long 					    spp_ipv6_flowlabel), 4)) {
26070b0dce7aSXin Long 		if (copy_from_user(&params, optval, optlen))
26080b0dce7aSXin Long 			return -EFAULT;
26090b0dce7aSXin Long 		if (params.spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL))
26100b0dce7aSXin Long 			return -EINVAL;
26110b0dce7aSXin Long 	} else {
26120b0dce7aSXin Long 		return -EINVAL;
26130b0dce7aSXin Long 	}
26141da177e4SLinus Torvalds 
261552ccb8e9SFrank Filz 	/* Validate flags and value parameters. */
261652ccb8e9SFrank Filz 	hb_change        = params.spp_flags & SPP_HB;
261752ccb8e9SFrank Filz 	pmtud_change     = params.spp_flags & SPP_PMTUD;
261852ccb8e9SFrank Filz 	sackdelay_change = params.spp_flags & SPP_SACKDELAY;
26191da177e4SLinus Torvalds 
262052ccb8e9SFrank Filz 	if (hb_change        == SPP_HB ||
262152ccb8e9SFrank Filz 	    pmtud_change     == SPP_PMTUD ||
262252ccb8e9SFrank Filz 	    sackdelay_change == SPP_SACKDELAY ||
262352ccb8e9SFrank Filz 	    params.spp_sackdelay > 500 ||
2624f64f9e71SJoe Perches 	    (params.spp_pathmtu &&
2625f64f9e71SJoe Perches 	     params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
26261da177e4SLinus Torvalds 		return -EINVAL;
26271da177e4SLinus Torvalds 
262852ccb8e9SFrank Filz 	/* If an address other than INADDR_ANY is specified, and
262952ccb8e9SFrank Filz 	 * no transport is found, then the request is invalid.
263052ccb8e9SFrank Filz 	 */
263152cae8f0SVlad Yasevich 	if (!sctp_is_any(sk, (union sctp_addr *)&params.spp_address)) {
26321da177e4SLinus Torvalds 		trans = sctp_addr_id2transport(sk, &params.spp_address,
26331da177e4SLinus Torvalds 					       params.spp_assoc_id);
26341da177e4SLinus Torvalds 		if (!trans)
26351da177e4SLinus Torvalds 			return -EINVAL;
26361da177e4SLinus Torvalds 	}
26371da177e4SLinus Torvalds 
2638b99e5e02SXin Long 	/* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the
2639b99e5e02SXin Long 	 * socket is a one to many style socket, and an association
2640b99e5e02SXin Long 	 * was not found, then the id was invalid.
26411da177e4SLinus Torvalds 	 */
264252ccb8e9SFrank Filz 	asoc = sctp_id2assoc(sk, params.spp_assoc_id);
2643b99e5e02SXin Long 	if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC &&
2644b99e5e02SXin Long 	    sctp_style(sk, UDP))
264552ccb8e9SFrank Filz 		return -EINVAL;
264652ccb8e9SFrank Filz 
264752ccb8e9SFrank Filz 	/* Heartbeat demand can only be sent on a transport or
264852ccb8e9SFrank Filz 	 * association, but not a socket.
264952ccb8e9SFrank Filz 	 */
265052ccb8e9SFrank Filz 	if (params.spp_flags & SPP_HB_DEMAND && !trans && !asoc)
265152ccb8e9SFrank Filz 		return -EINVAL;
265252ccb8e9SFrank Filz 
265352ccb8e9SFrank Filz 	/* Process parameters. */
265452ccb8e9SFrank Filz 	error = sctp_apply_peer_addr_params(&params, trans, asoc, sp,
265552ccb8e9SFrank Filz 					    hb_change, pmtud_change,
265652ccb8e9SFrank Filz 					    sackdelay_change);
265752ccb8e9SFrank Filz 
265852ccb8e9SFrank Filz 	if (error)
265952ccb8e9SFrank Filz 		return error;
266052ccb8e9SFrank Filz 
266152ccb8e9SFrank Filz 	/* If changes are for association, also apply parameters to each
266252ccb8e9SFrank Filz 	 * transport.
266352ccb8e9SFrank Filz 	 */
266452ccb8e9SFrank Filz 	if (!trans && asoc) {
26659dbc15f0SRobert P. J. Day 		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
26669dbc15f0SRobert P. J. Day 				transports) {
266752ccb8e9SFrank Filz 			sctp_apply_peer_addr_params(&params, trans, asoc, sp,
266852ccb8e9SFrank Filz 						    hb_change, pmtud_change,
266952ccb8e9SFrank Filz 						    sackdelay_change);
267052ccb8e9SFrank Filz 		}
267152ccb8e9SFrank Filz 	}
26721da177e4SLinus Torvalds 
26731da177e4SLinus Torvalds 	return 0;
26741da177e4SLinus Torvalds }
26751da177e4SLinus Torvalds 
26760ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags)
26770ea5e4dfSwangweidong {
26780ea5e4dfSwangweidong 	return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE;
26790ea5e4dfSwangweidong }
26800ea5e4dfSwangweidong 
26810ea5e4dfSwangweidong static inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags)
26820ea5e4dfSwangweidong {
26830ea5e4dfSwangweidong 	return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE;
26840ea5e4dfSwangweidong }
26850ea5e4dfSwangweidong 
26869c5829e1SXin Long static void sctp_apply_asoc_delayed_ack(struct sctp_sack_info *params,
26879c5829e1SXin Long 					struct sctp_association *asoc)
26889c5829e1SXin Long {
26899c5829e1SXin Long 	struct sctp_transport *trans;
26909c5829e1SXin Long 
26919c5829e1SXin Long 	if (params->sack_delay) {
26929c5829e1SXin Long 		asoc->sackdelay = msecs_to_jiffies(params->sack_delay);
26939c5829e1SXin Long 		asoc->param_flags =
26949c5829e1SXin Long 			sctp_spp_sackdelay_enable(asoc->param_flags);
26959c5829e1SXin Long 	}
26969c5829e1SXin Long 	if (params->sack_freq == 1) {
26979c5829e1SXin Long 		asoc->param_flags =
26989c5829e1SXin Long 			sctp_spp_sackdelay_disable(asoc->param_flags);
26999c5829e1SXin Long 	} else if (params->sack_freq > 1) {
27009c5829e1SXin Long 		asoc->sackfreq = params->sack_freq;
27019c5829e1SXin Long 		asoc->param_flags =
27029c5829e1SXin Long 			sctp_spp_sackdelay_enable(asoc->param_flags);
27039c5829e1SXin Long 	}
27049c5829e1SXin Long 
27059c5829e1SXin Long 	list_for_each_entry(trans, &asoc->peer.transport_addr_list,
27069c5829e1SXin Long 			    transports) {
27079c5829e1SXin Long 		if (params->sack_delay) {
27089c5829e1SXin Long 			trans->sackdelay = msecs_to_jiffies(params->sack_delay);
27099c5829e1SXin Long 			trans->param_flags =
27109c5829e1SXin Long 				sctp_spp_sackdelay_enable(trans->param_flags);
27119c5829e1SXin Long 		}
27129c5829e1SXin Long 		if (params->sack_freq == 1) {
27139c5829e1SXin Long 			trans->param_flags =
27149c5829e1SXin Long 				sctp_spp_sackdelay_disable(trans->param_flags);
27159c5829e1SXin Long 		} else if (params->sack_freq > 1) {
27169c5829e1SXin Long 			trans->sackfreq = params->sack_freq;
27179c5829e1SXin Long 			trans->param_flags =
27189c5829e1SXin Long 				sctp_spp_sackdelay_enable(trans->param_flags);
27199c5829e1SXin Long 		}
27209c5829e1SXin Long 	}
27219c5829e1SXin Long }
27229c5829e1SXin Long 
2723d364d927SWei Yongjun /*
2724d364d927SWei Yongjun  * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
27257708610bSFrank Filz  *
2726d364d927SWei Yongjun  * This option will effect the way delayed acks are performed.  This
2727d364d927SWei Yongjun  * option allows you to get or set the delayed ack time, in
2728d364d927SWei Yongjun  * milliseconds.  It also allows changing the delayed ack frequency.
2729d364d927SWei Yongjun  * Changing the frequency to 1 disables the delayed sack algorithm.  If
2730d364d927SWei Yongjun  * the assoc_id is 0, then this sets or gets the endpoints default
2731d364d927SWei Yongjun  * values.  If the assoc_id field is non-zero, then the set or get
2732d364d927SWei Yongjun  * effects the specified association for the one to many model (the
2733d364d927SWei Yongjun  * assoc_id field is ignored by the one to one model).  Note that if
2734d364d927SWei Yongjun  * sack_delay or sack_freq are 0 when setting this option, then the
2735d364d927SWei Yongjun  * current values will remain unchanged.
27367708610bSFrank Filz  *
2737d364d927SWei Yongjun  * struct sctp_sack_info {
2738d364d927SWei Yongjun  *     sctp_assoc_t            sack_assoc_id;
2739d364d927SWei Yongjun  *     uint32_t                sack_delay;
2740d364d927SWei Yongjun  *     uint32_t                sack_freq;
27417708610bSFrank Filz  * };
27427708610bSFrank Filz  *
2743d364d927SWei Yongjun  * sack_assoc_id -  This parameter, indicates which association the user
2744d364d927SWei Yongjun  *    is performing an action upon.  Note that if this field's value is
2745d364d927SWei Yongjun  *    zero then the endpoints default value is changed (effecting future
27467708610bSFrank Filz  *    associations only).
27477708610bSFrank Filz  *
2748d364d927SWei Yongjun  * sack_delay -  This parameter contains the number of milliseconds that
2749d364d927SWei Yongjun  *    the user is requesting the delayed ACK timer be set to.  Note that
2750d364d927SWei Yongjun  *    this value is defined in the standard to be between 200 and 500
2751d364d927SWei Yongjun  *    milliseconds.
27527708610bSFrank Filz  *
2753d364d927SWei Yongjun  * sack_freq -  This parameter contains the number of packets that must
2754d364d927SWei Yongjun  *    be received before a sack is sent without waiting for the delay
2755d364d927SWei Yongjun  *    timer to expire.  The default value for this is 2, setting this
2756d364d927SWei Yongjun  *    value to 1 will disable the delayed sack algorithm.
27577708610bSFrank Filz  */
27587708610bSFrank Filz 
2759d364d927SWei Yongjun static int sctp_setsockopt_delayed_ack(struct sock *sk,
2760b7058842SDavid S. Miller 				       char __user *optval, unsigned int optlen)
27617708610bSFrank Filz {
27627708610bSFrank Filz 	struct sctp_sock *sp = sctp_sk(sk);
27639c5829e1SXin Long 	struct sctp_association *asoc;
27649c5829e1SXin Long 	struct sctp_sack_info params;
27657708610bSFrank Filz 
2766d364d927SWei Yongjun 	if (optlen == sizeof(struct sctp_sack_info)) {
27677708610bSFrank Filz 		if (copy_from_user(&params, optval, optlen))
27687708610bSFrank Filz 			return -EFAULT;
27697708610bSFrank Filz 
2770d364d927SWei Yongjun 		if (params.sack_delay == 0 && params.sack_freq == 0)
2771d364d927SWei Yongjun 			return 0;
2772d364d927SWei Yongjun 	} else if (optlen == sizeof(struct sctp_assoc_value)) {
277394f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
2774f916ec96SNeil Horman 				    "%s (pid %d) "
277594f65193SNeil Horman 				    "Use of struct sctp_assoc_value in delayed_ack socket option.\n"
2776f916ec96SNeil Horman 				    "Use struct sctp_sack_info instead\n",
2777f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
2778d364d927SWei Yongjun 		if (copy_from_user(&params, optval, optlen))
2779d364d927SWei Yongjun 			return -EFAULT;
2780d364d927SWei Yongjun 
2781d364d927SWei Yongjun 		if (params.sack_delay == 0)
2782d364d927SWei Yongjun 			params.sack_freq = 1;
2783d364d927SWei Yongjun 		else
2784d364d927SWei Yongjun 			params.sack_freq = 0;
2785d364d927SWei Yongjun 	} else
27867708610bSFrank Filz 		return -EINVAL;
27877708610bSFrank Filz 
2788d364d927SWei Yongjun 	/* Validate value parameter. */
2789d364d927SWei Yongjun 	if (params.sack_delay > 500)
2790d364d927SWei Yongjun 		return -EINVAL;
2791d364d927SWei Yongjun 
27929c5829e1SXin Long 	/* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the
27939c5829e1SXin Long 	 * socket is a one to many style socket, and an association
27949c5829e1SXin Long 	 * was not found, then the id was invalid.
27957708610bSFrank Filz 	 */
2796d364d927SWei Yongjun 	asoc = sctp_id2assoc(sk, params.sack_assoc_id);
27979c5829e1SXin Long 	if (!asoc && params.sack_assoc_id > SCTP_ALL_ASSOC &&
27989c5829e1SXin Long 	    sctp_style(sk, UDP))
27997708610bSFrank Filz 		return -EINVAL;
28007708610bSFrank Filz 
28017708610bSFrank Filz 	if (asoc) {
28029c5829e1SXin Long 		sctp_apply_asoc_delayed_ack(&params, asoc);
28039c5829e1SXin Long 
28049c5829e1SXin Long 		return 0;
28059c5829e1SXin Long 	}
28069c5829e1SXin Long 
28078e2614fcSXin Long 	if (sctp_style(sk, TCP))
28088e2614fcSXin Long 		params.sack_assoc_id = SCTP_FUTURE_ASSOC;
28098e2614fcSXin Long 
28109c5829e1SXin Long 	if (params.sack_assoc_id == SCTP_FUTURE_ASSOC ||
28119c5829e1SXin Long 	    params.sack_assoc_id == SCTP_ALL_ASSOC) {
28129c5829e1SXin Long 		if (params.sack_delay) {
2813d364d927SWei Yongjun 			sp->sackdelay = params.sack_delay;
28147708610bSFrank Filz 			sp->param_flags =
28150ea5e4dfSwangweidong 				sctp_spp_sackdelay_enable(sp->param_flags);
28167708610bSFrank Filz 		}
2817d364d927SWei Yongjun 		if (params.sack_freq == 1) {
28187708610bSFrank Filz 			sp->param_flags =
28190ea5e4dfSwangweidong 				sctp_spp_sackdelay_disable(sp->param_flags);
2820d364d927SWei Yongjun 		} else if (params.sack_freq > 1) {
2821d364d927SWei Yongjun 			sp->sackfreq = params.sack_freq;
2822d364d927SWei Yongjun 			sp->param_flags =
28230ea5e4dfSwangweidong 				sctp_spp_sackdelay_enable(sp->param_flags);
2824d364d927SWei Yongjun 		}
28257708610bSFrank Filz 	}
28267708610bSFrank Filz 
28279c5829e1SXin Long 	if (params.sack_assoc_id == SCTP_CURRENT_ASSOC ||
28289c5829e1SXin Long 	    params.sack_assoc_id == SCTP_ALL_ASSOC)
28299c5829e1SXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs)
28309c5829e1SXin Long 			sctp_apply_asoc_delayed_ack(&params, asoc);
28317708610bSFrank Filz 
28327708610bSFrank Filz 	return 0;
28337708610bSFrank Filz }
28347708610bSFrank Filz 
28351da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG)
28361da177e4SLinus Torvalds  *
28371da177e4SLinus Torvalds  * Applications can specify protocol parameters for the default association
28381da177e4SLinus Torvalds  * initialization.  The option name argument to setsockopt() and getsockopt()
28391da177e4SLinus Torvalds  * is SCTP_INITMSG.
28401da177e4SLinus Torvalds  *
28411da177e4SLinus Torvalds  * Setting initialization parameters is effective only on an unconnected
28421da177e4SLinus Torvalds  * socket (for UDP-style sockets only future associations are effected
28431da177e4SLinus Torvalds  * by the change).  With TCP-style sockets, this option is inherited by
28441da177e4SLinus Torvalds  * sockets derived from a listener socket.
28451da177e4SLinus Torvalds  */
2846b7058842SDavid S. Miller static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen)
28471da177e4SLinus Torvalds {
28481da177e4SLinus Torvalds 	struct sctp_initmsg sinit;
28491da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
28501da177e4SLinus Torvalds 
28511da177e4SLinus Torvalds 	if (optlen != sizeof(struct sctp_initmsg))
28521da177e4SLinus Torvalds 		return -EINVAL;
28531da177e4SLinus Torvalds 	if (copy_from_user(&sinit, optval, optlen))
28541da177e4SLinus Torvalds 		return -EFAULT;
28551da177e4SLinus Torvalds 
28561da177e4SLinus Torvalds 	if (sinit.sinit_num_ostreams)
28571da177e4SLinus Torvalds 		sp->initmsg.sinit_num_ostreams = sinit.sinit_num_ostreams;
28581da177e4SLinus Torvalds 	if (sinit.sinit_max_instreams)
28591da177e4SLinus Torvalds 		sp->initmsg.sinit_max_instreams = sinit.sinit_max_instreams;
28601da177e4SLinus Torvalds 	if (sinit.sinit_max_attempts)
28611da177e4SLinus Torvalds 		sp->initmsg.sinit_max_attempts = sinit.sinit_max_attempts;
28621da177e4SLinus Torvalds 	if (sinit.sinit_max_init_timeo)
28631da177e4SLinus Torvalds 		sp->initmsg.sinit_max_init_timeo = sinit.sinit_max_init_timeo;
28641da177e4SLinus Torvalds 
28651da177e4SLinus Torvalds 	return 0;
28661da177e4SLinus Torvalds }
28671da177e4SLinus Torvalds 
28681da177e4SLinus Torvalds /*
28691da177e4SLinus Torvalds  * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM)
28701da177e4SLinus Torvalds  *
28711da177e4SLinus Torvalds  *   Applications that wish to use the sendto() system call may wish to
28721da177e4SLinus Torvalds  *   specify a default set of parameters that would normally be supplied
28731da177e4SLinus Torvalds  *   through the inclusion of ancillary data.  This socket option allows
28741da177e4SLinus Torvalds  *   such an application to set the default sctp_sndrcvinfo structure.
28751da177e4SLinus Torvalds  *   The application that wishes to use this socket option simply passes
28761da177e4SLinus Torvalds  *   in to this call the sctp_sndrcvinfo structure defined in Section
28771da177e4SLinus Torvalds  *   5.2.2) The input parameters accepted by this call include
28781da177e4SLinus Torvalds  *   sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
28791da177e4SLinus Torvalds  *   sinfo_timetolive.  The user must provide the sinfo_assoc_id field in
28801da177e4SLinus Torvalds  *   to this call if the caller is using the UDP model.
28811da177e4SLinus Torvalds  */
28821da177e4SLinus Torvalds static int sctp_setsockopt_default_send_param(struct sock *sk,
2883b7058842SDavid S. Miller 					      char __user *optval,
2884b7058842SDavid S. Miller 					      unsigned int optlen)
28851da177e4SLinus Torvalds {
28861da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
28876b3fd5f3SGeir Ola Vaagland 	struct sctp_association *asoc;
28886b3fd5f3SGeir Ola Vaagland 	struct sctp_sndrcvinfo info;
28891da177e4SLinus Torvalds 
28906b3fd5f3SGeir Ola Vaagland 	if (optlen != sizeof(info))
28911da177e4SLinus Torvalds 		return -EINVAL;
28921da177e4SLinus Torvalds 	if (copy_from_user(&info, optval, optlen))
28931da177e4SLinus Torvalds 		return -EFAULT;
28946b3fd5f3SGeir Ola Vaagland 	if (info.sinfo_flags &
28956b3fd5f3SGeir Ola Vaagland 	    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
28966b3fd5f3SGeir Ola Vaagland 	      SCTP_ABORT | SCTP_EOF))
28976b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
28981da177e4SLinus Torvalds 
28991da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
2900707e45b3SXin Long 	if (!asoc && info.sinfo_assoc_id > SCTP_ALL_ASSOC &&
2901707e45b3SXin Long 	    sctp_style(sk, UDP))
29021da177e4SLinus Torvalds 		return -EINVAL;
2903707e45b3SXin Long 
29041da177e4SLinus Torvalds 	if (asoc) {
29051da177e4SLinus Torvalds 		asoc->default_stream = info.sinfo_stream;
29061da177e4SLinus Torvalds 		asoc->default_flags = info.sinfo_flags;
29071da177e4SLinus Torvalds 		asoc->default_ppid = info.sinfo_ppid;
29081da177e4SLinus Torvalds 		asoc->default_context = info.sinfo_context;
29091da177e4SLinus Torvalds 		asoc->default_timetolive = info.sinfo_timetolive;
2910707e45b3SXin Long 
2911707e45b3SXin Long 		return 0;
2912707e45b3SXin Long 	}
2913707e45b3SXin Long 
29141354e72fSMarcelo Ricardo Leitner 	if (sctp_style(sk, TCP))
29151354e72fSMarcelo Ricardo Leitner 		info.sinfo_assoc_id = SCTP_FUTURE_ASSOC;
29161354e72fSMarcelo Ricardo Leitner 
2917707e45b3SXin Long 	if (info.sinfo_assoc_id == SCTP_FUTURE_ASSOC ||
2918707e45b3SXin Long 	    info.sinfo_assoc_id == SCTP_ALL_ASSOC) {
29191da177e4SLinus Torvalds 		sp->default_stream = info.sinfo_stream;
29201da177e4SLinus Torvalds 		sp->default_flags = info.sinfo_flags;
29211da177e4SLinus Torvalds 		sp->default_ppid = info.sinfo_ppid;
29221da177e4SLinus Torvalds 		sp->default_context = info.sinfo_context;
29231da177e4SLinus Torvalds 		sp->default_timetolive = info.sinfo_timetolive;
29241da177e4SLinus Torvalds 	}
29251da177e4SLinus Torvalds 
2926707e45b3SXin Long 	if (info.sinfo_assoc_id == SCTP_CURRENT_ASSOC ||
2927707e45b3SXin Long 	    info.sinfo_assoc_id == SCTP_ALL_ASSOC) {
2928707e45b3SXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
2929707e45b3SXin Long 			asoc->default_stream = info.sinfo_stream;
2930707e45b3SXin Long 			asoc->default_flags = info.sinfo_flags;
2931707e45b3SXin Long 			asoc->default_ppid = info.sinfo_ppid;
2932707e45b3SXin Long 			asoc->default_context = info.sinfo_context;
2933707e45b3SXin Long 			asoc->default_timetolive = info.sinfo_timetolive;
2934707e45b3SXin Long 		}
2935707e45b3SXin Long 	}
2936707e45b3SXin Long 
29371da177e4SLinus Torvalds 	return 0;
29381da177e4SLinus Torvalds }
29391da177e4SLinus Torvalds 
29406b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters
29416b3fd5f3SGeir Ola Vaagland  * (SCTP_DEFAULT_SNDINFO)
29426b3fd5f3SGeir Ola Vaagland  */
29436b3fd5f3SGeir Ola Vaagland static int sctp_setsockopt_default_sndinfo(struct sock *sk,
29446b3fd5f3SGeir Ola Vaagland 					   char __user *optval,
29456b3fd5f3SGeir Ola Vaagland 					   unsigned int optlen)
29466b3fd5f3SGeir Ola Vaagland {
29476b3fd5f3SGeir Ola Vaagland 	struct sctp_sock *sp = sctp_sk(sk);
29486b3fd5f3SGeir Ola Vaagland 	struct sctp_association *asoc;
29496b3fd5f3SGeir Ola Vaagland 	struct sctp_sndinfo info;
29506b3fd5f3SGeir Ola Vaagland 
29516b3fd5f3SGeir Ola Vaagland 	if (optlen != sizeof(info))
29526b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
29536b3fd5f3SGeir Ola Vaagland 	if (copy_from_user(&info, optval, optlen))
29546b3fd5f3SGeir Ola Vaagland 		return -EFAULT;
29556b3fd5f3SGeir Ola Vaagland 	if (info.snd_flags &
29566b3fd5f3SGeir Ola Vaagland 	    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
29576b3fd5f3SGeir Ola Vaagland 	      SCTP_ABORT | SCTP_EOF))
29586b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
29596b3fd5f3SGeir Ola Vaagland 
29606b3fd5f3SGeir Ola Vaagland 	asoc = sctp_id2assoc(sk, info.snd_assoc_id);
296192fc3bd9SXin Long 	if (!asoc && info.snd_assoc_id > SCTP_ALL_ASSOC &&
296292fc3bd9SXin Long 	    sctp_style(sk, UDP))
29636b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
296492fc3bd9SXin Long 
29656b3fd5f3SGeir Ola Vaagland 	if (asoc) {
29666b3fd5f3SGeir Ola Vaagland 		asoc->default_stream = info.snd_sid;
29676b3fd5f3SGeir Ola Vaagland 		asoc->default_flags = info.snd_flags;
29686b3fd5f3SGeir Ola Vaagland 		asoc->default_ppid = info.snd_ppid;
29696b3fd5f3SGeir Ola Vaagland 		asoc->default_context = info.snd_context;
297092fc3bd9SXin Long 
297192fc3bd9SXin Long 		return 0;
297292fc3bd9SXin Long 	}
297392fc3bd9SXin Long 
2974a842e65bSXin Long 	if (sctp_style(sk, TCP))
2975a842e65bSXin Long 		info.snd_assoc_id = SCTP_FUTURE_ASSOC;
2976a842e65bSXin Long 
297792fc3bd9SXin Long 	if (info.snd_assoc_id == SCTP_FUTURE_ASSOC ||
297892fc3bd9SXin Long 	    info.snd_assoc_id == SCTP_ALL_ASSOC) {
29796b3fd5f3SGeir Ola Vaagland 		sp->default_stream = info.snd_sid;
29806b3fd5f3SGeir Ola Vaagland 		sp->default_flags = info.snd_flags;
29816b3fd5f3SGeir Ola Vaagland 		sp->default_ppid = info.snd_ppid;
29826b3fd5f3SGeir Ola Vaagland 		sp->default_context = info.snd_context;
29836b3fd5f3SGeir Ola Vaagland 	}
29846b3fd5f3SGeir Ola Vaagland 
298592fc3bd9SXin Long 	if (info.snd_assoc_id == SCTP_CURRENT_ASSOC ||
298692fc3bd9SXin Long 	    info.snd_assoc_id == SCTP_ALL_ASSOC) {
298792fc3bd9SXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
298892fc3bd9SXin Long 			asoc->default_stream = info.snd_sid;
298992fc3bd9SXin Long 			asoc->default_flags = info.snd_flags;
299092fc3bd9SXin Long 			asoc->default_ppid = info.snd_ppid;
299192fc3bd9SXin Long 			asoc->default_context = info.snd_context;
299292fc3bd9SXin Long 		}
299392fc3bd9SXin Long 	}
299492fc3bd9SXin Long 
29956b3fd5f3SGeir Ola Vaagland 	return 0;
29966b3fd5f3SGeir Ola Vaagland }
29976b3fd5f3SGeir Ola Vaagland 
29981da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
29991da177e4SLinus Torvalds  *
30001da177e4SLinus Torvalds  * Requests that the local SCTP stack use the enclosed peer address as
30011da177e4SLinus Torvalds  * the association primary.  The enclosed address must be one of the
30021da177e4SLinus Torvalds  * association peer's addresses.
30031da177e4SLinus Torvalds  */
30041da177e4SLinus Torvalds static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
3005b7058842SDavid S. Miller 					unsigned int optlen)
30061da177e4SLinus Torvalds {
30071da177e4SLinus Torvalds 	struct sctp_prim prim;
30081da177e4SLinus Torvalds 	struct sctp_transport *trans;
30092277c7cdSRichard Haines 	struct sctp_af *af;
30102277c7cdSRichard Haines 	int err;
30111da177e4SLinus Torvalds 
30121da177e4SLinus Torvalds 	if (optlen != sizeof(struct sctp_prim))
30131da177e4SLinus Torvalds 		return -EINVAL;
30141da177e4SLinus Torvalds 
30151da177e4SLinus Torvalds 	if (copy_from_user(&prim, optval, sizeof(struct sctp_prim)))
30161da177e4SLinus Torvalds 		return -EFAULT;
30171da177e4SLinus Torvalds 
30182277c7cdSRichard Haines 	/* Allow security module to validate address but need address len. */
30192277c7cdSRichard Haines 	af = sctp_get_af_specific(prim.ssp_addr.ss_family);
30202277c7cdSRichard Haines 	if (!af)
30212277c7cdSRichard Haines 		return -EINVAL;
30222277c7cdSRichard Haines 
30232277c7cdSRichard Haines 	err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR,
30242277c7cdSRichard Haines 					 (struct sockaddr *)&prim.ssp_addr,
30252277c7cdSRichard Haines 					 af->sockaddr_len);
30262277c7cdSRichard Haines 	if (err)
30272277c7cdSRichard Haines 		return err;
30282277c7cdSRichard Haines 
30291da177e4SLinus Torvalds 	trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id);
30301da177e4SLinus Torvalds 	if (!trans)
30311da177e4SLinus Torvalds 		return -EINVAL;
30321da177e4SLinus Torvalds 
30331da177e4SLinus Torvalds 	sctp_assoc_set_primary(trans->asoc, trans);
30341da177e4SLinus Torvalds 
30351da177e4SLinus Torvalds 	return 0;
30361da177e4SLinus Torvalds }
30371da177e4SLinus Torvalds 
30381da177e4SLinus Torvalds /*
30391da177e4SLinus Torvalds  * 7.1.5 SCTP_NODELAY
30401da177e4SLinus Torvalds  *
30411da177e4SLinus Torvalds  * Turn on/off any Nagle-like algorithm.  This means that packets are
30421da177e4SLinus Torvalds  * generally sent as soon as possible and no unnecessary delays are
30431da177e4SLinus Torvalds  * introduced, at the cost of more packets in the network.  Expects an
30441da177e4SLinus Torvalds  *  integer boolean flag.
30451da177e4SLinus Torvalds  */
30461da177e4SLinus Torvalds static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
3047b7058842SDavid S. Miller 				   unsigned int optlen)
30481da177e4SLinus Torvalds {
30491da177e4SLinus Torvalds 	int val;
30501da177e4SLinus Torvalds 
30511da177e4SLinus Torvalds 	if (optlen < sizeof(int))
30521da177e4SLinus Torvalds 		return -EINVAL;
30531da177e4SLinus Torvalds 	if (get_user(val, (int __user *)optval))
30541da177e4SLinus Torvalds 		return -EFAULT;
30551da177e4SLinus Torvalds 
30561da177e4SLinus Torvalds 	sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1;
30571da177e4SLinus Torvalds 	return 0;
30581da177e4SLinus Torvalds }
30591da177e4SLinus Torvalds 
30601da177e4SLinus Torvalds /*
30611da177e4SLinus Torvalds  *
30621da177e4SLinus Torvalds  * 7.1.1 SCTP_RTOINFO
30631da177e4SLinus Torvalds  *
30641da177e4SLinus Torvalds  * The protocol parameters used to initialize and bound retransmission
30651da177e4SLinus Torvalds  * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access
30661da177e4SLinus Torvalds  * and modify these parameters.
30671da177e4SLinus Torvalds  * All parameters are time values, in milliseconds.  A value of 0, when
30681da177e4SLinus Torvalds  * modifying the parameters, indicates that the current value should not
30691da177e4SLinus Torvalds  * be changed.
30701da177e4SLinus Torvalds  *
30711da177e4SLinus Torvalds  */
3072b7058842SDavid S. Miller static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen)
3073b7058842SDavid S. Miller {
30741da177e4SLinus Torvalds 	struct sctp_rtoinfo rtoinfo;
30751da177e4SLinus Torvalds 	struct sctp_association *asoc;
307685f935d4Swangweidong 	unsigned long rto_min, rto_max;
307785f935d4Swangweidong 	struct sctp_sock *sp = sctp_sk(sk);
30781da177e4SLinus Torvalds 
30791da177e4SLinus Torvalds 	if (optlen != sizeof (struct sctp_rtoinfo))
30801da177e4SLinus Torvalds 		return -EINVAL;
30811da177e4SLinus Torvalds 
30821da177e4SLinus Torvalds 	if (copy_from_user(&rtoinfo, optval, optlen))
30831da177e4SLinus Torvalds 		return -EFAULT;
30841da177e4SLinus Torvalds 
30851da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id);
30861da177e4SLinus Torvalds 
30871da177e4SLinus Torvalds 	/* Set the values to the specific association */
30887adb5ed5SXin Long 	if (!asoc && rtoinfo.srto_assoc_id != SCTP_FUTURE_ASSOC &&
30897adb5ed5SXin Long 	    sctp_style(sk, UDP))
30901da177e4SLinus Torvalds 		return -EINVAL;
30911da177e4SLinus Torvalds 
309285f935d4Swangweidong 	rto_max = rtoinfo.srto_max;
309385f935d4Swangweidong 	rto_min = rtoinfo.srto_min;
309485f935d4Swangweidong 
309585f935d4Swangweidong 	if (rto_max)
309685f935d4Swangweidong 		rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max;
309785f935d4Swangweidong 	else
309885f935d4Swangweidong 		rto_max = asoc ? asoc->rto_max : sp->rtoinfo.srto_max;
309985f935d4Swangweidong 
310085f935d4Swangweidong 	if (rto_min)
310185f935d4Swangweidong 		rto_min = asoc ? msecs_to_jiffies(rto_min) : rto_min;
310285f935d4Swangweidong 	else
310385f935d4Swangweidong 		rto_min = asoc ? asoc->rto_min : sp->rtoinfo.srto_min;
310485f935d4Swangweidong 
310585f935d4Swangweidong 	if (rto_min > rto_max)
310685f935d4Swangweidong 		return -EINVAL;
310785f935d4Swangweidong 
31081da177e4SLinus Torvalds 	if (asoc) {
31091da177e4SLinus Torvalds 		if (rtoinfo.srto_initial != 0)
31101da177e4SLinus Torvalds 			asoc->rto_initial =
31111da177e4SLinus Torvalds 				msecs_to_jiffies(rtoinfo.srto_initial);
311285f935d4Swangweidong 		asoc->rto_max = rto_max;
311385f935d4Swangweidong 		asoc->rto_min = rto_min;
31141da177e4SLinus Torvalds 	} else {
31151da177e4SLinus Torvalds 		/* If there is no association or the association-id = 0
31161da177e4SLinus Torvalds 		 * set the values to the endpoint.
31171da177e4SLinus Torvalds 		 */
31181da177e4SLinus Torvalds 		if (rtoinfo.srto_initial != 0)
31191da177e4SLinus Torvalds 			sp->rtoinfo.srto_initial = rtoinfo.srto_initial;
312085f935d4Swangweidong 		sp->rtoinfo.srto_max = rto_max;
312185f935d4Swangweidong 		sp->rtoinfo.srto_min = rto_min;
31221da177e4SLinus Torvalds 	}
31231da177e4SLinus Torvalds 
31241da177e4SLinus Torvalds 	return 0;
31251da177e4SLinus Torvalds }
31261da177e4SLinus Torvalds 
31271da177e4SLinus Torvalds /*
31281da177e4SLinus Torvalds  *
31291da177e4SLinus Torvalds  * 7.1.2 SCTP_ASSOCINFO
31301da177e4SLinus Torvalds  *
313159c51591SMichael Opdenacker  * This option is used to tune the maximum retransmission attempts
31321da177e4SLinus Torvalds  * of the association.
31331da177e4SLinus Torvalds  * Returns an error if the new association retransmission value is
31341da177e4SLinus Torvalds  * greater than the sum of the retransmission value  of the peer.
31351da177e4SLinus Torvalds  * See [SCTP] for more information.
31361da177e4SLinus Torvalds  *
31371da177e4SLinus Torvalds  */
3138b7058842SDavid S. Miller static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen)
31391da177e4SLinus Torvalds {
31401da177e4SLinus Torvalds 
31411da177e4SLinus Torvalds 	struct sctp_assocparams assocparams;
31421da177e4SLinus Torvalds 	struct sctp_association *asoc;
31431da177e4SLinus Torvalds 
31441da177e4SLinus Torvalds 	if (optlen != sizeof(struct sctp_assocparams))
31451da177e4SLinus Torvalds 		return -EINVAL;
31461da177e4SLinus Torvalds 	if (copy_from_user(&assocparams, optval, optlen))
31471da177e4SLinus Torvalds 		return -EFAULT;
31481da177e4SLinus Torvalds 
31491da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id);
31501da177e4SLinus Torvalds 
31518889394dSXin Long 	if (!asoc && assocparams.sasoc_assoc_id != SCTP_FUTURE_ASSOC &&
31528889394dSXin Long 	    sctp_style(sk, UDP))
31531da177e4SLinus Torvalds 		return -EINVAL;
31541da177e4SLinus Torvalds 
31551da177e4SLinus Torvalds 	/* Set the values to the specific association */
31561da177e4SLinus Torvalds 	if (asoc) {
3157402d68c4SVlad Yasevich 		if (assocparams.sasoc_asocmaxrxt != 0) {
3158402d68c4SVlad Yasevich 			__u32 path_sum = 0;
3159402d68c4SVlad Yasevich 			int   paths = 0;
3160402d68c4SVlad Yasevich 			struct sctp_transport *peer_addr;
3161402d68c4SVlad Yasevich 
31629dbc15f0SRobert P. J. Day 			list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list,
31639dbc15f0SRobert P. J. Day 					transports) {
3164402d68c4SVlad Yasevich 				path_sum += peer_addr->pathmaxrxt;
3165402d68c4SVlad Yasevich 				paths++;
3166402d68c4SVlad Yasevich 			}
3167402d68c4SVlad Yasevich 
3168025dfdafSFrederik Schwarzer 			/* Only validate asocmaxrxt if we have more than
3169402d68c4SVlad Yasevich 			 * one path/transport.  We do this because path
3170402d68c4SVlad Yasevich 			 * retransmissions are only counted when we have more
3171402d68c4SVlad Yasevich 			 * then one path.
3172402d68c4SVlad Yasevich 			 */
3173402d68c4SVlad Yasevich 			if (paths > 1 &&
3174402d68c4SVlad Yasevich 			    assocparams.sasoc_asocmaxrxt > path_sum)
3175402d68c4SVlad Yasevich 				return -EINVAL;
3176402d68c4SVlad Yasevich 
31771da177e4SLinus Torvalds 			asoc->max_retrans = assocparams.sasoc_asocmaxrxt;
3178402d68c4SVlad Yasevich 		}
3179402d68c4SVlad Yasevich 
318052db882fSDaniel Borkmann 		if (assocparams.sasoc_cookie_life != 0)
318152db882fSDaniel Borkmann 			asoc->cookie_life = ms_to_ktime(assocparams.sasoc_cookie_life);
31821da177e4SLinus Torvalds 	} else {
31831da177e4SLinus Torvalds 		/* Set the values to the endpoint */
31841da177e4SLinus Torvalds 		struct sctp_sock *sp = sctp_sk(sk);
31851da177e4SLinus Torvalds 
31861da177e4SLinus Torvalds 		if (assocparams.sasoc_asocmaxrxt != 0)
31871da177e4SLinus Torvalds 			sp->assocparams.sasoc_asocmaxrxt =
31881da177e4SLinus Torvalds 						assocparams.sasoc_asocmaxrxt;
31891da177e4SLinus Torvalds 		if (assocparams.sasoc_cookie_life != 0)
31901da177e4SLinus Torvalds 			sp->assocparams.sasoc_cookie_life =
31911da177e4SLinus Torvalds 						assocparams.sasoc_cookie_life;
31921da177e4SLinus Torvalds 	}
31931da177e4SLinus Torvalds 	return 0;
31941da177e4SLinus Torvalds }
31951da177e4SLinus Torvalds 
31961da177e4SLinus Torvalds /*
31971da177e4SLinus Torvalds  * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
31981da177e4SLinus Torvalds  *
31991da177e4SLinus Torvalds  * This socket option is a boolean flag which turns on or off mapped V4
32001da177e4SLinus Torvalds  * addresses.  If this option is turned on and the socket is type
32011da177e4SLinus Torvalds  * PF_INET6, then IPv4 addresses will be mapped to V6 representation.
32021da177e4SLinus Torvalds  * If this option is turned off, then no mapping will be done of V4
32031da177e4SLinus Torvalds  * addresses and a user will receive both PF_INET6 and PF_INET type
32041da177e4SLinus Torvalds  * addresses on the socket.
32051da177e4SLinus Torvalds  */
3206b7058842SDavid S. Miller static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen)
32071da177e4SLinus Torvalds {
32081da177e4SLinus Torvalds 	int val;
32091da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
32101da177e4SLinus Torvalds 
32111da177e4SLinus Torvalds 	if (optlen < sizeof(int))
32121da177e4SLinus Torvalds 		return -EINVAL;
32131da177e4SLinus Torvalds 	if (get_user(val, (int __user *)optval))
32141da177e4SLinus Torvalds 		return -EFAULT;
32151da177e4SLinus Torvalds 	if (val)
32161da177e4SLinus Torvalds 		sp->v4mapped = 1;
32171da177e4SLinus Torvalds 	else
32181da177e4SLinus Torvalds 		sp->v4mapped = 0;
32191da177e4SLinus Torvalds 
32201da177e4SLinus Torvalds 	return 0;
32211da177e4SLinus Torvalds }
32221da177e4SLinus Torvalds 
32231da177e4SLinus Torvalds /*
3224e89c2095SWei Yongjun  * 8.1.16.  Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
3225e89c2095SWei Yongjun  * This option will get or set the maximum size to put in any outgoing
3226e89c2095SWei Yongjun  * SCTP DATA chunk.  If a message is larger than this size it will be
32271da177e4SLinus Torvalds  * fragmented by SCTP into the specified size.  Note that the underlying
32281da177e4SLinus Torvalds  * SCTP implementation may fragment into smaller sized chunks when the
32291da177e4SLinus Torvalds  * PMTU of the underlying association is smaller than the value set by
3230e89c2095SWei Yongjun  * the user.  The default value for this option is '0' which indicates
3231e89c2095SWei Yongjun  * the user is NOT limiting fragmentation and only the PMTU will effect
3232e89c2095SWei Yongjun  * SCTP's choice of DATA chunk size.  Note also that values set larger
3233e89c2095SWei Yongjun  * than the maximum size of an IP datagram will effectively let SCTP
3234e89c2095SWei Yongjun  * control fragmentation (i.e. the same as setting this option to 0).
3235e89c2095SWei Yongjun  *
3236e89c2095SWei Yongjun  * The following structure is used to access and modify this parameter:
3237e89c2095SWei Yongjun  *
3238e89c2095SWei Yongjun  * struct sctp_assoc_value {
3239e89c2095SWei Yongjun  *   sctp_assoc_t assoc_id;
3240e89c2095SWei Yongjun  *   uint32_t assoc_value;
3241e89c2095SWei Yongjun  * };
3242e89c2095SWei Yongjun  *
3243e89c2095SWei Yongjun  * assoc_id:  This parameter is ignored for one-to-one style sockets.
3244e89c2095SWei Yongjun  *    For one-to-many style sockets this parameter indicates which
3245e89c2095SWei Yongjun  *    association the user is performing an action upon.  Note that if
3246e89c2095SWei Yongjun  *    this field's value is zero then the endpoints default value is
3247e89c2095SWei Yongjun  *    changed (effecting future associations only).
3248e89c2095SWei Yongjun  * assoc_value:  This parameter specifies the maximum size in bytes.
32491da177e4SLinus Torvalds  */
3250b7058842SDavid S. Miller static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
32511da177e4SLinus Torvalds {
3252ecca8f88SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
3253e89c2095SWei Yongjun 	struct sctp_assoc_value params;
32541da177e4SLinus Torvalds 	struct sctp_association *asoc;
32551da177e4SLinus Torvalds 	int val;
32561da177e4SLinus Torvalds 
3257e89c2095SWei Yongjun 	if (optlen == sizeof(int)) {
325894f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
3259f916ec96SNeil Horman 				    "%s (pid %d) "
326094f65193SNeil Horman 				    "Use of int in maxseg socket option.\n"
3261f916ec96SNeil Horman 				    "Use struct sctp_assoc_value instead\n",
3262f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
3263e89c2095SWei Yongjun 		if (copy_from_user(&val, optval, optlen))
32641da177e4SLinus Torvalds 			return -EFAULT;
32656fd769beSXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
3266e89c2095SWei Yongjun 	} else if (optlen == sizeof(struct sctp_assoc_value)) {
3267e89c2095SWei Yongjun 		if (copy_from_user(&params, optval, optlen))
3268e89c2095SWei Yongjun 			return -EFAULT;
3269e89c2095SWei Yongjun 		val = params.assoc_value;
3270ecca8f88SXin Long 	} else {
3271e89c2095SWei Yongjun 		return -EINVAL;
3272ecca8f88SXin Long 	}
3273e89c2095SWei Yongjun 
3274439ef030SMarcelo Ricardo Leitner 	asoc = sctp_id2assoc(sk, params.assoc_id);
32756fd769beSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
32766fd769beSXin Long 	    sctp_style(sk, UDP))
32776fd769beSXin Long 		return -EINVAL;
3278439ef030SMarcelo Ricardo Leitner 
3279ecca8f88SXin Long 	if (val) {
3280ecca8f88SXin Long 		int min_len, max_len;
3281439ef030SMarcelo Ricardo Leitner 		__u16 datasize = asoc ? sctp_datachk_len(&asoc->stream) :
3282ecca8f88SXin Long 				 sizeof(struct sctp_data_chunk);
3283ecca8f88SXin Long 
3284afd0a800SJakub Audykowicz 		min_len = sctp_min_frag_point(sp, datasize);
3285439ef030SMarcelo Ricardo Leitner 		max_len = SCTP_MAX_CHUNK_LEN - datasize;
3286ecca8f88SXin Long 
3287ecca8f88SXin Long 		if (val < min_len || val > max_len)
32881da177e4SLinus Torvalds 			return -EINVAL;
3289ecca8f88SXin Long 	}
3290e89c2095SWei Yongjun 
3291e89c2095SWei Yongjun 	if (asoc) {
3292f68b2e05SVlad Yasevich 		asoc->user_frag = val;
32932f5e3c9dSMarcelo Ricardo Leitner 		sctp_assoc_update_frag_point(asoc);
3294e89c2095SWei Yongjun 	} else {
32951da177e4SLinus Torvalds 		sp->user_frag = val;
3296e89c2095SWei Yongjun 	}
32971da177e4SLinus Torvalds 
32981da177e4SLinus Torvalds 	return 0;
32991da177e4SLinus Torvalds }
33001da177e4SLinus Torvalds 
33011da177e4SLinus Torvalds 
33021da177e4SLinus Torvalds /*
33031da177e4SLinus Torvalds  *  7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR)
33041da177e4SLinus Torvalds  *
33051da177e4SLinus Torvalds  *   Requests that the peer mark the enclosed address as the association
33061da177e4SLinus Torvalds  *   primary. The enclosed address must be one of the association's
33071da177e4SLinus Torvalds  *   locally bound addresses. The following structure is used to make a
33081da177e4SLinus Torvalds  *   set primary request:
33091da177e4SLinus Torvalds  */
33101da177e4SLinus Torvalds static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval,
3311b7058842SDavid S. Miller 					     unsigned int optlen)
33121da177e4SLinus Torvalds {
33131da177e4SLinus Torvalds 	struct sctp_sock	*sp;
33141da177e4SLinus Torvalds 	struct sctp_association	*asoc = NULL;
33151da177e4SLinus Torvalds 	struct sctp_setpeerprim	prim;
33161da177e4SLinus Torvalds 	struct sctp_chunk	*chunk;
331740a01039SWei Yongjun 	struct sctp_af		*af;
33181da177e4SLinus Torvalds 	int 			err;
33191da177e4SLinus Torvalds 
33201da177e4SLinus Torvalds 	sp = sctp_sk(sk);
33211da177e4SLinus Torvalds 
33224e27428fSXin Long 	if (!sp->ep->asconf_enable)
33231da177e4SLinus Torvalds 		return -EPERM;
33241da177e4SLinus Torvalds 
33251da177e4SLinus Torvalds 	if (optlen != sizeof(struct sctp_setpeerprim))
33261da177e4SLinus Torvalds 		return -EINVAL;
33271da177e4SLinus Torvalds 
33281da177e4SLinus Torvalds 	if (copy_from_user(&prim, optval, optlen))
33291da177e4SLinus Torvalds 		return -EFAULT;
33301da177e4SLinus Torvalds 
33311da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, prim.sspp_assoc_id);
33321da177e4SLinus Torvalds 	if (!asoc)
33331da177e4SLinus Torvalds 		return -EINVAL;
33341da177e4SLinus Torvalds 
33351da177e4SLinus Torvalds 	if (!asoc->peer.asconf_capable)
33361da177e4SLinus Torvalds 		return -EPERM;
33371da177e4SLinus Torvalds 
33381da177e4SLinus Torvalds 	if (asoc->peer.addip_disabled_mask & SCTP_PARAM_SET_PRIMARY)
33391da177e4SLinus Torvalds 		return -EPERM;
33401da177e4SLinus Torvalds 
33411da177e4SLinus Torvalds 	if (!sctp_state(asoc, ESTABLISHED))
33421da177e4SLinus Torvalds 		return -ENOTCONN;
33431da177e4SLinus Torvalds 
334440a01039SWei Yongjun 	af = sctp_get_af_specific(prim.sspp_addr.ss_family);
334540a01039SWei Yongjun 	if (!af)
334640a01039SWei Yongjun 		return -EINVAL;
334740a01039SWei Yongjun 
334840a01039SWei Yongjun 	if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL))
334940a01039SWei Yongjun 		return -EADDRNOTAVAIL;
335040a01039SWei Yongjun 
33511da177e4SLinus Torvalds 	if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))
33521da177e4SLinus Torvalds 		return -EADDRNOTAVAIL;
33531da177e4SLinus Torvalds 
33542277c7cdSRichard Haines 	/* Allow security module to validate address. */
33552277c7cdSRichard Haines 	err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR,
33562277c7cdSRichard Haines 					 (struct sockaddr *)&prim.sspp_addr,
33572277c7cdSRichard Haines 					 af->sockaddr_len);
33582277c7cdSRichard Haines 	if (err)
33592277c7cdSRichard Haines 		return err;
33602277c7cdSRichard Haines 
33611da177e4SLinus Torvalds 	/* Create an ASCONF chunk with SET_PRIMARY parameter	*/
33621da177e4SLinus Torvalds 	chunk = sctp_make_asconf_set_prim(asoc,
33631da177e4SLinus Torvalds 					  (union sctp_addr *)&prim.sspp_addr);
33641da177e4SLinus Torvalds 	if (!chunk)
33651da177e4SLinus Torvalds 		return -ENOMEM;
33661da177e4SLinus Torvalds 
33671da177e4SLinus Torvalds 	err = sctp_send_asconf(asoc, chunk);
33681da177e4SLinus Torvalds 
3369bb33381dSDaniel Borkmann 	pr_debug("%s: we set peer primary addr primitively\n", __func__);
33701da177e4SLinus Torvalds 
33711da177e4SLinus Torvalds 	return err;
33721da177e4SLinus Torvalds }
33731da177e4SLinus Torvalds 
33740f3fffd8SIvan Skytte Jorgensen static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval,
3375b7058842SDavid S. Miller 					    unsigned int optlen)
33761da177e4SLinus Torvalds {
33770f3fffd8SIvan Skytte Jorgensen 	struct sctp_setadaptation adaptation;
33781da177e4SLinus Torvalds 
33790f3fffd8SIvan Skytte Jorgensen 	if (optlen != sizeof(struct sctp_setadaptation))
33801da177e4SLinus Torvalds 		return -EINVAL;
33810f3fffd8SIvan Skytte Jorgensen 	if (copy_from_user(&adaptation, optval, optlen))
33821da177e4SLinus Torvalds 		return -EFAULT;
33831da177e4SLinus Torvalds 
33840f3fffd8SIvan Skytte Jorgensen 	sctp_sk(sk)->adaptation_ind = adaptation.ssb_adaptation_ind;
33851da177e4SLinus Torvalds 
33861da177e4SLinus Torvalds 	return 0;
33871da177e4SLinus Torvalds }
33881da177e4SLinus Torvalds 
33896ab792f5SIvan Skytte Jorgensen /*
33906ab792f5SIvan Skytte Jorgensen  * 7.1.29.  Set or Get the default context (SCTP_CONTEXT)
33916ab792f5SIvan Skytte Jorgensen  *
33926ab792f5SIvan Skytte Jorgensen  * The context field in the sctp_sndrcvinfo structure is normally only
33936ab792f5SIvan Skytte Jorgensen  * used when a failed message is retrieved holding the value that was
33946ab792f5SIvan Skytte Jorgensen  * sent down on the actual send call.  This option allows the setting of
33956ab792f5SIvan Skytte Jorgensen  * a default context on an association basis that will be received on
33966ab792f5SIvan Skytte Jorgensen  * reading messages from the peer.  This is especially helpful in the
33976ab792f5SIvan Skytte Jorgensen  * one-2-many model for an application to keep some reference to an
33986ab792f5SIvan Skytte Jorgensen  * internal state machine that is processing messages on the
33996ab792f5SIvan Skytte Jorgensen  * association.  Note that the setting of this value only effects
34006ab792f5SIvan Skytte Jorgensen  * received messages from the peer and does not effect the value that is
34016ab792f5SIvan Skytte Jorgensen  * saved with outbound messages.
34026ab792f5SIvan Skytte Jorgensen  */
34036ab792f5SIvan Skytte Jorgensen static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
3404b7058842SDavid S. Miller 				   unsigned int optlen)
34056ab792f5SIvan Skytte Jorgensen {
340649b037acSXin Long 	struct sctp_sock *sp = sctp_sk(sk);
34076ab792f5SIvan Skytte Jorgensen 	struct sctp_assoc_value params;
34086ab792f5SIvan Skytte Jorgensen 	struct sctp_association *asoc;
34096ab792f5SIvan Skytte Jorgensen 
34106ab792f5SIvan Skytte Jorgensen 	if (optlen != sizeof(struct sctp_assoc_value))
34116ab792f5SIvan Skytte Jorgensen 		return -EINVAL;
34126ab792f5SIvan Skytte Jorgensen 	if (copy_from_user(&params, optval, optlen))
34136ab792f5SIvan Skytte Jorgensen 		return -EFAULT;
34146ab792f5SIvan Skytte Jorgensen 
34156ab792f5SIvan Skytte Jorgensen 	asoc = sctp_id2assoc(sk, params.assoc_id);
341649b037acSXin Long 	if (!asoc && params.assoc_id > SCTP_ALL_ASSOC &&
341749b037acSXin Long 	    sctp_style(sk, UDP))
34186ab792f5SIvan Skytte Jorgensen 		return -EINVAL;
341949b037acSXin Long 
342049b037acSXin Long 	if (asoc) {
34216ab792f5SIvan Skytte Jorgensen 		asoc->default_rcv_context = params.assoc_value;
342249b037acSXin Long 
342349b037acSXin Long 		return 0;
34246ab792f5SIvan Skytte Jorgensen 	}
34256ab792f5SIvan Skytte Jorgensen 
3426cface2cbSXin Long 	if (sctp_style(sk, TCP))
3427cface2cbSXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
3428cface2cbSXin Long 
342949b037acSXin Long 	if (params.assoc_id == SCTP_FUTURE_ASSOC ||
343049b037acSXin Long 	    params.assoc_id == SCTP_ALL_ASSOC)
343149b037acSXin Long 		sp->default_rcv_context = params.assoc_value;
343249b037acSXin Long 
343349b037acSXin Long 	if (params.assoc_id == SCTP_CURRENT_ASSOC ||
343449b037acSXin Long 	    params.assoc_id == SCTP_ALL_ASSOC)
343549b037acSXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs)
343649b037acSXin Long 			asoc->default_rcv_context = params.assoc_value;
343749b037acSXin Long 
34386ab792f5SIvan Skytte Jorgensen 	return 0;
34396ab792f5SIvan Skytte Jorgensen }
34406ab792f5SIvan Skytte Jorgensen 
3441b6e1331fSVlad Yasevich /*
3442b6e1331fSVlad Yasevich  * 7.1.24.  Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE)
3443b6e1331fSVlad Yasevich  *
3444b6e1331fSVlad Yasevich  * This options will at a minimum specify if the implementation is doing
3445b6e1331fSVlad Yasevich  * fragmented interleave.  Fragmented interleave, for a one to many
3446b6e1331fSVlad Yasevich  * socket, is when subsequent calls to receive a message may return
3447b6e1331fSVlad Yasevich  * parts of messages from different associations.  Some implementations
3448b6e1331fSVlad Yasevich  * may allow you to turn this value on or off.  If so, when turned off,
3449b6e1331fSVlad Yasevich  * no fragment interleave will occur (which will cause a head of line
3450b6e1331fSVlad Yasevich  * blocking amongst multiple associations sharing the same one to many
3451b6e1331fSVlad Yasevich  * socket).  When this option is turned on, then each receive call may
3452b6e1331fSVlad Yasevich  * come from a different association (thus the user must receive data
3453b6e1331fSVlad Yasevich  * with the extended calls (e.g. sctp_recvmsg) to keep track of which
3454b6e1331fSVlad Yasevich  * association each receive belongs to.
3455b6e1331fSVlad Yasevich  *
3456b6e1331fSVlad Yasevich  * This option takes a boolean value.  A non-zero value indicates that
3457b6e1331fSVlad Yasevich  * fragmented interleave is on.  A value of zero indicates that
3458b6e1331fSVlad Yasevich  * fragmented interleave is off.
3459b6e1331fSVlad Yasevich  *
3460b6e1331fSVlad Yasevich  * Note that it is important that an implementation that allows this
3461b6e1331fSVlad Yasevich  * option to be turned on, have it off by default.  Otherwise an unaware
3462b6e1331fSVlad Yasevich  * application using the one to many model may become confused and act
3463b6e1331fSVlad Yasevich  * incorrectly.
3464b6e1331fSVlad Yasevich  */
3465b6e1331fSVlad Yasevich static int sctp_setsockopt_fragment_interleave(struct sock *sk,
3466b6e1331fSVlad Yasevich 					       char __user *optval,
3467b7058842SDavid S. Miller 					       unsigned int optlen)
3468b6e1331fSVlad Yasevich {
3469b6e1331fSVlad Yasevich 	int val;
3470b6e1331fSVlad Yasevich 
3471b6e1331fSVlad Yasevich 	if (optlen != sizeof(int))
3472b6e1331fSVlad Yasevich 		return -EINVAL;
3473b6e1331fSVlad Yasevich 	if (get_user(val, (int __user *)optval))
3474b6e1331fSVlad Yasevich 		return -EFAULT;
3475b6e1331fSVlad Yasevich 
3476772a5869SXin Long 	sctp_sk(sk)->frag_interleave = !!val;
3477772a5869SXin Long 
3478772a5869SXin Long 	if (!sctp_sk(sk)->frag_interleave)
3479e55f4b8bSXin Long 		sctp_sk(sk)->ep->intl_enable = 0;
3480b6e1331fSVlad Yasevich 
3481b6e1331fSVlad Yasevich 	return 0;
3482b6e1331fSVlad Yasevich }
3483b6e1331fSVlad Yasevich 
3484d49d91d7SVlad Yasevich /*
34858510b937SWei Yongjun  * 8.1.21.  Set or Get the SCTP Partial Delivery Point
3486d49d91d7SVlad Yasevich  *       (SCTP_PARTIAL_DELIVERY_POINT)
34878510b937SWei Yongjun  *
3488d49d91d7SVlad Yasevich  * This option will set or get the SCTP partial delivery point.  This
3489d49d91d7SVlad Yasevich  * point is the size of a message where the partial delivery API will be
3490d49d91d7SVlad Yasevich  * invoked to help free up rwnd space for the peer.  Setting this to a
34918510b937SWei Yongjun  * lower value will cause partial deliveries to happen more often.  The
3492d49d91d7SVlad Yasevich  * calls argument is an integer that sets or gets the partial delivery
34938510b937SWei Yongjun  * point.  Note also that the call will fail if the user attempts to set
34948510b937SWei Yongjun  * this value larger than the socket receive buffer size.
34958510b937SWei Yongjun  *
34968510b937SWei Yongjun  * Note that any single message having a length smaller than or equal to
34978510b937SWei Yongjun  * the SCTP partial delivery point will be delivered in one single read
34988510b937SWei Yongjun  * call as long as the user provided buffer is large enough to hold the
34998510b937SWei Yongjun  * message.
3500d49d91d7SVlad Yasevich  */
3501d49d91d7SVlad Yasevich static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
3502d49d91d7SVlad Yasevich 						  char __user *optval,
3503b7058842SDavid S. Miller 						  unsigned int optlen)
3504d49d91d7SVlad Yasevich {
3505d49d91d7SVlad Yasevich 	u32 val;
3506d49d91d7SVlad Yasevich 
3507d49d91d7SVlad Yasevich 	if (optlen != sizeof(u32))
3508d49d91d7SVlad Yasevich 		return -EINVAL;
3509d49d91d7SVlad Yasevich 	if (get_user(val, (int __user *)optval))
3510d49d91d7SVlad Yasevich 		return -EFAULT;
3511d49d91d7SVlad Yasevich 
35128510b937SWei Yongjun 	/* Note: We double the receive buffer from what the user sets
35138510b937SWei Yongjun 	 * it to be, also initial rwnd is based on rcvbuf/2.
35148510b937SWei Yongjun 	 */
35158510b937SWei Yongjun 	if (val > (sk->sk_rcvbuf >> 1))
35168510b937SWei Yongjun 		return -EINVAL;
35178510b937SWei Yongjun 
3518d49d91d7SVlad Yasevich 	sctp_sk(sk)->pd_point = val;
3519d49d91d7SVlad Yasevich 
3520d49d91d7SVlad Yasevich 	return 0; /* is this the right error code? */
3521d49d91d7SVlad Yasevich }
3522d49d91d7SVlad Yasevich 
352370331571SVlad Yasevich /*
352470331571SVlad Yasevich  * 7.1.28.  Set or Get the maximum burst (SCTP_MAX_BURST)
352570331571SVlad Yasevich  *
352670331571SVlad Yasevich  * This option will allow a user to change the maximum burst of packets
352770331571SVlad Yasevich  * that can be emitted by this association.  Note that the default value
352870331571SVlad Yasevich  * is 4, and some implementations may restrict this setting so that it
352970331571SVlad Yasevich  * can only be lowered.
353070331571SVlad Yasevich  *
353170331571SVlad Yasevich  * NOTE: This text doesn't seem right.  Do this on a socket basis with
353270331571SVlad Yasevich  * future associations inheriting the socket value.
353370331571SVlad Yasevich  */
353470331571SVlad Yasevich static int sctp_setsockopt_maxburst(struct sock *sk,
353570331571SVlad Yasevich 				    char __user *optval,
3536b7058842SDavid S. Miller 				    unsigned int optlen)
353770331571SVlad Yasevich {
3538e0651a0dSXin Long 	struct sctp_sock *sp = sctp_sk(sk);
3539219b99a9SNeil Horman 	struct sctp_assoc_value params;
3540219b99a9SNeil Horman 	struct sctp_association *asoc;
354170331571SVlad Yasevich 
3542219b99a9SNeil Horman 	if (optlen == sizeof(int)) {
354394f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
3544f916ec96SNeil Horman 				    "%s (pid %d) "
354594f65193SNeil Horman 				    "Use of int in max_burst socket option deprecated.\n"
3546f916ec96SNeil Horman 				    "Use struct sctp_assoc_value instead\n",
3547f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
3548e0651a0dSXin Long 		if (copy_from_user(&params.assoc_value, optval, optlen))
354970331571SVlad Yasevich 			return -EFAULT;
3550e0651a0dSXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
3551219b99a9SNeil Horman 	} else if (optlen == sizeof(struct sctp_assoc_value)) {
3552219b99a9SNeil Horman 		if (copy_from_user(&params, optval, optlen))
3553219b99a9SNeil Horman 			return -EFAULT;
3554219b99a9SNeil Horman 	} else
355570331571SVlad Yasevich 		return -EINVAL;
355670331571SVlad Yasevich 
3557e0651a0dSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
3558e0651a0dSXin Long 	if (!asoc && params.assoc_id > SCTP_ALL_ASSOC &&
3559e0651a0dSXin Long 	    sctp_style(sk, UDP))
3560219b99a9SNeil Horman 		return -EINVAL;
3561e0651a0dSXin Long 
3562e0651a0dSXin Long 	if (asoc) {
3563e0651a0dSXin Long 		asoc->max_burst = params.assoc_value;
3564e0651a0dSXin Long 
3565e0651a0dSXin Long 		return 0;
3566e0651a0dSXin Long 	}
3567e0651a0dSXin Long 
3568746bc215SXin Long 	if (sctp_style(sk, TCP))
3569746bc215SXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
3570746bc215SXin Long 
3571e0651a0dSXin Long 	if (params.assoc_id == SCTP_FUTURE_ASSOC ||
3572e0651a0dSXin Long 	    params.assoc_id == SCTP_ALL_ASSOC)
3573e0651a0dSXin Long 		sp->max_burst = params.assoc_value;
3574e0651a0dSXin Long 
3575e0651a0dSXin Long 	if (params.assoc_id == SCTP_CURRENT_ASSOC ||
3576e0651a0dSXin Long 	    params.assoc_id == SCTP_ALL_ASSOC)
3577e0651a0dSXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs)
3578e0651a0dSXin Long 			asoc->max_burst = params.assoc_value;
357970331571SVlad Yasevich 
358070331571SVlad Yasevich 	return 0;
358170331571SVlad Yasevich }
358270331571SVlad Yasevich 
358365b07e5dSVlad Yasevich /*
358465b07e5dSVlad Yasevich  * 7.1.18.  Add a chunk that must be authenticated (SCTP_AUTH_CHUNK)
358565b07e5dSVlad Yasevich  *
358665b07e5dSVlad Yasevich  * This set option adds a chunk type that the user is requesting to be
358765b07e5dSVlad Yasevich  * received only in an authenticated way.  Changes to the list of chunks
358865b07e5dSVlad Yasevich  * will only effect future associations on the socket.
358965b07e5dSVlad Yasevich  */
359065b07e5dSVlad Yasevich static int sctp_setsockopt_auth_chunk(struct sock *sk,
359165b07e5dSVlad Yasevich 				      char __user *optval,
3592b7058842SDavid S. Miller 				      unsigned int optlen)
359365b07e5dSVlad Yasevich {
3594b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
359565b07e5dSVlad Yasevich 	struct sctp_authchunk val;
359665b07e5dSVlad Yasevich 
3597b14878ccSVlad Yasevich 	if (!ep->auth_enable)
35985e739d17SVlad Yasevich 		return -EACCES;
35995e739d17SVlad Yasevich 
360065b07e5dSVlad Yasevich 	if (optlen != sizeof(struct sctp_authchunk))
360165b07e5dSVlad Yasevich 		return -EINVAL;
360265b07e5dSVlad Yasevich 	if (copy_from_user(&val, optval, optlen))
360365b07e5dSVlad Yasevich 		return -EFAULT;
360465b07e5dSVlad Yasevich 
360565b07e5dSVlad Yasevich 	switch (val.sauth_chunk) {
360665b07e5dSVlad Yasevich 	case SCTP_CID_INIT:
360765b07e5dSVlad Yasevich 	case SCTP_CID_INIT_ACK:
360865b07e5dSVlad Yasevich 	case SCTP_CID_SHUTDOWN_COMPLETE:
360965b07e5dSVlad Yasevich 	case SCTP_CID_AUTH:
361065b07e5dSVlad Yasevich 		return -EINVAL;
361165b07e5dSVlad Yasevich 	}
361265b07e5dSVlad Yasevich 
361365b07e5dSVlad Yasevich 	/* add this chunk id to the endpoint */
3614b14878ccSVlad Yasevich 	return sctp_auth_ep_add_chunkid(ep, val.sauth_chunk);
361565b07e5dSVlad Yasevich }
361665b07e5dSVlad Yasevich 
361765b07e5dSVlad Yasevich /*
361865b07e5dSVlad Yasevich  * 7.1.19.  Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT)
361965b07e5dSVlad Yasevich  *
362065b07e5dSVlad Yasevich  * This option gets or sets the list of HMAC algorithms that the local
362165b07e5dSVlad Yasevich  * endpoint requires the peer to use.
362265b07e5dSVlad Yasevich  */
362365b07e5dSVlad Yasevich static int sctp_setsockopt_hmac_ident(struct sock *sk,
362465b07e5dSVlad Yasevich 				      char __user *optval,
3625b7058842SDavid S. Miller 				      unsigned int optlen)
362665b07e5dSVlad Yasevich {
3627b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
362865b07e5dSVlad Yasevich 	struct sctp_hmacalgo *hmacs;
3629d9724055SVlad Yasevich 	u32 idents;
363065b07e5dSVlad Yasevich 	int err;
363165b07e5dSVlad Yasevich 
3632b14878ccSVlad Yasevich 	if (!ep->auth_enable)
36335e739d17SVlad Yasevich 		return -EACCES;
36345e739d17SVlad Yasevich 
363565b07e5dSVlad Yasevich 	if (optlen < sizeof(struct sctp_hmacalgo))
363665b07e5dSVlad Yasevich 		return -EINVAL;
36375960cefaSMarcelo Ricardo Leitner 	optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) +
36385960cefaSMarcelo Ricardo Leitner 					     SCTP_AUTH_NUM_HMACS * sizeof(u16));
363965b07e5dSVlad Yasevich 
3640934253a7SShan Wei 	hmacs = memdup_user(optval, optlen);
3641934253a7SShan Wei 	if (IS_ERR(hmacs))
3642934253a7SShan Wei 		return PTR_ERR(hmacs);
364365b07e5dSVlad Yasevich 
3644d9724055SVlad Yasevich 	idents = hmacs->shmac_num_idents;
3645d9724055SVlad Yasevich 	if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS ||
3646d9724055SVlad Yasevich 	    (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) {
364765b07e5dSVlad Yasevich 		err = -EINVAL;
364865b07e5dSVlad Yasevich 		goto out;
364965b07e5dSVlad Yasevich 	}
365065b07e5dSVlad Yasevich 
3651b14878ccSVlad Yasevich 	err = sctp_auth_ep_set_hmacs(ep, hmacs);
365265b07e5dSVlad Yasevich out:
365365b07e5dSVlad Yasevich 	kfree(hmacs);
365465b07e5dSVlad Yasevich 	return err;
365565b07e5dSVlad Yasevich }
365665b07e5dSVlad Yasevich 
365765b07e5dSVlad Yasevich /*
365865b07e5dSVlad Yasevich  * 7.1.20.  Set a shared key (SCTP_AUTH_KEY)
365965b07e5dSVlad Yasevich  *
366065b07e5dSVlad Yasevich  * This option will set a shared secret key which is used to build an
366165b07e5dSVlad Yasevich  * association shared key.
366265b07e5dSVlad Yasevich  */
366365b07e5dSVlad Yasevich static int sctp_setsockopt_auth_key(struct sock *sk,
366465b07e5dSVlad Yasevich 				    char __user *optval,
3665b7058842SDavid S. Miller 				    unsigned int optlen)
366665b07e5dSVlad Yasevich {
3667b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
366865b07e5dSVlad Yasevich 	struct sctp_authkey *authkey;
366965b07e5dSVlad Yasevich 	struct sctp_association *asoc;
36707fb3be13SXin Long 	int ret = -EINVAL;
367165b07e5dSVlad Yasevich 
367265b07e5dSVlad Yasevich 	if (optlen <= sizeof(struct sctp_authkey))
367365b07e5dSVlad Yasevich 		return -EINVAL;
36745960cefaSMarcelo Ricardo Leitner 	/* authkey->sca_keylength is u16, so optlen can't be bigger than
36755960cefaSMarcelo Ricardo Leitner 	 * this.
36765960cefaSMarcelo Ricardo Leitner 	 */
36777fb3be13SXin Long 	optlen = min_t(unsigned int, optlen, USHRT_MAX + sizeof(*authkey));
367865b07e5dSVlad Yasevich 
3679934253a7SShan Wei 	authkey = memdup_user(optval, optlen);
3680934253a7SShan Wei 	if (IS_ERR(authkey))
3681934253a7SShan Wei 		return PTR_ERR(authkey);
368265b07e5dSVlad Yasevich 
36837fb3be13SXin Long 	if (authkey->sca_keylength > optlen - sizeof(*authkey))
368430c2235cSVlad Yasevich 		goto out;
368530c2235cSVlad Yasevich 
368665b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, authkey->sca_assoc_id);
36877fb3be13SXin Long 	if (!asoc && authkey->sca_assoc_id > SCTP_ALL_ASSOC &&
36887fb3be13SXin Long 	    sctp_style(sk, UDP))
36897fb3be13SXin Long 		goto out;
36907fb3be13SXin Long 
36917fb3be13SXin Long 	if (asoc) {
36927fb3be13SXin Long 		ret = sctp_auth_set_key(ep, asoc, authkey);
369365b07e5dSVlad Yasevich 		goto out;
369465b07e5dSVlad Yasevich 	}
369565b07e5dSVlad Yasevich 
36960685d6b7SXin Long 	if (sctp_style(sk, TCP))
36970685d6b7SXin Long 		authkey->sca_assoc_id = SCTP_FUTURE_ASSOC;
36980685d6b7SXin Long 
36997fb3be13SXin Long 	if (authkey->sca_assoc_id == SCTP_FUTURE_ASSOC ||
37007fb3be13SXin Long 	    authkey->sca_assoc_id == SCTP_ALL_ASSOC) {
3701b14878ccSVlad Yasevich 		ret = sctp_auth_set_key(ep, asoc, authkey);
37027fb3be13SXin Long 		if (ret)
37037fb3be13SXin Long 			goto out;
37047fb3be13SXin Long 	}
37057fb3be13SXin Long 
37067fb3be13SXin Long 	ret = 0;
37077fb3be13SXin Long 
37087fb3be13SXin Long 	if (authkey->sca_assoc_id == SCTP_CURRENT_ASSOC ||
37097fb3be13SXin Long 	    authkey->sca_assoc_id == SCTP_ALL_ASSOC) {
37107fb3be13SXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs) {
37117fb3be13SXin Long 			int res = sctp_auth_set_key(ep, asoc, authkey);
37127fb3be13SXin Long 
37137fb3be13SXin Long 			if (res && !ret)
37147fb3be13SXin Long 				ret = res;
37157fb3be13SXin Long 		}
37167fb3be13SXin Long 	}
37177fb3be13SXin Long 
371865b07e5dSVlad Yasevich out:
37196ba542a2SDaniel Borkmann 	kzfree(authkey);
372065b07e5dSVlad Yasevich 	return ret;
372165b07e5dSVlad Yasevich }
372265b07e5dSVlad Yasevich 
372365b07e5dSVlad Yasevich /*
372465b07e5dSVlad Yasevich  * 7.1.21.  Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY)
372565b07e5dSVlad Yasevich  *
372665b07e5dSVlad Yasevich  * This option will get or set the active shared key to be used to build
372765b07e5dSVlad Yasevich  * the association shared key.
372865b07e5dSVlad Yasevich  */
372965b07e5dSVlad Yasevich static int sctp_setsockopt_active_key(struct sock *sk,
373065b07e5dSVlad Yasevich 				      char __user *optval,
3731b7058842SDavid S. Miller 				      unsigned int optlen)
373265b07e5dSVlad Yasevich {
3733b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
373465b07e5dSVlad Yasevich 	struct sctp_association *asoc;
3735bf9fb6adSXin Long 	struct sctp_authkeyid val;
3736bf9fb6adSXin Long 	int ret = 0;
373765b07e5dSVlad Yasevich 
373865b07e5dSVlad Yasevich 	if (optlen != sizeof(struct sctp_authkeyid))
373965b07e5dSVlad Yasevich 		return -EINVAL;
374065b07e5dSVlad Yasevich 	if (copy_from_user(&val, optval, optlen))
374165b07e5dSVlad Yasevich 		return -EFAULT;
374265b07e5dSVlad Yasevich 
374365b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, val.scact_assoc_id);
3744bf9fb6adSXin Long 	if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC &&
3745bf9fb6adSXin Long 	    sctp_style(sk, UDP))
374665b07e5dSVlad Yasevich 		return -EINVAL;
374765b07e5dSVlad Yasevich 
3748bf9fb6adSXin Long 	if (asoc)
3749b14878ccSVlad Yasevich 		return sctp_auth_set_active_key(ep, asoc, val.scact_keynumber);
3750bf9fb6adSXin Long 
375106b39e85SXin Long 	if (sctp_style(sk, TCP))
375206b39e85SXin Long 		val.scact_assoc_id = SCTP_FUTURE_ASSOC;
375306b39e85SXin Long 
3754bf9fb6adSXin Long 	if (val.scact_assoc_id == SCTP_FUTURE_ASSOC ||
3755bf9fb6adSXin Long 	    val.scact_assoc_id == SCTP_ALL_ASSOC) {
3756bf9fb6adSXin Long 		ret = sctp_auth_set_active_key(ep, asoc, val.scact_keynumber);
3757bf9fb6adSXin Long 		if (ret)
3758bf9fb6adSXin Long 			return ret;
3759bf9fb6adSXin Long 	}
3760bf9fb6adSXin Long 
3761bf9fb6adSXin Long 	if (val.scact_assoc_id == SCTP_CURRENT_ASSOC ||
3762bf9fb6adSXin Long 	    val.scact_assoc_id == SCTP_ALL_ASSOC) {
3763bf9fb6adSXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs) {
3764bf9fb6adSXin Long 			int res = sctp_auth_set_active_key(ep, asoc,
3765bf9fb6adSXin Long 							   val.scact_keynumber);
3766bf9fb6adSXin Long 
3767bf9fb6adSXin Long 			if (res && !ret)
3768bf9fb6adSXin Long 				ret = res;
3769bf9fb6adSXin Long 		}
3770bf9fb6adSXin Long 	}
3771bf9fb6adSXin Long 
3772bf9fb6adSXin Long 	return ret;
377365b07e5dSVlad Yasevich }
377465b07e5dSVlad Yasevich 
377565b07e5dSVlad Yasevich /*
377665b07e5dSVlad Yasevich  * 7.1.22.  Delete a shared key (SCTP_AUTH_DELETE_KEY)
377765b07e5dSVlad Yasevich  *
377865b07e5dSVlad Yasevich  * This set option will delete a shared secret key from use.
377965b07e5dSVlad Yasevich  */
378065b07e5dSVlad Yasevich static int sctp_setsockopt_del_key(struct sock *sk,
378165b07e5dSVlad Yasevich 				   char __user *optval,
3782b7058842SDavid S. Miller 				   unsigned int optlen)
378365b07e5dSVlad Yasevich {
3784b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
378565b07e5dSVlad Yasevich 	struct sctp_association *asoc;
37863adcc300SXin Long 	struct sctp_authkeyid val;
37873adcc300SXin Long 	int ret = 0;
378865b07e5dSVlad Yasevich 
378965b07e5dSVlad Yasevich 	if (optlen != sizeof(struct sctp_authkeyid))
379065b07e5dSVlad Yasevich 		return -EINVAL;
379165b07e5dSVlad Yasevich 	if (copy_from_user(&val, optval, optlen))
379265b07e5dSVlad Yasevich 		return -EFAULT;
379365b07e5dSVlad Yasevich 
379465b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, val.scact_assoc_id);
37953adcc300SXin Long 	if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC &&
37963adcc300SXin Long 	    sctp_style(sk, UDP))
379765b07e5dSVlad Yasevich 		return -EINVAL;
379865b07e5dSVlad Yasevich 
37993adcc300SXin Long 	if (asoc)
3800b14878ccSVlad Yasevich 		return sctp_auth_del_key_id(ep, asoc, val.scact_keynumber);
380165b07e5dSVlad Yasevich 
3802220675ebSXin Long 	if (sctp_style(sk, TCP))
3803220675ebSXin Long 		val.scact_assoc_id = SCTP_FUTURE_ASSOC;
3804220675ebSXin Long 
38053adcc300SXin Long 	if (val.scact_assoc_id == SCTP_FUTURE_ASSOC ||
38063adcc300SXin Long 	    val.scact_assoc_id == SCTP_ALL_ASSOC) {
38073adcc300SXin Long 		ret = sctp_auth_del_key_id(ep, asoc, val.scact_keynumber);
38083adcc300SXin Long 		if (ret)
38093adcc300SXin Long 			return ret;
38103adcc300SXin Long 	}
38113adcc300SXin Long 
38123adcc300SXin Long 	if (val.scact_assoc_id == SCTP_CURRENT_ASSOC ||
38133adcc300SXin Long 	    val.scact_assoc_id == SCTP_ALL_ASSOC) {
38143adcc300SXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs) {
38153adcc300SXin Long 			int res = sctp_auth_del_key_id(ep, asoc,
38163adcc300SXin Long 						       val.scact_keynumber);
38173adcc300SXin Long 
38183adcc300SXin Long 			if (res && !ret)
38193adcc300SXin Long 				ret = res;
38203adcc300SXin Long 		}
38213adcc300SXin Long 	}
38223adcc300SXin Long 
38233adcc300SXin Long 	return ret;
382465b07e5dSVlad Yasevich }
382565b07e5dSVlad Yasevich 
38267dc04d71SMichio Honda /*
3827601590ecSXin Long  * 8.3.4  Deactivate a Shared Key (SCTP_AUTH_DEACTIVATE_KEY)
3828601590ecSXin Long  *
3829601590ecSXin Long  * This set option will deactivate a shared secret key.
3830601590ecSXin Long  */
3831601590ecSXin Long static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval,
3832601590ecSXin Long 					  unsigned int optlen)
3833601590ecSXin Long {
3834601590ecSXin Long 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
3835601590ecSXin Long 	struct sctp_association *asoc;
38362af66ff3SXin Long 	struct sctp_authkeyid val;
38372af66ff3SXin Long 	int ret = 0;
3838601590ecSXin Long 
3839601590ecSXin Long 	if (optlen != sizeof(struct sctp_authkeyid))
3840601590ecSXin Long 		return -EINVAL;
3841601590ecSXin Long 	if (copy_from_user(&val, optval, optlen))
3842601590ecSXin Long 		return -EFAULT;
3843601590ecSXin Long 
3844601590ecSXin Long 	asoc = sctp_id2assoc(sk, val.scact_assoc_id);
38452af66ff3SXin Long 	if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC &&
38462af66ff3SXin Long 	    sctp_style(sk, UDP))
3847601590ecSXin Long 		return -EINVAL;
3848601590ecSXin Long 
38492af66ff3SXin Long 	if (asoc)
3850601590ecSXin Long 		return sctp_auth_deact_key_id(ep, asoc, val.scact_keynumber);
38512af66ff3SXin Long 
3852200f3a3bSXin Long 	if (sctp_style(sk, TCP))
3853200f3a3bSXin Long 		val.scact_assoc_id = SCTP_FUTURE_ASSOC;
3854200f3a3bSXin Long 
38552af66ff3SXin Long 	if (val.scact_assoc_id == SCTP_FUTURE_ASSOC ||
38562af66ff3SXin Long 	    val.scact_assoc_id == SCTP_ALL_ASSOC) {
38572af66ff3SXin Long 		ret = sctp_auth_deact_key_id(ep, asoc, val.scact_keynumber);
38582af66ff3SXin Long 		if (ret)
38592af66ff3SXin Long 			return ret;
38602af66ff3SXin Long 	}
38612af66ff3SXin Long 
38622af66ff3SXin Long 	if (val.scact_assoc_id == SCTP_CURRENT_ASSOC ||
38632af66ff3SXin Long 	    val.scact_assoc_id == SCTP_ALL_ASSOC) {
38642af66ff3SXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs) {
38652af66ff3SXin Long 			int res = sctp_auth_deact_key_id(ep, asoc,
38662af66ff3SXin Long 							 val.scact_keynumber);
38672af66ff3SXin Long 
38682af66ff3SXin Long 			if (res && !ret)
38692af66ff3SXin Long 				ret = res;
38702af66ff3SXin Long 		}
38712af66ff3SXin Long 	}
38722af66ff3SXin Long 
38732af66ff3SXin Long 	return ret;
3874601590ecSXin Long }
3875601590ecSXin Long 
3876601590ecSXin Long /*
38777dc04d71SMichio Honda  * 8.1.23 SCTP_AUTO_ASCONF
38787dc04d71SMichio Honda  *
38797dc04d71SMichio Honda  * This option will enable or disable the use of the automatic generation of
38807dc04d71SMichio Honda  * ASCONF chunks to add and delete addresses to an existing association.  Note
38817dc04d71SMichio Honda  * that this option has two caveats namely: a) it only affects sockets that
38827dc04d71SMichio Honda  * are bound to all addresses available to the SCTP stack, and b) the system
38837dc04d71SMichio Honda  * administrator may have an overriding control that turns the ASCONF feature
38847dc04d71SMichio Honda  * off no matter what setting the socket option may have.
38857dc04d71SMichio Honda  * This option expects an integer boolean flag, where a non-zero value turns on
38867dc04d71SMichio Honda  * the option, and a zero value turns off the option.
38877dc04d71SMichio Honda  * Note. In this implementation, socket operation overrides default parameter
38887dc04d71SMichio Honda  * being set by sysctl as well as FreeBSD implementation
38897dc04d71SMichio Honda  */
38907dc04d71SMichio Honda static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
38917dc04d71SMichio Honda 					unsigned int optlen)
38927dc04d71SMichio Honda {
38937dc04d71SMichio Honda 	int val;
38947dc04d71SMichio Honda 	struct sctp_sock *sp = sctp_sk(sk);
38957dc04d71SMichio Honda 
38967dc04d71SMichio Honda 	if (optlen < sizeof(int))
38977dc04d71SMichio Honda 		return -EINVAL;
38987dc04d71SMichio Honda 	if (get_user(val, (int __user *)optval))
38997dc04d71SMichio Honda 		return -EFAULT;
39007dc04d71SMichio Honda 	if (!sctp_is_ep_boundall(sk) && val)
39017dc04d71SMichio Honda 		return -EINVAL;
39027dc04d71SMichio Honda 	if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf))
39037dc04d71SMichio Honda 		return 0;
39047dc04d71SMichio Honda 
39052d45a02dSMarcelo Ricardo Leitner 	spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock);
39067dc04d71SMichio Honda 	if (val == 0 && sp->do_auto_asconf) {
39077dc04d71SMichio Honda 		list_del(&sp->auto_asconf_list);
39087dc04d71SMichio Honda 		sp->do_auto_asconf = 0;
39097dc04d71SMichio Honda 	} else if (val && !sp->do_auto_asconf) {
39107dc04d71SMichio Honda 		list_add_tail(&sp->auto_asconf_list,
39114db67e80SEric W. Biederman 		    &sock_net(sk)->sctp.auto_asconf_splist);
39127dc04d71SMichio Honda 		sp->do_auto_asconf = 1;
39137dc04d71SMichio Honda 	}
39142d45a02dSMarcelo Ricardo Leitner 	spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock);
39157dc04d71SMichio Honda 	return 0;
39167dc04d71SMichio Honda }
39177dc04d71SMichio Honda 
39185aa93bcfSNeil Horman /*
39195aa93bcfSNeil Horman  * SCTP_PEER_ADDR_THLDS
39205aa93bcfSNeil Horman  *
39215aa93bcfSNeil Horman  * This option allows us to alter the partially failed threshold for one or all
39225aa93bcfSNeil Horman  * transports in an association.  See Section 6.1 of:
39235aa93bcfSNeil Horman  * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt
39245aa93bcfSNeil Horman  */
39255aa93bcfSNeil Horman static int sctp_setsockopt_paddr_thresholds(struct sock *sk,
39265aa93bcfSNeil Horman 					    char __user *optval,
3927d467ac0aSXin Long 					    unsigned int optlen, bool v2)
39285aa93bcfSNeil Horman {
3929d467ac0aSXin Long 	struct sctp_paddrthlds_v2 val;
39305aa93bcfSNeil Horman 	struct sctp_transport *trans;
39315aa93bcfSNeil Horman 	struct sctp_association *asoc;
3932d467ac0aSXin Long 	int len;
39335aa93bcfSNeil Horman 
3934d467ac0aSXin Long 	len = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds);
3935d467ac0aSXin Long 	if (optlen < len)
39365aa93bcfSNeil Horman 		return -EINVAL;
3937d467ac0aSXin Long 	if (copy_from_user(&val, optval, len))
39385aa93bcfSNeil Horman 		return -EFAULT;
39395aa93bcfSNeil Horman 
3940d467ac0aSXin Long 	if (v2 && val.spt_pathpfthld > val.spt_pathcpthld)
3941d467ac0aSXin Long 		return -EINVAL;
3942d467ac0aSXin Long 
39438add543eSXin Long 	if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) {
39448add543eSXin Long 		trans = sctp_addr_id2transport(sk, &val.spt_address,
39458add543eSXin Long 					       val.spt_assoc_id);
39468add543eSXin Long 		if (!trans)
39475aa93bcfSNeil Horman 			return -ENOENT;
39488add543eSXin Long 
39498add543eSXin Long 		if (val.spt_pathmaxrxt)
39508add543eSXin Long 			trans->pathmaxrxt = val.spt_pathmaxrxt;
3951d467ac0aSXin Long 		if (v2)
3952d467ac0aSXin Long 			trans->ps_retrans = val.spt_pathcpthld;
39538add543eSXin Long 		trans->pf_retrans = val.spt_pathpfthld;
39548add543eSXin Long 
39558add543eSXin Long 		return 0;
39568add543eSXin Long 	}
39578add543eSXin Long 
39588add543eSXin Long 	asoc = sctp_id2assoc(sk, val.spt_assoc_id);
39598add543eSXin Long 	if (!asoc && val.spt_assoc_id != SCTP_FUTURE_ASSOC &&
39608add543eSXin Long 	    sctp_style(sk, UDP))
39618add543eSXin Long 		return -EINVAL;
39628add543eSXin Long 
39638add543eSXin Long 	if (asoc) {
39645aa93bcfSNeil Horman 		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
39655aa93bcfSNeil Horman 				    transports) {
39665aa93bcfSNeil Horman 			if (val.spt_pathmaxrxt)
39675aa93bcfSNeil Horman 				trans->pathmaxrxt = val.spt_pathmaxrxt;
3968d467ac0aSXin Long 			if (v2)
3969d467ac0aSXin Long 				trans->ps_retrans = val.spt_pathcpthld;
39705aa93bcfSNeil Horman 			trans->pf_retrans = val.spt_pathpfthld;
39715aa93bcfSNeil Horman 		}
39725aa93bcfSNeil Horman 
39735aa93bcfSNeil Horman 		if (val.spt_pathmaxrxt)
39745aa93bcfSNeil Horman 			asoc->pathmaxrxt = val.spt_pathmaxrxt;
3975d467ac0aSXin Long 		if (v2)
3976d467ac0aSXin Long 			asoc->ps_retrans = val.spt_pathcpthld;
39775aa93bcfSNeil Horman 		asoc->pf_retrans = val.spt_pathpfthld;
39785aa93bcfSNeil Horman 	} else {
39798add543eSXin Long 		struct sctp_sock *sp = sctp_sk(sk);
39805aa93bcfSNeil Horman 
39815aa93bcfSNeil Horman 		if (val.spt_pathmaxrxt)
39828add543eSXin Long 			sp->pathmaxrxt = val.spt_pathmaxrxt;
3983d467ac0aSXin Long 		if (v2)
3984d467ac0aSXin Long 			sp->ps_retrans = val.spt_pathcpthld;
39858add543eSXin Long 		sp->pf_retrans = val.spt_pathpfthld;
39865aa93bcfSNeil Horman 	}
39875aa93bcfSNeil Horman 
39885aa93bcfSNeil Horman 	return 0;
39895aa93bcfSNeil Horman }
39905aa93bcfSNeil Horman 
39910d3a421dSGeir Ola Vaagland static int sctp_setsockopt_recvrcvinfo(struct sock *sk,
39920d3a421dSGeir Ola Vaagland 				       char __user *optval,
39930d3a421dSGeir Ola Vaagland 				       unsigned int optlen)
39940d3a421dSGeir Ola Vaagland {
39950d3a421dSGeir Ola Vaagland 	int val;
39960d3a421dSGeir Ola Vaagland 
39970d3a421dSGeir Ola Vaagland 	if (optlen < sizeof(int))
39980d3a421dSGeir Ola Vaagland 		return -EINVAL;
39990d3a421dSGeir Ola Vaagland 	if (get_user(val, (int __user *) optval))
40000d3a421dSGeir Ola Vaagland 		return -EFAULT;
40010d3a421dSGeir Ola Vaagland 
40020d3a421dSGeir Ola Vaagland 	sctp_sk(sk)->recvrcvinfo = (val == 0) ? 0 : 1;
40030d3a421dSGeir Ola Vaagland 
40040d3a421dSGeir Ola Vaagland 	return 0;
40050d3a421dSGeir Ola Vaagland }
40060d3a421dSGeir Ola Vaagland 
40072347c80fSGeir Ola Vaagland static int sctp_setsockopt_recvnxtinfo(struct sock *sk,
40082347c80fSGeir Ola Vaagland 				       char __user *optval,
40092347c80fSGeir Ola Vaagland 				       unsigned int optlen)
40102347c80fSGeir Ola Vaagland {
40112347c80fSGeir Ola Vaagland 	int val;
40122347c80fSGeir Ola Vaagland 
40132347c80fSGeir Ola Vaagland 	if (optlen < sizeof(int))
40142347c80fSGeir Ola Vaagland 		return -EINVAL;
40152347c80fSGeir Ola Vaagland 	if (get_user(val, (int __user *) optval))
40162347c80fSGeir Ola Vaagland 		return -EFAULT;
40172347c80fSGeir Ola Vaagland 
40182347c80fSGeir Ola Vaagland 	sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1;
40192347c80fSGeir Ola Vaagland 
40202347c80fSGeir Ola Vaagland 	return 0;
40212347c80fSGeir Ola Vaagland }
40222347c80fSGeir Ola Vaagland 
402328aa4c26SXin Long static int sctp_setsockopt_pr_supported(struct sock *sk,
402428aa4c26SXin Long 					char __user *optval,
402528aa4c26SXin Long 					unsigned int optlen)
402628aa4c26SXin Long {
402728aa4c26SXin Long 	struct sctp_assoc_value params;
4028fb195605SXin Long 	struct sctp_association *asoc;
402928aa4c26SXin Long 
403028aa4c26SXin Long 	if (optlen != sizeof(params))
4031cc3ccf26SXin Long 		return -EINVAL;
403228aa4c26SXin Long 
4033cc3ccf26SXin Long 	if (copy_from_user(&params, optval, optlen))
4034cc3ccf26SXin Long 		return -EFAULT;
403528aa4c26SXin Long 
4036fb195605SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
4037fb195605SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
4038fb195605SXin Long 	    sctp_style(sk, UDP))
4039fb195605SXin Long 		return -EINVAL;
4040fb195605SXin Long 
4041cc3ccf26SXin Long 	sctp_sk(sk)->ep->prsctp_enable = !!params.assoc_value;
404228aa4c26SXin Long 
4043cc3ccf26SXin Long 	return 0;
404428aa4c26SXin Long }
404528aa4c26SXin Long 
4046f959fb44SXin Long static int sctp_setsockopt_default_prinfo(struct sock *sk,
4047f959fb44SXin Long 					  char __user *optval,
4048f959fb44SXin Long 					  unsigned int optlen)
4049f959fb44SXin Long {
40503a583059SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
4051f959fb44SXin Long 	struct sctp_default_prinfo info;
4052f959fb44SXin Long 	struct sctp_association *asoc;
4053f959fb44SXin Long 	int retval = -EINVAL;
4054f959fb44SXin Long 
4055f959fb44SXin Long 	if (optlen != sizeof(info))
4056f959fb44SXin Long 		goto out;
4057f959fb44SXin Long 
4058f959fb44SXin Long 	if (copy_from_user(&info, optval, sizeof(info))) {
4059f959fb44SXin Long 		retval = -EFAULT;
4060f959fb44SXin Long 		goto out;
4061f959fb44SXin Long 	}
4062f959fb44SXin Long 
4063f959fb44SXin Long 	if (info.pr_policy & ~SCTP_PR_SCTP_MASK)
4064f959fb44SXin Long 		goto out;
4065f959fb44SXin Long 
4066f959fb44SXin Long 	if (info.pr_policy == SCTP_PR_SCTP_NONE)
4067f959fb44SXin Long 		info.pr_value = 0;
4068f959fb44SXin Long 
4069f959fb44SXin Long 	asoc = sctp_id2assoc(sk, info.pr_assoc_id);
40703a583059SXin Long 	if (!asoc && info.pr_assoc_id > SCTP_ALL_ASSOC &&
40713a583059SXin Long 	    sctp_style(sk, UDP))
40723a583059SXin Long 		goto out;
40733a583059SXin Long 
40743a583059SXin Long 	retval = 0;
40753a583059SXin Long 
4076f959fb44SXin Long 	if (asoc) {
4077f959fb44SXin Long 		SCTP_PR_SET_POLICY(asoc->default_flags, info.pr_policy);
4078f959fb44SXin Long 		asoc->default_timetolive = info.pr_value;
4079f959fb44SXin Long 		goto out;
4080f959fb44SXin Long 	}
4081f959fb44SXin Long 
4082cbb45c6cSXin Long 	if (sctp_style(sk, TCP))
4083cbb45c6cSXin Long 		info.pr_assoc_id = SCTP_FUTURE_ASSOC;
4084cbb45c6cSXin Long 
40853a583059SXin Long 	if (info.pr_assoc_id == SCTP_FUTURE_ASSOC ||
40863a583059SXin Long 	    info.pr_assoc_id == SCTP_ALL_ASSOC) {
40873a583059SXin Long 		SCTP_PR_SET_POLICY(sp->default_flags, info.pr_policy);
40883a583059SXin Long 		sp->default_timetolive = info.pr_value;
40893a583059SXin Long 	}
40903a583059SXin Long 
40913a583059SXin Long 	if (info.pr_assoc_id == SCTP_CURRENT_ASSOC ||
40923a583059SXin Long 	    info.pr_assoc_id == SCTP_ALL_ASSOC) {
40933a583059SXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
40943a583059SXin Long 			SCTP_PR_SET_POLICY(asoc->default_flags, info.pr_policy);
40953a583059SXin Long 			asoc->default_timetolive = info.pr_value;
40963a583059SXin Long 		}
40973a583059SXin Long 	}
4098f959fb44SXin Long 
4099f959fb44SXin Long out:
4100f959fb44SXin Long 	return retval;
4101f959fb44SXin Long }
4102f959fb44SXin Long 
4103c0d8bab6SXin Long static int sctp_setsockopt_reconfig_supported(struct sock *sk,
4104c0d8bab6SXin Long 					      char __user *optval,
4105c0d8bab6SXin Long 					      unsigned int optlen)
4106c0d8bab6SXin Long {
4107c0d8bab6SXin Long 	struct sctp_assoc_value params;
4108c0d8bab6SXin Long 	struct sctp_association *asoc;
4109c0d8bab6SXin Long 	int retval = -EINVAL;
4110c0d8bab6SXin Long 
4111c0d8bab6SXin Long 	if (optlen != sizeof(params))
4112c0d8bab6SXin Long 		goto out;
4113c0d8bab6SXin Long 
4114c0d8bab6SXin Long 	if (copy_from_user(&params, optval, optlen)) {
4115c0d8bab6SXin Long 		retval = -EFAULT;
4116c0d8bab6SXin Long 		goto out;
4117c0d8bab6SXin Long 	}
4118c0d8bab6SXin Long 
4119c0d8bab6SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
4120acce7f3bSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
4121acce7f3bSXin Long 	    sctp_style(sk, UDP))
4122c0d8bab6SXin Long 		goto out;
4123acce7f3bSXin Long 
4124acce7f3bSXin Long 	sctp_sk(sk)->ep->reconf_enable = !!params.assoc_value;
4125c0d8bab6SXin Long 
4126c0d8bab6SXin Long 	retval = 0;
4127c0d8bab6SXin Long 
4128c0d8bab6SXin Long out:
4129c0d8bab6SXin Long 	return retval;
4130c0d8bab6SXin Long }
4131c0d8bab6SXin Long 
41329fb657aeSXin Long static int sctp_setsockopt_enable_strreset(struct sock *sk,
41339fb657aeSXin Long 					   char __user *optval,
41349fb657aeSXin Long 					   unsigned int optlen)
41359fb657aeSXin Long {
413699a62135SXin Long 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
41379fb657aeSXin Long 	struct sctp_assoc_value params;
41389fb657aeSXin Long 	struct sctp_association *asoc;
41399fb657aeSXin Long 	int retval = -EINVAL;
41409fb657aeSXin Long 
41419fb657aeSXin Long 	if (optlen != sizeof(params))
41429fb657aeSXin Long 		goto out;
41439fb657aeSXin Long 
41449fb657aeSXin Long 	if (copy_from_user(&params, optval, optlen)) {
41459fb657aeSXin Long 		retval = -EFAULT;
41469fb657aeSXin Long 		goto out;
41479fb657aeSXin Long 	}
41489fb657aeSXin Long 
41499fb657aeSXin Long 	if (params.assoc_value & (~SCTP_ENABLE_STRRESET_MASK))
41509fb657aeSXin Long 		goto out;
41519fb657aeSXin Long 
41529fb657aeSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
415399a62135SXin Long 	if (!asoc && params.assoc_id > SCTP_ALL_ASSOC &&
415499a62135SXin Long 	    sctp_style(sk, UDP))
415599a62135SXin Long 		goto out;
415699a62135SXin Long 
415799a62135SXin Long 	retval = 0;
415899a62135SXin Long 
41599fb657aeSXin Long 	if (asoc) {
41609fb657aeSXin Long 		asoc->strreset_enable = params.assoc_value;
41619fb657aeSXin Long 		goto out;
41629fb657aeSXin Long 	}
41639fb657aeSXin Long 
41649430ff99SXin Long 	if (sctp_style(sk, TCP))
41659430ff99SXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
41669430ff99SXin Long 
416799a62135SXin Long 	if (params.assoc_id == SCTP_FUTURE_ASSOC ||
416899a62135SXin Long 	    params.assoc_id == SCTP_ALL_ASSOC)
416999a62135SXin Long 		ep->strreset_enable = params.assoc_value;
417099a62135SXin Long 
417199a62135SXin Long 	if (params.assoc_id == SCTP_CURRENT_ASSOC ||
417299a62135SXin Long 	    params.assoc_id == SCTP_ALL_ASSOC)
417399a62135SXin Long 		list_for_each_entry(asoc, &ep->asocs, asocs)
417499a62135SXin Long 			asoc->strreset_enable = params.assoc_value;
41759fb657aeSXin Long 
41769fb657aeSXin Long out:
41779fb657aeSXin Long 	return retval;
41789fb657aeSXin Long }
41799fb657aeSXin Long 
41807f9d68acSXin Long static int sctp_setsockopt_reset_streams(struct sock *sk,
41817f9d68acSXin Long 					 char __user *optval,
41827f9d68acSXin Long 					 unsigned int optlen)
41837f9d68acSXin Long {
41847f9d68acSXin Long 	struct sctp_reset_streams *params;
41857f9d68acSXin Long 	struct sctp_association *asoc;
41867f9d68acSXin Long 	int retval = -EINVAL;
41877f9d68acSXin Long 
41882342b8d9SXin Long 	if (optlen < sizeof(*params))
41897f9d68acSXin Long 		return -EINVAL;
41905960cefaSMarcelo Ricardo Leitner 	/* srs_number_streams is u16, so optlen can't be bigger than this. */
41915960cefaSMarcelo Ricardo Leitner 	optlen = min_t(unsigned int, optlen, USHRT_MAX +
41925960cefaSMarcelo Ricardo Leitner 					     sizeof(__u16) * sizeof(*params));
41937f9d68acSXin Long 
41947f9d68acSXin Long 	params = memdup_user(optval, optlen);
41957f9d68acSXin Long 	if (IS_ERR(params))
41967f9d68acSXin Long 		return PTR_ERR(params);
41977f9d68acSXin Long 
41982342b8d9SXin Long 	if (params->srs_number_streams * sizeof(__u16) >
41992342b8d9SXin Long 	    optlen - sizeof(*params))
42002342b8d9SXin Long 		goto out;
42012342b8d9SXin Long 
42027f9d68acSXin Long 	asoc = sctp_id2assoc(sk, params->srs_assoc_id);
42037f9d68acSXin Long 	if (!asoc)
42047f9d68acSXin Long 		goto out;
42057f9d68acSXin Long 
42067f9d68acSXin Long 	retval = sctp_send_reset_streams(asoc, params);
42077f9d68acSXin Long 
42087f9d68acSXin Long out:
42097f9d68acSXin Long 	kfree(params);
42107f9d68acSXin Long 	return retval;
42117f9d68acSXin Long }
42127f9d68acSXin Long 
4213a92ce1a4SXin Long static int sctp_setsockopt_reset_assoc(struct sock *sk,
4214a92ce1a4SXin Long 				       char __user *optval,
4215a92ce1a4SXin Long 				       unsigned int optlen)
4216a92ce1a4SXin Long {
4217a92ce1a4SXin Long 	struct sctp_association *asoc;
4218a92ce1a4SXin Long 	sctp_assoc_t associd;
4219a92ce1a4SXin Long 	int retval = -EINVAL;
4220a92ce1a4SXin Long 
4221a92ce1a4SXin Long 	if (optlen != sizeof(associd))
4222a92ce1a4SXin Long 		goto out;
4223a92ce1a4SXin Long 
4224a92ce1a4SXin Long 	if (copy_from_user(&associd, optval, optlen)) {
4225a92ce1a4SXin Long 		retval = -EFAULT;
4226a92ce1a4SXin Long 		goto out;
4227a92ce1a4SXin Long 	}
4228a92ce1a4SXin Long 
4229a92ce1a4SXin Long 	asoc = sctp_id2assoc(sk, associd);
4230a92ce1a4SXin Long 	if (!asoc)
4231a92ce1a4SXin Long 		goto out;
4232a92ce1a4SXin Long 
4233a92ce1a4SXin Long 	retval = sctp_send_reset_assoc(asoc);
4234a92ce1a4SXin Long 
4235a92ce1a4SXin Long out:
4236a92ce1a4SXin Long 	return retval;
4237a92ce1a4SXin Long }
4238a92ce1a4SXin Long 
4239242bd2d5SXin Long static int sctp_setsockopt_add_streams(struct sock *sk,
4240242bd2d5SXin Long 				       char __user *optval,
4241242bd2d5SXin Long 				       unsigned int optlen)
4242242bd2d5SXin Long {
4243242bd2d5SXin Long 	struct sctp_association *asoc;
4244242bd2d5SXin Long 	struct sctp_add_streams params;
4245242bd2d5SXin Long 	int retval = -EINVAL;
4246242bd2d5SXin Long 
4247242bd2d5SXin Long 	if (optlen != sizeof(params))
4248242bd2d5SXin Long 		goto out;
4249242bd2d5SXin Long 
4250242bd2d5SXin Long 	if (copy_from_user(&params, optval, optlen)) {
4251242bd2d5SXin Long 		retval = -EFAULT;
4252242bd2d5SXin Long 		goto out;
4253242bd2d5SXin Long 	}
4254242bd2d5SXin Long 
4255242bd2d5SXin Long 	asoc = sctp_id2assoc(sk, params.sas_assoc_id);
4256242bd2d5SXin Long 	if (!asoc)
4257242bd2d5SXin Long 		goto out;
4258242bd2d5SXin Long 
4259242bd2d5SXin Long 	retval = sctp_send_add_streams(asoc, &params);
4260242bd2d5SXin Long 
4261242bd2d5SXin Long out:
4262242bd2d5SXin Long 	return retval;
4263242bd2d5SXin Long }
4264242bd2d5SXin Long 
426513aa8770SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler(struct sock *sk,
426613aa8770SMarcelo Ricardo Leitner 				     char __user *optval,
426713aa8770SMarcelo Ricardo Leitner 				     unsigned int optlen)
426813aa8770SMarcelo Ricardo Leitner {
42697efba10dSXin Long 	struct sctp_sock *sp = sctp_sk(sk);
427013aa8770SMarcelo Ricardo Leitner 	struct sctp_association *asoc;
427113aa8770SMarcelo Ricardo Leitner 	struct sctp_assoc_value params;
42727efba10dSXin Long 	int retval = 0;
427313aa8770SMarcelo Ricardo Leitner 
427413aa8770SMarcelo Ricardo Leitner 	if (optlen < sizeof(params))
42757efba10dSXin Long 		return -EINVAL;
427613aa8770SMarcelo Ricardo Leitner 
427713aa8770SMarcelo Ricardo Leitner 	optlen = sizeof(params);
42787efba10dSXin Long 	if (copy_from_user(&params, optval, optlen))
42797efba10dSXin Long 		return -EFAULT;
428013aa8770SMarcelo Ricardo Leitner 
428113aa8770SMarcelo Ricardo Leitner 	if (params.assoc_value > SCTP_SS_MAX)
42827efba10dSXin Long 		return -EINVAL;
428313aa8770SMarcelo Ricardo Leitner 
428413aa8770SMarcelo Ricardo Leitner 	asoc = sctp_id2assoc(sk, params.assoc_id);
42857efba10dSXin Long 	if (!asoc && params.assoc_id > SCTP_ALL_ASSOC &&
42867efba10dSXin Long 	    sctp_style(sk, UDP))
42877efba10dSXin Long 		return -EINVAL;
428813aa8770SMarcelo Ricardo Leitner 
42897efba10dSXin Long 	if (asoc)
42907efba10dSXin Long 		return sctp_sched_set_sched(asoc, params.assoc_value);
429113aa8770SMarcelo Ricardo Leitner 
4292b59c19d9SXin Long 	if (sctp_style(sk, TCP))
4293b59c19d9SXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
4294b59c19d9SXin Long 
42957efba10dSXin Long 	if (params.assoc_id == SCTP_FUTURE_ASSOC ||
42967efba10dSXin Long 	    params.assoc_id == SCTP_ALL_ASSOC)
42977efba10dSXin Long 		sp->default_ss = params.assoc_value;
42987efba10dSXin Long 
42997efba10dSXin Long 	if (params.assoc_id == SCTP_CURRENT_ASSOC ||
43007efba10dSXin Long 	    params.assoc_id == SCTP_ALL_ASSOC) {
43017efba10dSXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
43027efba10dSXin Long 			int ret = sctp_sched_set_sched(asoc,
43037efba10dSXin Long 						       params.assoc_value);
43047efba10dSXin Long 
43057efba10dSXin Long 			if (ret && !retval)
43067efba10dSXin Long 				retval = ret;
43077efba10dSXin Long 		}
43087efba10dSXin Long 	}
43097efba10dSXin Long 
431013aa8770SMarcelo Ricardo Leitner 	return retval;
431113aa8770SMarcelo Ricardo Leitner }
431213aa8770SMarcelo Ricardo Leitner 
43130ccdf3c7SMarcelo Ricardo Leitner static int sctp_setsockopt_scheduler_value(struct sock *sk,
43140ccdf3c7SMarcelo Ricardo Leitner 					   char __user *optval,
43150ccdf3c7SMarcelo Ricardo Leitner 					   unsigned int optlen)
43160ccdf3c7SMarcelo Ricardo Leitner {
43170ccdf3c7SMarcelo Ricardo Leitner 	struct sctp_stream_value params;
4318e7f28248SXin Long 	struct sctp_association *asoc;
43190ccdf3c7SMarcelo Ricardo Leitner 	int retval = -EINVAL;
43200ccdf3c7SMarcelo Ricardo Leitner 
43210ccdf3c7SMarcelo Ricardo Leitner 	if (optlen < sizeof(params))
43220ccdf3c7SMarcelo Ricardo Leitner 		goto out;
43230ccdf3c7SMarcelo Ricardo Leitner 
43240ccdf3c7SMarcelo Ricardo Leitner 	optlen = sizeof(params);
43250ccdf3c7SMarcelo Ricardo Leitner 	if (copy_from_user(&params, optval, optlen)) {
43260ccdf3c7SMarcelo Ricardo Leitner 		retval = -EFAULT;
43270ccdf3c7SMarcelo Ricardo Leitner 		goto out;
43280ccdf3c7SMarcelo Ricardo Leitner 	}
43290ccdf3c7SMarcelo Ricardo Leitner 
43300ccdf3c7SMarcelo Ricardo Leitner 	asoc = sctp_id2assoc(sk, params.assoc_id);
4331e7f28248SXin Long 	if (!asoc && params.assoc_id != SCTP_CURRENT_ASSOC &&
4332e7f28248SXin Long 	    sctp_style(sk, UDP))
43330ccdf3c7SMarcelo Ricardo Leitner 		goto out;
43340ccdf3c7SMarcelo Ricardo Leitner 
4335e7f28248SXin Long 	if (asoc) {
43360ccdf3c7SMarcelo Ricardo Leitner 		retval = sctp_sched_set_value(asoc, params.stream_id,
43370ccdf3c7SMarcelo Ricardo Leitner 					      params.stream_value, GFP_KERNEL);
4338e7f28248SXin Long 		goto out;
4339e7f28248SXin Long 	}
4340e7f28248SXin Long 
4341e7f28248SXin Long 	retval = 0;
4342e7f28248SXin Long 
4343e7f28248SXin Long 	list_for_each_entry(asoc, &sctp_sk(sk)->ep->asocs, asocs) {
4344e7f28248SXin Long 		int ret = sctp_sched_set_value(asoc, params.stream_id,
4345e7f28248SXin Long 					       params.stream_value, GFP_KERNEL);
4346e7f28248SXin Long 		if (ret && !retval) /* try to return the 1st error. */
4347e7f28248SXin Long 			retval = ret;
4348e7f28248SXin Long 	}
43490ccdf3c7SMarcelo Ricardo Leitner 
43500ccdf3c7SMarcelo Ricardo Leitner out:
43510ccdf3c7SMarcelo Ricardo Leitner 	return retval;
43520ccdf3c7SMarcelo Ricardo Leitner }
43530ccdf3c7SMarcelo Ricardo Leitner 
4354772a5869SXin Long static int sctp_setsockopt_interleaving_supported(struct sock *sk,
4355772a5869SXin Long 						  char __user *optval,
4356772a5869SXin Long 						  unsigned int optlen)
4357772a5869SXin Long {
4358772a5869SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
4359772a5869SXin Long 	struct sctp_assoc_value params;
43602e7709d1SXin Long 	struct sctp_association *asoc;
4361772a5869SXin Long 	int retval = -EINVAL;
4362772a5869SXin Long 
4363772a5869SXin Long 	if (optlen < sizeof(params))
4364772a5869SXin Long 		goto out;
4365772a5869SXin Long 
4366772a5869SXin Long 	optlen = sizeof(params);
4367772a5869SXin Long 	if (copy_from_user(&params, optval, optlen)) {
4368772a5869SXin Long 		retval = -EFAULT;
4369772a5869SXin Long 		goto out;
4370772a5869SXin Long 	}
4371772a5869SXin Long 
43722e7709d1SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
43732e7709d1SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
43742e7709d1SXin Long 	    sctp_style(sk, UDP))
4375772a5869SXin Long 		goto out;
4376772a5869SXin Long 
43772e7709d1SXin Long 	if (!sock_net(sk)->sctp.intl_enable || !sp->frag_interleave) {
4378772a5869SXin Long 		retval = -EPERM;
4379772a5869SXin Long 		goto out;
4380772a5869SXin Long 	}
4381772a5869SXin Long 
4382e55f4b8bSXin Long 	sp->ep->intl_enable = !!params.assoc_value;
4383772a5869SXin Long 
4384772a5869SXin Long 	retval = 0;
4385772a5869SXin Long 
4386772a5869SXin Long out:
4387772a5869SXin Long 	return retval;
4388772a5869SXin Long }
4389772a5869SXin Long 
4390b0e9a2feSXin Long static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval,
4391b0e9a2feSXin Long 				      unsigned int optlen)
4392b0e9a2feSXin Long {
4393b0e9a2feSXin Long 	int val;
4394b0e9a2feSXin Long 
4395b0e9a2feSXin Long 	if (!sctp_style(sk, TCP))
4396b0e9a2feSXin Long 		return -EOPNOTSUPP;
4397b0e9a2feSXin Long 
4398b0e9a2feSXin Long 	if (sctp_sk(sk)->ep->base.bind_addr.port)
4399b0e9a2feSXin Long 		return -EFAULT;
4400b0e9a2feSXin Long 
4401b0e9a2feSXin Long 	if (optlen < sizeof(int))
4402b0e9a2feSXin Long 		return -EINVAL;
4403b0e9a2feSXin Long 
4404b0e9a2feSXin Long 	if (get_user(val, (int __user *)optval))
4405b0e9a2feSXin Long 		return -EFAULT;
4406b0e9a2feSXin Long 
4407b0e9a2feSXin Long 	sctp_sk(sk)->reuse = !!val;
4408b0e9a2feSXin Long 
4409b0e9a2feSXin Long 	return 0;
4410b0e9a2feSXin Long }
4411b0e9a2feSXin Long 
4412d251f05eSXin Long static int sctp_assoc_ulpevent_type_set(struct sctp_event *param,
4413d251f05eSXin Long 					struct sctp_association *asoc)
4414480ba9c1SXin Long {
4415480ba9c1SXin Long 	struct sctp_ulpevent *event;
4416480ba9c1SXin Long 
4417d251f05eSXin Long 	sctp_ulpevent_type_set(&asoc->subscribe, param->se_type, param->se_on);
4418480ba9c1SXin Long 
4419d251f05eSXin Long 	if (param->se_type == SCTP_SENDER_DRY_EVENT && param->se_on) {
4420480ba9c1SXin Long 		if (sctp_outq_is_empty(&asoc->outqueue)) {
4421480ba9c1SXin Long 			event = sctp_ulpevent_make_sender_dry_event(asoc,
4422480ba9c1SXin Long 					GFP_USER | __GFP_NOWARN);
4423d251f05eSXin Long 			if (!event)
4424d251f05eSXin Long 				return -ENOMEM;
4425480ba9c1SXin Long 
4426480ba9c1SXin Long 			asoc->stream.si->enqueue_event(&asoc->ulpq, event);
4427480ba9c1SXin Long 		}
4428480ba9c1SXin Long 	}
4429480ba9c1SXin Long 
4430d251f05eSXin Long 	return 0;
4431d251f05eSXin Long }
4432d251f05eSXin Long 
4433d251f05eSXin Long static int sctp_setsockopt_event(struct sock *sk, char __user *optval,
4434d251f05eSXin Long 				 unsigned int optlen)
4435d251f05eSXin Long {
4436d251f05eSXin Long 	struct sctp_sock *sp = sctp_sk(sk);
4437d251f05eSXin Long 	struct sctp_association *asoc;
4438d251f05eSXin Long 	struct sctp_event param;
4439d251f05eSXin Long 	int retval = 0;
4440d251f05eSXin Long 
4441d251f05eSXin Long 	if (optlen < sizeof(param))
4442d251f05eSXin Long 		return -EINVAL;
4443d251f05eSXin Long 
4444d251f05eSXin Long 	optlen = sizeof(param);
4445d251f05eSXin Long 	if (copy_from_user(&param, optval, optlen))
4446d251f05eSXin Long 		return -EFAULT;
4447d251f05eSXin Long 
4448d251f05eSXin Long 	if (param.se_type < SCTP_SN_TYPE_BASE ||
4449d251f05eSXin Long 	    param.se_type > SCTP_SN_TYPE_MAX)
4450d251f05eSXin Long 		return -EINVAL;
4451d251f05eSXin Long 
4452d251f05eSXin Long 	asoc = sctp_id2assoc(sk, param.se_assoc_id);
4453d251f05eSXin Long 	if (!asoc && param.se_assoc_id > SCTP_ALL_ASSOC &&
4454d251f05eSXin Long 	    sctp_style(sk, UDP))
4455d251f05eSXin Long 		return -EINVAL;
4456d251f05eSXin Long 
4457d251f05eSXin Long 	if (asoc)
4458d251f05eSXin Long 		return sctp_assoc_ulpevent_type_set(&param, asoc);
4459d251f05eSXin Long 
446099518619SXin Long 	if (sctp_style(sk, TCP))
446199518619SXin Long 		param.se_assoc_id = SCTP_FUTURE_ASSOC;
446299518619SXin Long 
4463d251f05eSXin Long 	if (param.se_assoc_id == SCTP_FUTURE_ASSOC ||
4464d251f05eSXin Long 	    param.se_assoc_id == SCTP_ALL_ASSOC)
4465d251f05eSXin Long 		sctp_ulpevent_type_set(&sp->subscribe,
4466d251f05eSXin Long 				       param.se_type, param.se_on);
4467d251f05eSXin Long 
4468d251f05eSXin Long 	if (param.se_assoc_id == SCTP_CURRENT_ASSOC ||
4469d251f05eSXin Long 	    param.se_assoc_id == SCTP_ALL_ASSOC) {
4470d251f05eSXin Long 		list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
4471d251f05eSXin Long 			int ret = sctp_assoc_ulpevent_type_set(&param, asoc);
4472d251f05eSXin Long 
4473d251f05eSXin Long 			if (ret && !retval)
4474d251f05eSXin Long 				retval = ret;
4475d251f05eSXin Long 		}
4476d251f05eSXin Long 	}
4477d251f05eSXin Long 
4478480ba9c1SXin Long 	return retval;
4479480ba9c1SXin Long }
4480480ba9c1SXin Long 
4481df2c71ffSXin Long static int sctp_setsockopt_asconf_supported(struct sock *sk,
4482df2c71ffSXin Long 					    char __user *optval,
4483df2c71ffSXin Long 					    unsigned int optlen)
4484df2c71ffSXin Long {
4485df2c71ffSXin Long 	struct sctp_assoc_value params;
4486df2c71ffSXin Long 	struct sctp_association *asoc;
4487df2c71ffSXin Long 	struct sctp_endpoint *ep;
4488df2c71ffSXin Long 	int retval = -EINVAL;
4489df2c71ffSXin Long 
4490df2c71ffSXin Long 	if (optlen != sizeof(params))
4491df2c71ffSXin Long 		goto out;
4492df2c71ffSXin Long 
4493df2c71ffSXin Long 	if (copy_from_user(&params, optval, optlen)) {
4494df2c71ffSXin Long 		retval = -EFAULT;
4495df2c71ffSXin Long 		goto out;
4496df2c71ffSXin Long 	}
4497df2c71ffSXin Long 
4498df2c71ffSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
4499df2c71ffSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
4500df2c71ffSXin Long 	    sctp_style(sk, UDP))
4501df2c71ffSXin Long 		goto out;
4502df2c71ffSXin Long 
4503df2c71ffSXin Long 	ep = sctp_sk(sk)->ep;
4504df2c71ffSXin Long 	ep->asconf_enable = !!params.assoc_value;
4505df2c71ffSXin Long 
4506df2c71ffSXin Long 	if (ep->asconf_enable && ep->auth_enable) {
4507df2c71ffSXin Long 		sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
4508df2c71ffSXin Long 		sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
4509df2c71ffSXin Long 	}
4510df2c71ffSXin Long 
4511df2c71ffSXin Long 	retval = 0;
4512df2c71ffSXin Long 
4513df2c71ffSXin Long out:
4514df2c71ffSXin Long 	return retval;
4515df2c71ffSXin Long }
4516df2c71ffSXin Long 
451756dd525aSXin Long static int sctp_setsockopt_auth_supported(struct sock *sk,
451856dd525aSXin Long 					  char __user *optval,
451956dd525aSXin Long 					  unsigned int optlen)
452056dd525aSXin Long {
452156dd525aSXin Long 	struct sctp_assoc_value params;
452256dd525aSXin Long 	struct sctp_association *asoc;
452356dd525aSXin Long 	struct sctp_endpoint *ep;
452456dd525aSXin Long 	int retval = -EINVAL;
452556dd525aSXin Long 
452656dd525aSXin Long 	if (optlen != sizeof(params))
452756dd525aSXin Long 		goto out;
452856dd525aSXin Long 
452956dd525aSXin Long 	if (copy_from_user(&params, optval, optlen)) {
453056dd525aSXin Long 		retval = -EFAULT;
453156dd525aSXin Long 		goto out;
453256dd525aSXin Long 	}
453356dd525aSXin Long 
453456dd525aSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
453556dd525aSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
453656dd525aSXin Long 	    sctp_style(sk, UDP))
453756dd525aSXin Long 		goto out;
453856dd525aSXin Long 
453956dd525aSXin Long 	ep = sctp_sk(sk)->ep;
454056dd525aSXin Long 	if (params.assoc_value) {
454156dd525aSXin Long 		retval = sctp_auth_init(ep, GFP_KERNEL);
454256dd525aSXin Long 		if (retval)
454356dd525aSXin Long 			goto out;
454456dd525aSXin Long 		if (ep->asconf_enable) {
454556dd525aSXin Long 			sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
454656dd525aSXin Long 			sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
454756dd525aSXin Long 		}
454856dd525aSXin Long 	}
454956dd525aSXin Long 
455056dd525aSXin Long 	ep->auth_enable = !!params.assoc_value;
455156dd525aSXin Long 	retval = 0;
455256dd525aSXin Long 
455356dd525aSXin Long out:
455456dd525aSXin Long 	return retval;
455556dd525aSXin Long }
455656dd525aSXin Long 
4557d5886b91SXin Long static int sctp_setsockopt_ecn_supported(struct sock *sk,
4558d5886b91SXin Long 					 char __user *optval,
4559d5886b91SXin Long 					 unsigned int optlen)
4560d5886b91SXin Long {
4561d5886b91SXin Long 	struct sctp_assoc_value params;
4562d5886b91SXin Long 	struct sctp_association *asoc;
4563d5886b91SXin Long 	int retval = -EINVAL;
4564d5886b91SXin Long 
4565d5886b91SXin Long 	if (optlen != sizeof(params))
4566d5886b91SXin Long 		goto out;
4567d5886b91SXin Long 
4568d5886b91SXin Long 	if (copy_from_user(&params, optval, optlen)) {
4569d5886b91SXin Long 		retval = -EFAULT;
4570d5886b91SXin Long 		goto out;
4571d5886b91SXin Long 	}
4572d5886b91SXin Long 
4573d5886b91SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
4574d5886b91SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
4575d5886b91SXin Long 	    sctp_style(sk, UDP))
4576d5886b91SXin Long 		goto out;
4577d5886b91SXin Long 
4578d5886b91SXin Long 	sctp_sk(sk)->ep->ecn_enable = !!params.assoc_value;
4579d5886b91SXin Long 	retval = 0;
4580d5886b91SXin Long 
4581d5886b91SXin Long out:
4582d5886b91SXin Long 	return retval;
4583d5886b91SXin Long }
4584d5886b91SXin Long 
45858d2a6935SXin Long static int sctp_setsockopt_pf_expose(struct sock *sk,
45868d2a6935SXin Long 				     char __user *optval,
45878d2a6935SXin Long 				     unsigned int optlen)
45888d2a6935SXin Long {
45898d2a6935SXin Long 	struct sctp_assoc_value params;
45908d2a6935SXin Long 	struct sctp_association *asoc;
45918d2a6935SXin Long 	int retval = -EINVAL;
45928d2a6935SXin Long 
45938d2a6935SXin Long 	if (optlen != sizeof(params))
45948d2a6935SXin Long 		goto out;
45958d2a6935SXin Long 
45968d2a6935SXin Long 	if (copy_from_user(&params, optval, optlen)) {
45978d2a6935SXin Long 		retval = -EFAULT;
45988d2a6935SXin Long 		goto out;
45998d2a6935SXin Long 	}
46008d2a6935SXin Long 
46018d2a6935SXin Long 	if (params.assoc_value > SCTP_PF_EXPOSE_MAX)
46028d2a6935SXin Long 		goto out;
46038d2a6935SXin Long 
46048d2a6935SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
46058d2a6935SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
46068d2a6935SXin Long 	    sctp_style(sk, UDP))
46078d2a6935SXin Long 		goto out;
46088d2a6935SXin Long 
46098d2a6935SXin Long 	if (asoc)
46108d2a6935SXin Long 		asoc->pf_expose = params.assoc_value;
46118d2a6935SXin Long 	else
46128d2a6935SXin Long 		sctp_sk(sk)->pf_expose = params.assoc_value;
46138d2a6935SXin Long 	retval = 0;
46148d2a6935SXin Long 
46158d2a6935SXin Long out:
46168d2a6935SXin Long 	return retval;
46178d2a6935SXin Long }
46188d2a6935SXin Long 
46191da177e4SLinus Torvalds /* API 6.2 setsockopt(), getsockopt()
46201da177e4SLinus Torvalds  *
46211da177e4SLinus Torvalds  * Applications use setsockopt() and getsockopt() to set or retrieve
46221da177e4SLinus Torvalds  * socket options.  Socket options are used to change the default
46231da177e4SLinus Torvalds  * behavior of sockets calls.  They are described in Section 7.
46241da177e4SLinus Torvalds  *
46251da177e4SLinus Torvalds  * The syntax is:
46261da177e4SLinus Torvalds  *
46271da177e4SLinus Torvalds  *   ret = getsockopt(int sd, int level, int optname, void __user *optval,
46281da177e4SLinus Torvalds  *                    int __user *optlen);
46291da177e4SLinus Torvalds  *   ret = setsockopt(int sd, int level, int optname, const void __user *optval,
46301da177e4SLinus Torvalds  *                    int optlen);
46311da177e4SLinus Torvalds  *
46321da177e4SLinus Torvalds  *   sd      - the socket descript.
46331da177e4SLinus Torvalds  *   level   - set to IPPROTO_SCTP for all SCTP options.
46341da177e4SLinus Torvalds  *   optname - the option name.
46351da177e4SLinus Torvalds  *   optval  - the buffer to store the value of the option.
46361da177e4SLinus Torvalds  *   optlen  - the size of the buffer.
46371da177e4SLinus Torvalds  */
4638dda91928SDaniel Borkmann static int sctp_setsockopt(struct sock *sk, int level, int optname,
4639b7058842SDavid S. Miller 			   char __user *optval, unsigned int optlen)
46401da177e4SLinus Torvalds {
4641ca84bd05SChristoph Hellwig 	void *kopt = NULL;
46421da177e4SLinus Torvalds 	int retval = 0;
46431da177e4SLinus Torvalds 
4644bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname);
46451da177e4SLinus Torvalds 
46461da177e4SLinus Torvalds 	/* I can hardly begin to describe how wrong this is.  This is
46471da177e4SLinus Torvalds 	 * so broken as to be worse than useless.  The API draft
46481da177e4SLinus Torvalds 	 * REALLY is NOT helpful here...  I am not convinced that the
46491da177e4SLinus Torvalds 	 * semantics of setsockopt() with a level OTHER THAN SOL_SCTP
46501da177e4SLinus Torvalds 	 * are at all well-founded.
46511da177e4SLinus Torvalds 	 */
46521da177e4SLinus Torvalds 	if (level != SOL_SCTP) {
46531da177e4SLinus Torvalds 		struct sctp_af *af = sctp_sk(sk)->pf->af;
46541da177e4SLinus Torvalds 		retval = af->setsockopt(sk, level, optname, optval, optlen);
46551da177e4SLinus Torvalds 		goto out_nounlock;
46561da177e4SLinus Torvalds 	}
46571da177e4SLinus Torvalds 
4658ca84bd05SChristoph Hellwig 	if (optlen > 0) {
4659ca84bd05SChristoph Hellwig 		kopt = memdup_user(optval, optlen);
4660ca84bd05SChristoph Hellwig 		if (IS_ERR(kopt))
4661ca84bd05SChristoph Hellwig 			return PTR_ERR(kopt);
4662ca84bd05SChristoph Hellwig 	}
4663ca84bd05SChristoph Hellwig 
4664048ed4b6Swangweidong 	lock_sock(sk);
46651da177e4SLinus Torvalds 
46661da177e4SLinus Torvalds 	switch (optname) {
46671da177e4SLinus Torvalds 	case SCTP_SOCKOPT_BINDX_ADD:
46681da177e4SLinus Torvalds 		/* 'optlen' is the size of the addresses buffer. */
46698c7517f5SChristoph Hellwig 		retval = sctp_setsockopt_bindx(sk, kopt, optlen,
46708c7517f5SChristoph Hellwig 					       SCTP_BINDX_ADD_ADDR);
46711da177e4SLinus Torvalds 		break;
46721da177e4SLinus Torvalds 
46731da177e4SLinus Torvalds 	case SCTP_SOCKOPT_BINDX_REM:
46741da177e4SLinus Torvalds 		/* 'optlen' is the size of the addresses buffer. */
46758c7517f5SChristoph Hellwig 		retval = sctp_setsockopt_bindx(sk, kopt, optlen,
46768c7517f5SChristoph Hellwig 					       SCTP_BINDX_REM_ADDR);
46771da177e4SLinus Torvalds 		break;
46781da177e4SLinus Torvalds 
467988a0a948SVlad Yasevich 	case SCTP_SOCKOPT_CONNECTX_OLD:
468088a0a948SVlad Yasevich 		/* 'optlen' is the size of the addresses buffer. */
4681ce5b2f89SChristoph Hellwig 		retval = sctp_setsockopt_connectx_old(sk, kopt, optlen);
468288a0a948SVlad Yasevich 		break;
468388a0a948SVlad Yasevich 
46843f7a87d2SFrank Filz 	case SCTP_SOCKOPT_CONNECTX:
46853f7a87d2SFrank Filz 		/* 'optlen' is the size of the addresses buffer. */
4686ce5b2f89SChristoph Hellwig 		retval = sctp_setsockopt_connectx(sk, kopt, optlen);
46873f7a87d2SFrank Filz 		break;
46883f7a87d2SFrank Filz 
46891da177e4SLinus Torvalds 	case SCTP_DISABLE_FRAGMENTS:
469010835825SChristoph Hellwig 		retval = sctp_setsockopt_disable_fragments(sk, kopt, optlen);
46911da177e4SLinus Torvalds 		break;
46921da177e4SLinus Torvalds 
46931da177e4SLinus Torvalds 	case SCTP_EVENTS:
4694a98d21a1SChristoph Hellwig 		retval = sctp_setsockopt_events(sk, kopt, optlen);
46951da177e4SLinus Torvalds 		break;
46961da177e4SLinus Torvalds 
46971da177e4SLinus Torvalds 	case SCTP_AUTOCLOSE:
4698*0b49a65cSChristoph Hellwig 		retval = sctp_setsockopt_autoclose(sk, kopt, optlen);
46991da177e4SLinus Torvalds 		break;
47001da177e4SLinus Torvalds 
47011da177e4SLinus Torvalds 	case SCTP_PEER_ADDR_PARAMS:
47021da177e4SLinus Torvalds 		retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
47031da177e4SLinus Torvalds 		break;
47041da177e4SLinus Torvalds 
47054580ccc0SShan Wei 	case SCTP_DELAYED_SACK:
4706d364d927SWei Yongjun 		retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
47077708610bSFrank Filz 		break;
4708d49d91d7SVlad Yasevich 	case SCTP_PARTIAL_DELIVERY_POINT:
4709d49d91d7SVlad Yasevich 		retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen);
4710d49d91d7SVlad Yasevich 		break;
47117708610bSFrank Filz 
47121da177e4SLinus Torvalds 	case SCTP_INITMSG:
47131da177e4SLinus Torvalds 		retval = sctp_setsockopt_initmsg(sk, optval, optlen);
47141da177e4SLinus Torvalds 		break;
47151da177e4SLinus Torvalds 	case SCTP_DEFAULT_SEND_PARAM:
47161da177e4SLinus Torvalds 		retval = sctp_setsockopt_default_send_param(sk, optval,
47171da177e4SLinus Torvalds 							    optlen);
47181da177e4SLinus Torvalds 		break;
47196b3fd5f3SGeir Ola Vaagland 	case SCTP_DEFAULT_SNDINFO:
47206b3fd5f3SGeir Ola Vaagland 		retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen);
47216b3fd5f3SGeir Ola Vaagland 		break;
47221da177e4SLinus Torvalds 	case SCTP_PRIMARY_ADDR:
47231da177e4SLinus Torvalds 		retval = sctp_setsockopt_primary_addr(sk, optval, optlen);
47241da177e4SLinus Torvalds 		break;
47251da177e4SLinus Torvalds 	case SCTP_SET_PEER_PRIMARY_ADDR:
47261da177e4SLinus Torvalds 		retval = sctp_setsockopt_peer_primary_addr(sk, optval, optlen);
47271da177e4SLinus Torvalds 		break;
47281da177e4SLinus Torvalds 	case SCTP_NODELAY:
47291da177e4SLinus Torvalds 		retval = sctp_setsockopt_nodelay(sk, optval, optlen);
47301da177e4SLinus Torvalds 		break;
47311da177e4SLinus Torvalds 	case SCTP_RTOINFO:
47321da177e4SLinus Torvalds 		retval = sctp_setsockopt_rtoinfo(sk, optval, optlen);
47331da177e4SLinus Torvalds 		break;
47341da177e4SLinus Torvalds 	case SCTP_ASSOCINFO:
47351da177e4SLinus Torvalds 		retval = sctp_setsockopt_associnfo(sk, optval, optlen);
47361da177e4SLinus Torvalds 		break;
47371da177e4SLinus Torvalds 	case SCTP_I_WANT_MAPPED_V4_ADDR:
47381da177e4SLinus Torvalds 		retval = sctp_setsockopt_mappedv4(sk, optval, optlen);
47391da177e4SLinus Torvalds 		break;
47401da177e4SLinus Torvalds 	case SCTP_MAXSEG:
47411da177e4SLinus Torvalds 		retval = sctp_setsockopt_maxseg(sk, optval, optlen);
47421da177e4SLinus Torvalds 		break;
47430f3fffd8SIvan Skytte Jorgensen 	case SCTP_ADAPTATION_LAYER:
47440f3fffd8SIvan Skytte Jorgensen 		retval = sctp_setsockopt_adaptation_layer(sk, optval, optlen);
47451da177e4SLinus Torvalds 		break;
47466ab792f5SIvan Skytte Jorgensen 	case SCTP_CONTEXT:
47476ab792f5SIvan Skytte Jorgensen 		retval = sctp_setsockopt_context(sk, optval, optlen);
47486ab792f5SIvan Skytte Jorgensen 		break;
4749b6e1331fSVlad Yasevich 	case SCTP_FRAGMENT_INTERLEAVE:
4750b6e1331fSVlad Yasevich 		retval = sctp_setsockopt_fragment_interleave(sk, optval, optlen);
4751b6e1331fSVlad Yasevich 		break;
475270331571SVlad Yasevich 	case SCTP_MAX_BURST:
475370331571SVlad Yasevich 		retval = sctp_setsockopt_maxburst(sk, optval, optlen);
475470331571SVlad Yasevich 		break;
475565b07e5dSVlad Yasevich 	case SCTP_AUTH_CHUNK:
475665b07e5dSVlad Yasevich 		retval = sctp_setsockopt_auth_chunk(sk, optval, optlen);
475765b07e5dSVlad Yasevich 		break;
475865b07e5dSVlad Yasevich 	case SCTP_HMAC_IDENT:
475965b07e5dSVlad Yasevich 		retval = sctp_setsockopt_hmac_ident(sk, optval, optlen);
476065b07e5dSVlad Yasevich 		break;
476165b07e5dSVlad Yasevich 	case SCTP_AUTH_KEY:
476265b07e5dSVlad Yasevich 		retval = sctp_setsockopt_auth_key(sk, optval, optlen);
476365b07e5dSVlad Yasevich 		break;
476465b07e5dSVlad Yasevich 	case SCTP_AUTH_ACTIVE_KEY:
476565b07e5dSVlad Yasevich 		retval = sctp_setsockopt_active_key(sk, optval, optlen);
476665b07e5dSVlad Yasevich 		break;
476765b07e5dSVlad Yasevich 	case SCTP_AUTH_DELETE_KEY:
476865b07e5dSVlad Yasevich 		retval = sctp_setsockopt_del_key(sk, optval, optlen);
476965b07e5dSVlad Yasevich 		break;
4770601590ecSXin Long 	case SCTP_AUTH_DEACTIVATE_KEY:
4771601590ecSXin Long 		retval = sctp_setsockopt_deactivate_key(sk, optval, optlen);
4772601590ecSXin Long 		break;
47737dc04d71SMichio Honda 	case SCTP_AUTO_ASCONF:
47747dc04d71SMichio Honda 		retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
47757dc04d71SMichio Honda 		break;
47765aa93bcfSNeil Horman 	case SCTP_PEER_ADDR_THLDS:
4777d467ac0aSXin Long 		retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen,
4778d467ac0aSXin Long 							  false);
4779d467ac0aSXin Long 		break;
4780d467ac0aSXin Long 	case SCTP_PEER_ADDR_THLDS_V2:
4781d467ac0aSXin Long 		retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen,
4782d467ac0aSXin Long 							  true);
47835aa93bcfSNeil Horman 		break;
47840d3a421dSGeir Ola Vaagland 	case SCTP_RECVRCVINFO:
47850d3a421dSGeir Ola Vaagland 		retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen);
47860d3a421dSGeir Ola Vaagland 		break;
47872347c80fSGeir Ola Vaagland 	case SCTP_RECVNXTINFO:
47882347c80fSGeir Ola Vaagland 		retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen);
47892347c80fSGeir Ola Vaagland 		break;
479028aa4c26SXin Long 	case SCTP_PR_SUPPORTED:
479128aa4c26SXin Long 		retval = sctp_setsockopt_pr_supported(sk, optval, optlen);
479228aa4c26SXin Long 		break;
4793f959fb44SXin Long 	case SCTP_DEFAULT_PRINFO:
4794f959fb44SXin Long 		retval = sctp_setsockopt_default_prinfo(sk, optval, optlen);
4795f959fb44SXin Long 		break;
4796c0d8bab6SXin Long 	case SCTP_RECONFIG_SUPPORTED:
4797c0d8bab6SXin Long 		retval = sctp_setsockopt_reconfig_supported(sk, optval, optlen);
4798c0d8bab6SXin Long 		break;
47999fb657aeSXin Long 	case SCTP_ENABLE_STREAM_RESET:
48009fb657aeSXin Long 		retval = sctp_setsockopt_enable_strreset(sk, optval, optlen);
48019fb657aeSXin Long 		break;
48027f9d68acSXin Long 	case SCTP_RESET_STREAMS:
48037f9d68acSXin Long 		retval = sctp_setsockopt_reset_streams(sk, optval, optlen);
48047f9d68acSXin Long 		break;
4805a92ce1a4SXin Long 	case SCTP_RESET_ASSOC:
4806a92ce1a4SXin Long 		retval = sctp_setsockopt_reset_assoc(sk, optval, optlen);
4807a92ce1a4SXin Long 		break;
4808242bd2d5SXin Long 	case SCTP_ADD_STREAMS:
4809242bd2d5SXin Long 		retval = sctp_setsockopt_add_streams(sk, optval, optlen);
4810242bd2d5SXin Long 		break;
481113aa8770SMarcelo Ricardo Leitner 	case SCTP_STREAM_SCHEDULER:
481213aa8770SMarcelo Ricardo Leitner 		retval = sctp_setsockopt_scheduler(sk, optval, optlen);
481313aa8770SMarcelo Ricardo Leitner 		break;
48140ccdf3c7SMarcelo Ricardo Leitner 	case SCTP_STREAM_SCHEDULER_VALUE:
48150ccdf3c7SMarcelo Ricardo Leitner 		retval = sctp_setsockopt_scheduler_value(sk, optval, optlen);
48160ccdf3c7SMarcelo Ricardo Leitner 		break;
4817772a5869SXin Long 	case SCTP_INTERLEAVING_SUPPORTED:
4818772a5869SXin Long 		retval = sctp_setsockopt_interleaving_supported(sk, optval,
4819772a5869SXin Long 								optlen);
4820772a5869SXin Long 		break;
4821b0e9a2feSXin Long 	case SCTP_REUSE_PORT:
4822b0e9a2feSXin Long 		retval = sctp_setsockopt_reuse_port(sk, optval, optlen);
4823b0e9a2feSXin Long 		break;
4824480ba9c1SXin Long 	case SCTP_EVENT:
4825480ba9c1SXin Long 		retval = sctp_setsockopt_event(sk, optval, optlen);
4826480ba9c1SXin Long 		break;
4827df2c71ffSXin Long 	case SCTP_ASCONF_SUPPORTED:
4828df2c71ffSXin Long 		retval = sctp_setsockopt_asconf_supported(sk, optval, optlen);
4829df2c71ffSXin Long 		break;
483056dd525aSXin Long 	case SCTP_AUTH_SUPPORTED:
483156dd525aSXin Long 		retval = sctp_setsockopt_auth_supported(sk, optval, optlen);
483256dd525aSXin Long 		break;
4833d5886b91SXin Long 	case SCTP_ECN_SUPPORTED:
4834d5886b91SXin Long 		retval = sctp_setsockopt_ecn_supported(sk, optval, optlen);
4835d5886b91SXin Long 		break;
48368d2a6935SXin Long 	case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
48378d2a6935SXin Long 		retval = sctp_setsockopt_pf_expose(sk, optval, optlen);
48388d2a6935SXin Long 		break;
48391da177e4SLinus Torvalds 	default:
48401da177e4SLinus Torvalds 		retval = -ENOPROTOOPT;
48411da177e4SLinus Torvalds 		break;
48423ff50b79SStephen Hemminger 	}
48431da177e4SLinus Torvalds 
4844048ed4b6Swangweidong 	release_sock(sk);
4845ca84bd05SChristoph Hellwig 	kfree(kopt);
48461da177e4SLinus Torvalds 
48471da177e4SLinus Torvalds out_nounlock:
48481da177e4SLinus Torvalds 	return retval;
48491da177e4SLinus Torvalds }
48501da177e4SLinus Torvalds 
48511da177e4SLinus Torvalds /* API 3.1.6 connect() - UDP Style Syntax
48521da177e4SLinus Torvalds  *
48531da177e4SLinus Torvalds  * An application may use the connect() call in the UDP model to initiate an
48541da177e4SLinus Torvalds  * association without sending data.
48551da177e4SLinus Torvalds  *
48561da177e4SLinus Torvalds  * The syntax is:
48571da177e4SLinus Torvalds  *
48581da177e4SLinus Torvalds  * ret = connect(int sd, const struct sockaddr *nam, socklen_t len);
48591da177e4SLinus Torvalds  *
48601da177e4SLinus Torvalds  * sd: the socket descriptor to have a new association added to.
48611da177e4SLinus Torvalds  *
48621da177e4SLinus Torvalds  * nam: the address structure (either struct sockaddr_in or struct
48631da177e4SLinus Torvalds  *    sockaddr_in6 defined in RFC2553 [7]).
48641da177e4SLinus Torvalds  *
48651da177e4SLinus Torvalds  * len: the size of the address.
48661da177e4SLinus Torvalds  */
4867dda91928SDaniel Borkmann static int sctp_connect(struct sock *sk, struct sockaddr *addr,
4868644fbdeaSXin Long 			int addr_len, int flags)
48691da177e4SLinus Torvalds {
48703f7a87d2SFrank Filz 	struct sctp_af *af;
48719b6c0887SXin Long 	int err = -EINVAL;
48721da177e4SLinus Torvalds 
4873048ed4b6Swangweidong 	lock_sock(sk);
4874bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk,
4875bb33381dSDaniel Borkmann 		 addr, addr_len);
48761da177e4SLinus Torvalds 
48773f7a87d2SFrank Filz 	/* Validate addr_len before calling common connect/connectx routine. */
48789b6c0887SXin Long 	af = sctp_get_af_specific(addr->sa_family);
48799b6c0887SXin Long 	if (af && addr_len >= af->sockaddr_len)
4880644fbdeaSXin Long 		err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL);
48811da177e4SLinus Torvalds 
4882048ed4b6Swangweidong 	release_sock(sk);
48831da177e4SLinus Torvalds 	return err;
48841da177e4SLinus Torvalds }
48851da177e4SLinus Torvalds 
4886644fbdeaSXin Long int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr,
4887644fbdeaSXin Long 		      int addr_len, int flags)
4888644fbdeaSXin Long {
4889644fbdeaSXin Long 	if (addr_len < sizeof(uaddr->sa_family))
4890644fbdeaSXin Long 		return -EINVAL;
4891644fbdeaSXin Long 
4892644fbdeaSXin Long 	if (uaddr->sa_family == AF_UNSPEC)
4893644fbdeaSXin Long 		return -EOPNOTSUPP;
4894644fbdeaSXin Long 
4895644fbdeaSXin Long 	return sctp_connect(sock->sk, uaddr, addr_len, flags);
4896644fbdeaSXin Long }
4897644fbdeaSXin Long 
48981da177e4SLinus Torvalds /* FIXME: Write comments. */
4899dda91928SDaniel Borkmann static int sctp_disconnect(struct sock *sk, int flags)
49001da177e4SLinus Torvalds {
49011da177e4SLinus Torvalds 	return -EOPNOTSUPP; /* STUB */
49021da177e4SLinus Torvalds }
49031da177e4SLinus Torvalds 
49041da177e4SLinus Torvalds /* 4.1.4 accept() - TCP Style Syntax
49051da177e4SLinus Torvalds  *
49061da177e4SLinus Torvalds  * Applications use accept() call to remove an established SCTP
49071da177e4SLinus Torvalds  * association from the accept queue of the endpoint.  A new socket
49081da177e4SLinus Torvalds  * descriptor will be returned from accept() to represent the newly
49091da177e4SLinus Torvalds  * formed association.
49101da177e4SLinus Torvalds  */
4911cdfbabfbSDavid Howells static struct sock *sctp_accept(struct sock *sk, int flags, int *err, bool kern)
49121da177e4SLinus Torvalds {
49131da177e4SLinus Torvalds 	struct sctp_sock *sp;
49141da177e4SLinus Torvalds 	struct sctp_endpoint *ep;
49151da177e4SLinus Torvalds 	struct sock *newsk = NULL;
49161da177e4SLinus Torvalds 	struct sctp_association *asoc;
49171da177e4SLinus Torvalds 	long timeo;
49181da177e4SLinus Torvalds 	int error = 0;
49191da177e4SLinus Torvalds 
4920048ed4b6Swangweidong 	lock_sock(sk);
49211da177e4SLinus Torvalds 
49221da177e4SLinus Torvalds 	sp = sctp_sk(sk);
49231da177e4SLinus Torvalds 	ep = sp->ep;
49241da177e4SLinus Torvalds 
49251da177e4SLinus Torvalds 	if (!sctp_style(sk, TCP)) {
49261da177e4SLinus Torvalds 		error = -EOPNOTSUPP;
49271da177e4SLinus Torvalds 		goto out;
49281da177e4SLinus Torvalds 	}
49291da177e4SLinus Torvalds 
49301da177e4SLinus Torvalds 	if (!sctp_sstate(sk, LISTENING)) {
49311da177e4SLinus Torvalds 		error = -EINVAL;
49321da177e4SLinus Torvalds 		goto out;
49331da177e4SLinus Torvalds 	}
49341da177e4SLinus Torvalds 
49358abfedd8SSridhar Samudrala 	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
49361da177e4SLinus Torvalds 
49371da177e4SLinus Torvalds 	error = sctp_wait_for_accept(sk, timeo);
49381da177e4SLinus Torvalds 	if (error)
49391da177e4SLinus Torvalds 		goto out;
49401da177e4SLinus Torvalds 
49411da177e4SLinus Torvalds 	/* We treat the list of associations on the endpoint as the accept
49421da177e4SLinus Torvalds 	 * queue and pick the first association on the list.
49431da177e4SLinus Torvalds 	 */
49441da177e4SLinus Torvalds 	asoc = list_entry(ep->asocs.next, struct sctp_association, asocs);
49451da177e4SLinus Torvalds 
4946cdfbabfbSDavid Howells 	newsk = sp->pf->create_accept_sk(sk, asoc, kern);
49471da177e4SLinus Torvalds 	if (!newsk) {
49481da177e4SLinus Torvalds 		error = -ENOMEM;
49491da177e4SLinus Torvalds 		goto out;
49501da177e4SLinus Torvalds 	}
49511da177e4SLinus Torvalds 
49521da177e4SLinus Torvalds 	/* Populate the fields of the newsk from the oldsk and migrate the
49531da177e4SLinus Torvalds 	 * asoc to the newsk.
49541da177e4SLinus Torvalds 	 */
495589664c62SXin Long 	error = sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP);
495689664c62SXin Long 	if (error) {
495789664c62SXin Long 		sk_common_release(newsk);
495889664c62SXin Long 		newsk = NULL;
495989664c62SXin Long 	}
49601da177e4SLinus Torvalds 
49611da177e4SLinus Torvalds out:
4962048ed4b6Swangweidong 	release_sock(sk);
49631da177e4SLinus Torvalds 	*err = error;
49641da177e4SLinus Torvalds 	return newsk;
49651da177e4SLinus Torvalds }
49661da177e4SLinus Torvalds 
49671da177e4SLinus Torvalds /* The SCTP ioctl handler. */
4968dda91928SDaniel Borkmann static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
49691da177e4SLinus Torvalds {
497065040c33SDiego Elio 'Flameeyes' Pettenò 	int rc = -ENOTCONN;
497165040c33SDiego Elio 'Flameeyes' Pettenò 
4972048ed4b6Swangweidong 	lock_sock(sk);
497365040c33SDiego Elio 'Flameeyes' Pettenò 
497465040c33SDiego Elio 'Flameeyes' Pettenò 	/*
497565040c33SDiego Elio 'Flameeyes' Pettenò 	 * SEQPACKET-style sockets in LISTENING state are valid, for
497665040c33SDiego Elio 'Flameeyes' Pettenò 	 * SCTP, so only discard TCP-style sockets in LISTENING state.
497765040c33SDiego Elio 'Flameeyes' Pettenò 	 */
497865040c33SDiego Elio 'Flameeyes' Pettenò 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
497965040c33SDiego Elio 'Flameeyes' Pettenò 		goto out;
498065040c33SDiego Elio 'Flameeyes' Pettenò 
498165040c33SDiego Elio 'Flameeyes' Pettenò 	switch (cmd) {
498265040c33SDiego Elio 'Flameeyes' Pettenò 	case SIOCINQ: {
498365040c33SDiego Elio 'Flameeyes' Pettenò 		struct sk_buff *skb;
498465040c33SDiego Elio 'Flameeyes' Pettenò 		unsigned int amount = 0;
498565040c33SDiego Elio 'Flameeyes' Pettenò 
498665040c33SDiego Elio 'Flameeyes' Pettenò 		skb = skb_peek(&sk->sk_receive_queue);
498765040c33SDiego Elio 'Flameeyes' Pettenò 		if (skb != NULL) {
498865040c33SDiego Elio 'Flameeyes' Pettenò 			/*
498965040c33SDiego Elio 'Flameeyes' Pettenò 			 * We will only return the amount of this packet since
499065040c33SDiego Elio 'Flameeyes' Pettenò 			 * that is all that will be read.
499165040c33SDiego Elio 'Flameeyes' Pettenò 			 */
499265040c33SDiego Elio 'Flameeyes' Pettenò 			amount = skb->len;
499365040c33SDiego Elio 'Flameeyes' Pettenò 		}
499465040c33SDiego Elio 'Flameeyes' Pettenò 		rc = put_user(amount, (int __user *)arg);
499565040c33SDiego Elio 'Flameeyes' Pettenò 		break;
49969a7241c2SDavid S. Miller 	}
499765040c33SDiego Elio 'Flameeyes' Pettenò 	default:
499865040c33SDiego Elio 'Flameeyes' Pettenò 		rc = -ENOIOCTLCMD;
499965040c33SDiego Elio 'Flameeyes' Pettenò 		break;
500065040c33SDiego Elio 'Flameeyes' Pettenò 	}
500165040c33SDiego Elio 'Flameeyes' Pettenò out:
5002048ed4b6Swangweidong 	release_sock(sk);
500365040c33SDiego Elio 'Flameeyes' Pettenò 	return rc;
50041da177e4SLinus Torvalds }
50051da177e4SLinus Torvalds 
50061da177e4SLinus Torvalds /* This is the function which gets called during socket creation to
50071da177e4SLinus Torvalds  * initialized the SCTP-specific portion of the sock.
50081da177e4SLinus Torvalds  * The sock structure should already be zero-filled memory.
50091da177e4SLinus Torvalds  */
5010dda91928SDaniel Borkmann static int sctp_init_sock(struct sock *sk)
50111da177e4SLinus Torvalds {
5012e1fc3b14SEric W. Biederman 	struct net *net = sock_net(sk);
50131da177e4SLinus Torvalds 	struct sctp_sock *sp;
50141da177e4SLinus Torvalds 
5015bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p\n", __func__, sk);
50161da177e4SLinus Torvalds 
50171da177e4SLinus Torvalds 	sp = sctp_sk(sk);
50181da177e4SLinus Torvalds 
50191da177e4SLinus Torvalds 	/* Initialize the SCTP per socket area.  */
50201da177e4SLinus Torvalds 	switch (sk->sk_type) {
50211da177e4SLinus Torvalds 	case SOCK_SEQPACKET:
50221da177e4SLinus Torvalds 		sp->type = SCTP_SOCKET_UDP;
50231da177e4SLinus Torvalds 		break;
50241da177e4SLinus Torvalds 	case SOCK_STREAM:
50251da177e4SLinus Torvalds 		sp->type = SCTP_SOCKET_TCP;
50261da177e4SLinus Torvalds 		break;
50271da177e4SLinus Torvalds 	default:
50281da177e4SLinus Torvalds 		return -ESOCKTNOSUPPORT;
50291da177e4SLinus Torvalds 	}
50301da177e4SLinus Torvalds 
503190017accSMarcelo Ricardo Leitner 	sk->sk_gso_type = SKB_GSO_SCTP;
503290017accSMarcelo Ricardo Leitner 
50331da177e4SLinus Torvalds 	/* Initialize default send parameters. These parameters can be
50341da177e4SLinus Torvalds 	 * modified with the SCTP_DEFAULT_SEND_PARAM socket option.
50351da177e4SLinus Torvalds 	 */
50361da177e4SLinus Torvalds 	sp->default_stream = 0;
50371da177e4SLinus Torvalds 	sp->default_ppid = 0;
50381da177e4SLinus Torvalds 	sp->default_flags = 0;
50391da177e4SLinus Torvalds 	sp->default_context = 0;
50401da177e4SLinus Torvalds 	sp->default_timetolive = 0;
50411da177e4SLinus Torvalds 
50426ab792f5SIvan Skytte Jorgensen 	sp->default_rcv_context = 0;
5043e1fc3b14SEric W. Biederman 	sp->max_burst = net->sctp.max_burst;
50446ab792f5SIvan Skytte Jorgensen 
50453c68198eSNeil Horman 	sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg;
50463c68198eSNeil Horman 
50471da177e4SLinus Torvalds 	/* Initialize default setup parameters. These parameters
50481da177e4SLinus Torvalds 	 * can be modified with the SCTP_INITMSG socket option or
50491da177e4SLinus Torvalds 	 * overridden by the SCTP_INIT CMSG.
50501da177e4SLinus Torvalds 	 */
50511da177e4SLinus Torvalds 	sp->initmsg.sinit_num_ostreams   = sctp_max_outstreams;
50521da177e4SLinus Torvalds 	sp->initmsg.sinit_max_instreams  = sctp_max_instreams;
5053e1fc3b14SEric W. Biederman 	sp->initmsg.sinit_max_attempts   = net->sctp.max_retrans_init;
5054e1fc3b14SEric W. Biederman 	sp->initmsg.sinit_max_init_timeo = net->sctp.rto_max;
50551da177e4SLinus Torvalds 
50561da177e4SLinus Torvalds 	/* Initialize default RTO related parameters.  These parameters can
50571da177e4SLinus Torvalds 	 * be modified for with the SCTP_RTOINFO socket option.
50581da177e4SLinus Torvalds 	 */
5059e1fc3b14SEric W. Biederman 	sp->rtoinfo.srto_initial = net->sctp.rto_initial;
5060e1fc3b14SEric W. Biederman 	sp->rtoinfo.srto_max     = net->sctp.rto_max;
5061e1fc3b14SEric W. Biederman 	sp->rtoinfo.srto_min     = net->sctp.rto_min;
50621da177e4SLinus Torvalds 
50631da177e4SLinus Torvalds 	/* Initialize default association related parameters. These parameters
50641da177e4SLinus Torvalds 	 * can be modified with the SCTP_ASSOCINFO socket option.
50651da177e4SLinus Torvalds 	 */
5066e1fc3b14SEric W. Biederman 	sp->assocparams.sasoc_asocmaxrxt = net->sctp.max_retrans_association;
50671da177e4SLinus Torvalds 	sp->assocparams.sasoc_number_peer_destinations = 0;
50681da177e4SLinus Torvalds 	sp->assocparams.sasoc_peer_rwnd = 0;
50691da177e4SLinus Torvalds 	sp->assocparams.sasoc_local_rwnd = 0;
5070e1fc3b14SEric W. Biederman 	sp->assocparams.sasoc_cookie_life = net->sctp.valid_cookie_life;
50711da177e4SLinus Torvalds 
50721da177e4SLinus Torvalds 	/* Initialize default event subscriptions. By default, all the
50731da177e4SLinus Torvalds 	 * options are off.
50741da177e4SLinus Torvalds 	 */
50752cc0eeb6SXin Long 	sp->subscribe = 0;
50761da177e4SLinus Torvalds 
50771da177e4SLinus Torvalds 	/* Default Peer Address Parameters.  These defaults can
50781da177e4SLinus Torvalds 	 * be modified via SCTP_PEER_ADDR_PARAMS
50791da177e4SLinus Torvalds 	 */
5080e1fc3b14SEric W. Biederman 	sp->hbinterval  = net->sctp.hb_interval;
5081e1fc3b14SEric W. Biederman 	sp->pathmaxrxt  = net->sctp.max_retrans_path;
50828add543eSXin Long 	sp->pf_retrans  = net->sctp.pf_retrans;
508334515e94SXin Long 	sp->ps_retrans  = net->sctp.ps_retrans;
5084aef587beSXin Long 	sp->pf_expose   = net->sctp.pf_expose;
50854e2d52bfSwangweidong 	sp->pathmtu     = 0; /* allow default discovery */
5086e1fc3b14SEric W. Biederman 	sp->sackdelay   = net->sctp.sack_timeout;
50877bfe8bdbSVlad Yasevich 	sp->sackfreq	= 2;
508852ccb8e9SFrank Filz 	sp->param_flags = SPP_HB_ENABLE |
508952ccb8e9SFrank Filz 			  SPP_PMTUD_ENABLE |
509052ccb8e9SFrank Filz 			  SPP_SACKDELAY_ENABLE;
50917efba10dSXin Long 	sp->default_ss = SCTP_SS_DEFAULT;
50921da177e4SLinus Torvalds 
50931da177e4SLinus Torvalds 	/* If enabled no SCTP message fragmentation will be performed.
50941da177e4SLinus Torvalds 	 * Configure through SCTP_DISABLE_FRAGMENTS socket option.
50951da177e4SLinus Torvalds 	 */
50961da177e4SLinus Torvalds 	sp->disable_fragments = 0;
50971da177e4SLinus Torvalds 
5098208edef6SSridhar Samudrala 	/* Enable Nagle algorithm by default.  */
5099208edef6SSridhar Samudrala 	sp->nodelay           = 0;
51001da177e4SLinus Torvalds 
51010d3a421dSGeir Ola Vaagland 	sp->recvrcvinfo = 0;
51022347c80fSGeir Ola Vaagland 	sp->recvnxtinfo = 0;
51030d3a421dSGeir Ola Vaagland 
51041da177e4SLinus Torvalds 	/* Enable by default. */
51051da177e4SLinus Torvalds 	sp->v4mapped          = 1;
51061da177e4SLinus Torvalds 
51071da177e4SLinus Torvalds 	/* Auto-close idle associations after the configured
51081da177e4SLinus Torvalds 	 * number of seconds.  A value of 0 disables this
51091da177e4SLinus Torvalds 	 * feature.  Configure through the SCTP_AUTOCLOSE socket option,
51101da177e4SLinus Torvalds 	 * for UDP-style sockets only.
51111da177e4SLinus Torvalds 	 */
51121da177e4SLinus Torvalds 	sp->autoclose         = 0;
51131da177e4SLinus Torvalds 
51141da177e4SLinus Torvalds 	/* User specified fragmentation limit. */
51151da177e4SLinus Torvalds 	sp->user_frag         = 0;
51161da177e4SLinus Torvalds 
51170f3fffd8SIvan Skytte Jorgensen 	sp->adaptation_ind = 0;
51181da177e4SLinus Torvalds 
51191da177e4SLinus Torvalds 	sp->pf = sctp_get_pf_specific(sk->sk_family);
51201da177e4SLinus Torvalds 
51211da177e4SLinus Torvalds 	/* Control variables for partial data delivery. */
5122b6e1331fSVlad Yasevich 	atomic_set(&sp->pd_mode, 0);
51231da177e4SLinus Torvalds 	skb_queue_head_init(&sp->pd_lobby);
5124b6e1331fSVlad Yasevich 	sp->frag_interleave = 0;
51251da177e4SLinus Torvalds 
51261da177e4SLinus Torvalds 	/* Create a per socket endpoint structure.  Even if we
51271da177e4SLinus Torvalds 	 * change the data structure relationships, this may still
51281da177e4SLinus Torvalds 	 * be useful for storing pre-connect address information.
51291da177e4SLinus Torvalds 	 */
5130c164b838SDaniel Borkmann 	sp->ep = sctp_endpoint_new(sk, GFP_KERNEL);
5131c164b838SDaniel Borkmann 	if (!sp->ep)
51321da177e4SLinus Torvalds 		return -ENOMEM;
51331da177e4SLinus Torvalds 
51341da177e4SLinus Torvalds 	sp->hmac = NULL;
51351da177e4SLinus Torvalds 
51360a2fbac1SDaniel Borkmann 	sk->sk_destruct = sctp_destruct_sock;
51370a2fbac1SDaniel Borkmann 
51381da177e4SLinus Torvalds 	SCTP_DBG_OBJCNT_INC(sock);
51396f756a8cSDavid S. Miller 
51406f756a8cSDavid S. Miller 	local_bh_disable();
51418cb38a60STonghao Zhang 	sk_sockets_allocated_inc(sk);
5142e1fc3b14SEric W. Biederman 	sock_prot_inuse_add(net, sk->sk_prot, 1);
51432d45a02dSMarcelo Ricardo Leitner 
51442d45a02dSMarcelo Ricardo Leitner 	/* Nothing can fail after this block, otherwise
51452d45a02dSMarcelo Ricardo Leitner 	 * sctp_destroy_sock() will be called without addr_wq_lock held
51462d45a02dSMarcelo Ricardo Leitner 	 */
5147e1fc3b14SEric W. Biederman 	if (net->sctp.default_auto_asconf) {
51482d45a02dSMarcelo Ricardo Leitner 		spin_lock(&sock_net(sk)->sctp.addr_wq_lock);
51499f7d653bSMichio Honda 		list_add_tail(&sp->auto_asconf_list,
5150e1fc3b14SEric W. Biederman 		    &net->sctp.auto_asconf_splist);
51519f7d653bSMichio Honda 		sp->do_auto_asconf = 1;
51522d45a02dSMarcelo Ricardo Leitner 		spin_unlock(&sock_net(sk)->sctp.addr_wq_lock);
51532d45a02dSMarcelo Ricardo Leitner 	} else {
51549f7d653bSMichio Honda 		sp->do_auto_asconf = 0;
51552d45a02dSMarcelo Ricardo Leitner 	}
51562d45a02dSMarcelo Ricardo Leitner 
51576f756a8cSDavid S. Miller 	local_bh_enable();
51586f756a8cSDavid S. Miller 
51591da177e4SLinus Torvalds 	return 0;
51601da177e4SLinus Torvalds }
51611da177e4SLinus Torvalds 
51622d45a02dSMarcelo Ricardo Leitner /* Cleanup any SCTP per socket resources. Must be called with
51632d45a02dSMarcelo Ricardo Leitner  * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true
51642d45a02dSMarcelo Ricardo Leitner  */
5165dda91928SDaniel Borkmann static void sctp_destroy_sock(struct sock *sk)
51661da177e4SLinus Torvalds {
51679f7d653bSMichio Honda 	struct sctp_sock *sp;
51681da177e4SLinus Torvalds 
5169bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p\n", __func__, sk);
51701da177e4SLinus Torvalds 
51711da177e4SLinus Torvalds 	/* Release our hold on the endpoint. */
51729f7d653bSMichio Honda 	sp = sctp_sk(sk);
51731abd165eSDaniel Borkmann 	/* This could happen during socket init, thus we bail out
51741abd165eSDaniel Borkmann 	 * early, since the rest of the below is not setup either.
51751abd165eSDaniel Borkmann 	 */
51761abd165eSDaniel Borkmann 	if (sp->ep == NULL)
51771abd165eSDaniel Borkmann 		return;
51781abd165eSDaniel Borkmann 
51799f7d653bSMichio Honda 	if (sp->do_auto_asconf) {
51809f7d653bSMichio Honda 		sp->do_auto_asconf = 0;
51819f7d653bSMichio Honda 		list_del(&sp->auto_asconf_list);
51829f7d653bSMichio Honda 	}
51839f7d653bSMichio Honda 	sctp_endpoint_free(sp->ep);
51845bc0b3bfSEric Dumazet 	local_bh_disable();
51858cb38a60STonghao Zhang 	sk_sockets_allocated_dec(sk);
51869a57f7faSEric Dumazet 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
51875bc0b3bfSEric Dumazet 	local_bh_enable();
51881da177e4SLinus Torvalds }
51891da177e4SLinus Torvalds 
51900a2fbac1SDaniel Borkmann /* Triggered when there are no references on the socket anymore */
51910a2fbac1SDaniel Borkmann static void sctp_destruct_sock(struct sock *sk)
51920a2fbac1SDaniel Borkmann {
51930a2fbac1SDaniel Borkmann 	struct sctp_sock *sp = sctp_sk(sk);
51940a2fbac1SDaniel Borkmann 
51950a2fbac1SDaniel Borkmann 	/* Free up the HMAC transform. */
51965821c769SHerbert Xu 	crypto_free_shash(sp->hmac);
51970a2fbac1SDaniel Borkmann 
51980a2fbac1SDaniel Borkmann 	inet_sock_destruct(sk);
51990a2fbac1SDaniel Borkmann }
52000a2fbac1SDaniel Borkmann 
52011da177e4SLinus Torvalds /* API 4.1.7 shutdown() - TCP Style Syntax
52021da177e4SLinus Torvalds  *     int shutdown(int socket, int how);
52031da177e4SLinus Torvalds  *
52041da177e4SLinus Torvalds  *     sd      - the socket descriptor of the association to be closed.
52051da177e4SLinus Torvalds  *     how     - Specifies the type of shutdown.  The  values  are
52061da177e4SLinus Torvalds  *               as follows:
52071da177e4SLinus Torvalds  *               SHUT_RD
52081da177e4SLinus Torvalds  *                     Disables further receive operations. No SCTP
52091da177e4SLinus Torvalds  *                     protocol action is taken.
52101da177e4SLinus Torvalds  *               SHUT_WR
52111da177e4SLinus Torvalds  *                     Disables further send operations, and initiates
52121da177e4SLinus Torvalds  *                     the SCTP shutdown sequence.
52131da177e4SLinus Torvalds  *               SHUT_RDWR
52141da177e4SLinus Torvalds  *                     Disables further send  and  receive  operations
52151da177e4SLinus Torvalds  *                     and initiates the SCTP shutdown sequence.
52161da177e4SLinus Torvalds  */
5217dda91928SDaniel Borkmann static void sctp_shutdown(struct sock *sk, int how)
52181da177e4SLinus Torvalds {
521955e26eb9SEric W. Biederman 	struct net *net = sock_net(sk);
52201da177e4SLinus Torvalds 	struct sctp_endpoint *ep;
52211da177e4SLinus Torvalds 
52221da177e4SLinus Torvalds 	if (!sctp_style(sk, TCP))
52231da177e4SLinus Torvalds 		return;
52241da177e4SLinus Torvalds 
52251da177e4SLinus Torvalds 	ep = sctp_sk(sk)->ep;
52265bf35ddfSXin Long 	if (how & SEND_SHUTDOWN && !list_empty(&ep->asocs)) {
52275bf35ddfSXin Long 		struct sctp_association *asoc;
52285bf35ddfSXin Long 
5229cbabf463SYafang Shao 		inet_sk_set_state(sk, SCTP_SS_CLOSING);
52301da177e4SLinus Torvalds 		asoc = list_entry(ep->asocs.next,
52311da177e4SLinus Torvalds 				  struct sctp_association, asocs);
523255e26eb9SEric W. Biederman 		sctp_primitive_SHUTDOWN(net, asoc, NULL);
52331da177e4SLinus Torvalds 	}
52341da177e4SLinus Torvalds }
52351da177e4SLinus Torvalds 
523652c52a61SXin Long int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
523752c52a61SXin Long 		       struct sctp_info *info)
523852c52a61SXin Long {
523952c52a61SXin Long 	struct sctp_transport *prim;
524052c52a61SXin Long 	struct list_head *pos;
524152c52a61SXin Long 	int mask;
524252c52a61SXin Long 
524352c52a61SXin Long 	memset(info, 0, sizeof(*info));
524452c52a61SXin Long 	if (!asoc) {
524552c52a61SXin Long 		struct sctp_sock *sp = sctp_sk(sk);
524652c52a61SXin Long 
524752c52a61SXin Long 		info->sctpi_s_autoclose = sp->autoclose;
524852c52a61SXin Long 		info->sctpi_s_adaptation_ind = sp->adaptation_ind;
524952c52a61SXin Long 		info->sctpi_s_pd_point = sp->pd_point;
525052c52a61SXin Long 		info->sctpi_s_nodelay = sp->nodelay;
525152c52a61SXin Long 		info->sctpi_s_disable_fragments = sp->disable_fragments;
525252c52a61SXin Long 		info->sctpi_s_v4mapped = sp->v4mapped;
525352c52a61SXin Long 		info->sctpi_s_frag_interleave = sp->frag_interleave;
525440eb90e9SXin Long 		info->sctpi_s_type = sp->type;
525552c52a61SXin Long 
525652c52a61SXin Long 		return 0;
525752c52a61SXin Long 	}
525852c52a61SXin Long 
525952c52a61SXin Long 	info->sctpi_tag = asoc->c.my_vtag;
526052c52a61SXin Long 	info->sctpi_state = asoc->state;
526152c52a61SXin Long 	info->sctpi_rwnd = asoc->a_rwnd;
526252c52a61SXin Long 	info->sctpi_unackdata = asoc->unack_data;
526352c52a61SXin Long 	info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
5264cee360abSXin Long 	info->sctpi_instrms = asoc->stream.incnt;
5265cee360abSXin Long 	info->sctpi_outstrms = asoc->stream.outcnt;
526652c52a61SXin Long 	list_for_each(pos, &asoc->base.inqueue.in_chunk_list)
526752c52a61SXin Long 		info->sctpi_inqueue++;
526852c52a61SXin Long 	list_for_each(pos, &asoc->outqueue.out_chunk_list)
526952c52a61SXin Long 		info->sctpi_outqueue++;
527052c52a61SXin Long 	info->sctpi_overall_error = asoc->overall_error_count;
527152c52a61SXin Long 	info->sctpi_max_burst = asoc->max_burst;
527252c52a61SXin Long 	info->sctpi_maxseg = asoc->frag_point;
527352c52a61SXin Long 	info->sctpi_peer_rwnd = asoc->peer.rwnd;
527452c52a61SXin Long 	info->sctpi_peer_tag = asoc->c.peer_vtag;
527552c52a61SXin Long 
527652c52a61SXin Long 	mask = asoc->peer.ecn_capable << 1;
527752c52a61SXin Long 	mask = (mask | asoc->peer.ipv4_address) << 1;
527852c52a61SXin Long 	mask = (mask | asoc->peer.ipv6_address) << 1;
527952c52a61SXin Long 	mask = (mask | asoc->peer.hostname_address) << 1;
528052c52a61SXin Long 	mask = (mask | asoc->peer.asconf_capable) << 1;
528152c52a61SXin Long 	mask = (mask | asoc->peer.prsctp_capable) << 1;
528252c52a61SXin Long 	mask = (mask | asoc->peer.auth_capable);
528352c52a61SXin Long 	info->sctpi_peer_capable = mask;
528452c52a61SXin Long 	mask = asoc->peer.sack_needed << 1;
528552c52a61SXin Long 	mask = (mask | asoc->peer.sack_generation) << 1;
528652c52a61SXin Long 	mask = (mask | asoc->peer.zero_window_announced);
528752c52a61SXin Long 	info->sctpi_peer_sack = mask;
528852c52a61SXin Long 
528952c52a61SXin Long 	info->sctpi_isacks = asoc->stats.isacks;
529052c52a61SXin Long 	info->sctpi_osacks = asoc->stats.osacks;
529152c52a61SXin Long 	info->sctpi_opackets = asoc->stats.opackets;
529252c52a61SXin Long 	info->sctpi_ipackets = asoc->stats.ipackets;
529352c52a61SXin Long 	info->sctpi_rtxchunks = asoc->stats.rtxchunks;
529452c52a61SXin Long 	info->sctpi_outofseqtsns = asoc->stats.outofseqtsns;
529552c52a61SXin Long 	info->sctpi_idupchunks = asoc->stats.idupchunks;
529652c52a61SXin Long 	info->sctpi_gapcnt = asoc->stats.gapcnt;
529752c52a61SXin Long 	info->sctpi_ouodchunks = asoc->stats.ouodchunks;
529852c52a61SXin Long 	info->sctpi_iuodchunks = asoc->stats.iuodchunks;
529952c52a61SXin Long 	info->sctpi_oodchunks = asoc->stats.oodchunks;
530052c52a61SXin Long 	info->sctpi_iodchunks = asoc->stats.iodchunks;
530152c52a61SXin Long 	info->sctpi_octrlchunks = asoc->stats.octrlchunks;
530252c52a61SXin Long 	info->sctpi_ictrlchunks = asoc->stats.ictrlchunks;
530352c52a61SXin Long 
530452c52a61SXin Long 	prim = asoc->peer.primary_path;
5305ee6c88bbSStefano Brivio 	memcpy(&info->sctpi_p_address, &prim->ipaddr, sizeof(prim->ipaddr));
530652c52a61SXin Long 	info->sctpi_p_state = prim->state;
530752c52a61SXin Long 	info->sctpi_p_cwnd = prim->cwnd;
530852c52a61SXin Long 	info->sctpi_p_srtt = prim->srtt;
530952c52a61SXin Long 	info->sctpi_p_rto = jiffies_to_msecs(prim->rto);
531052c52a61SXin Long 	info->sctpi_p_hbinterval = prim->hbinterval;
531152c52a61SXin Long 	info->sctpi_p_pathmaxrxt = prim->pathmaxrxt;
531252c52a61SXin Long 	info->sctpi_p_sackdelay = jiffies_to_msecs(prim->sackdelay);
531352c52a61SXin Long 	info->sctpi_p_ssthresh = prim->ssthresh;
531452c52a61SXin Long 	info->sctpi_p_partial_bytes_acked = prim->partial_bytes_acked;
531552c52a61SXin Long 	info->sctpi_p_flight_size = prim->flight_size;
531652c52a61SXin Long 	info->sctpi_p_error = prim->error_count;
531752c52a61SXin Long 
531852c52a61SXin Long 	return 0;
531952c52a61SXin Long }
532052c52a61SXin Long EXPORT_SYMBOL_GPL(sctp_get_sctp_info);
532152c52a61SXin Long 
5322626d16f5SXin Long /* use callback to avoid exporting the core structure */
53236c72b774SJules Irenge void sctp_transport_walk_start(struct rhashtable_iter *iter) __acquires(RCU)
5324626d16f5SXin Long {
53257fda702fSXin Long 	rhltable_walk_enter(&sctp_transport_hashtable, iter);
5326626d16f5SXin Long 
532797a6ec4aSTom Herbert 	rhashtable_walk_start(iter);
5328626d16f5SXin Long }
5329626d16f5SXin Long 
5330b77b4f63SJules Irenge void sctp_transport_walk_stop(struct rhashtable_iter *iter) __releases(RCU)
5331626d16f5SXin Long {
5332626d16f5SXin Long 	rhashtable_walk_stop(iter);
5333626d16f5SXin Long 	rhashtable_walk_exit(iter);
5334626d16f5SXin Long }
5335626d16f5SXin Long 
5336626d16f5SXin Long struct sctp_transport *sctp_transport_get_next(struct net *net,
5337626d16f5SXin Long 					       struct rhashtable_iter *iter)
5338626d16f5SXin Long {
5339626d16f5SXin Long 	struct sctp_transport *t;
5340626d16f5SXin Long 
5341626d16f5SXin Long 	t = rhashtable_walk_next(iter);
5342626d16f5SXin Long 	for (; t; t = rhashtable_walk_next(iter)) {
5343626d16f5SXin Long 		if (IS_ERR(t)) {
5344626d16f5SXin Long 			if (PTR_ERR(t) == -EAGAIN)
5345626d16f5SXin Long 				continue;
5346626d16f5SXin Long 			break;
5347626d16f5SXin Long 		}
5348626d16f5SXin Long 
5349bab1be79SXin Long 		if (!sctp_transport_hold(t))
5350bab1be79SXin Long 			continue;
5351bab1be79SXin Long 
53524e7696d9SXin Long 		if (net_eq(t->asoc->base.net, net) &&
5353626d16f5SXin Long 		    t->asoc->peer.primary_path == t)
5354626d16f5SXin Long 			break;
5355bab1be79SXin Long 
5356bab1be79SXin Long 		sctp_transport_put(t);
5357626d16f5SXin Long 	}
5358626d16f5SXin Long 
5359626d16f5SXin Long 	return t;
5360626d16f5SXin Long }
5361626d16f5SXin Long 
5362626d16f5SXin Long struct sctp_transport *sctp_transport_get_idx(struct net *net,
5363626d16f5SXin Long 					      struct rhashtable_iter *iter,
5364626d16f5SXin Long 					      int pos)
5365626d16f5SXin Long {
5366bab1be79SXin Long 	struct sctp_transport *t;
5367626d16f5SXin Long 
5368bab1be79SXin Long 	if (!pos)
5369bab1be79SXin Long 		return SEQ_START_TOKEN;
5370626d16f5SXin Long 
5371bab1be79SXin Long 	while ((t = sctp_transport_get_next(net, iter)) && !IS_ERR(t)) {
5372bab1be79SXin Long 		if (!--pos)
5373bab1be79SXin Long 			break;
5374bab1be79SXin Long 		sctp_transport_put(t);
5375bab1be79SXin Long 	}
5376bab1be79SXin Long 
5377bab1be79SXin Long 	return t;
5378626d16f5SXin Long }
5379626d16f5SXin Long 
5380626d16f5SXin Long int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *),
5381626d16f5SXin Long 			   void *p) {
5382626d16f5SXin Long 	int err = 0;
5383626d16f5SXin Long 	int hash = 0;
5384626d16f5SXin Long 	struct sctp_ep_common *epb;
5385626d16f5SXin Long 	struct sctp_hashbucket *head;
5386626d16f5SXin Long 
5387626d16f5SXin Long 	for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize;
5388626d16f5SXin Long 	     hash++, head++) {
5389581409daSXin Long 		read_lock_bh(&head->lock);
5390626d16f5SXin Long 		sctp_for_each_hentry(epb, &head->chain) {
5391626d16f5SXin Long 			err = cb(sctp_ep(epb), p);
5392626d16f5SXin Long 			if (err)
5393626d16f5SXin Long 				break;
5394626d16f5SXin Long 		}
5395581409daSXin Long 		read_unlock_bh(&head->lock);
5396626d16f5SXin Long 	}
5397626d16f5SXin Long 
5398626d16f5SXin Long 	return err;
5399626d16f5SXin Long }
5400626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_for_each_endpoint);
5401626d16f5SXin Long 
5402626d16f5SXin Long int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
5403626d16f5SXin Long 				  struct net *net,
5404626d16f5SXin Long 				  const union sctp_addr *laddr,
5405626d16f5SXin Long 				  const union sctp_addr *paddr, void *p)
5406626d16f5SXin Long {
5407626d16f5SXin Long 	struct sctp_transport *transport;
540808abb795SXin Long 	int err;
5409626d16f5SXin Long 
5410626d16f5SXin Long 	rcu_read_lock();
5411626d16f5SXin Long 	transport = sctp_addrs_lookup_transport(net, laddr, paddr);
5412626d16f5SXin Long 	rcu_read_unlock();
541308abb795SXin Long 	if (!transport)
541408abb795SXin Long 		return -ENOENT;
541508abb795SXin Long 
54161cceda78SXin Long 	err = cb(transport, p);
5417cd26da4fSXin Long 	sctp_transport_put(transport);
54181cceda78SXin Long 
5419626d16f5SXin Long 	return err;
5420626d16f5SXin Long }
5421626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_transport_lookup_process);
5422626d16f5SXin Long 
5423626d16f5SXin Long int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
5424d25adbebSXin Long 			    int (*cb_done)(struct sctp_transport *, void *),
5425d25adbebSXin Long 			    struct net *net, int *pos, void *p) {
5426626d16f5SXin Long 	struct rhashtable_iter hti;
5427d25adbebSXin Long 	struct sctp_transport *tsp;
5428d25adbebSXin Long 	int ret;
5429626d16f5SXin Long 
5430d25adbebSXin Long again:
5431f53d77e1SXin Long 	ret = 0;
543297a6ec4aSTom Herbert 	sctp_transport_walk_start(&hti);
5433626d16f5SXin Long 
5434d25adbebSXin Long 	tsp = sctp_transport_get_idx(net, &hti, *pos + 1);
5435d25adbebSXin Long 	for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) {
5436d25adbebSXin Long 		ret = cb(tsp, p);
5437d25adbebSXin Long 		if (ret)
5438626d16f5SXin Long 			break;
5439d25adbebSXin Long 		(*pos)++;
5440d25adbebSXin Long 		sctp_transport_put(tsp);
5441626d16f5SXin Long 	}
5442626d16f5SXin Long 	sctp_transport_walk_stop(&hti);
544353fa1036SXin Long 
5444d25adbebSXin Long 	if (ret) {
5445d25adbebSXin Long 		if (cb_done && !cb_done(tsp, p)) {
5446d25adbebSXin Long 			(*pos)++;
5447d25adbebSXin Long 			sctp_transport_put(tsp);
5448d25adbebSXin Long 			goto again;
5449d25adbebSXin Long 		}
5450d25adbebSXin Long 		sctp_transport_put(tsp);
5451d25adbebSXin Long 	}
5452d25adbebSXin Long 
5453d25adbebSXin Long 	return ret;
5454626d16f5SXin Long }
5455626d16f5SXin Long EXPORT_SYMBOL_GPL(sctp_for_each_transport);
5456626d16f5SXin Long 
54571da177e4SLinus Torvalds /* 7.2.1 Association Status (SCTP_STATUS)
54581da177e4SLinus Torvalds 
54591da177e4SLinus Torvalds  * Applications can retrieve current status information about an
54601da177e4SLinus Torvalds  * association, including association state, peer receiver window size,
54611da177e4SLinus Torvalds  * number of unacked data chunks, and number of data chunks pending
54621da177e4SLinus Torvalds  * receipt.  This information is read-only.
54631da177e4SLinus Torvalds  */
54641da177e4SLinus Torvalds static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
54651da177e4SLinus Torvalds 				       char __user *optval,
54661da177e4SLinus Torvalds 				       int __user *optlen)
54671da177e4SLinus Torvalds {
54681da177e4SLinus Torvalds 	struct sctp_status status;
54691da177e4SLinus Torvalds 	struct sctp_association *asoc = NULL;
54701da177e4SLinus Torvalds 	struct sctp_transport *transport;
54711da177e4SLinus Torvalds 	sctp_assoc_t associd;
54721da177e4SLinus Torvalds 	int retval = 0;
54731da177e4SLinus Torvalds 
5474408f22e8SNeil Horman 	if (len < sizeof(status)) {
54751da177e4SLinus Torvalds 		retval = -EINVAL;
54761da177e4SLinus Torvalds 		goto out;
54771da177e4SLinus Torvalds 	}
54781da177e4SLinus Torvalds 
5479408f22e8SNeil Horman 	len = sizeof(status);
5480408f22e8SNeil Horman 	if (copy_from_user(&status, optval, len)) {
54811da177e4SLinus Torvalds 		retval = -EFAULT;
54821da177e4SLinus Torvalds 		goto out;
54831da177e4SLinus Torvalds 	}
54841da177e4SLinus Torvalds 
54851da177e4SLinus Torvalds 	associd = status.sstat_assoc_id;
54861da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, associd);
54871da177e4SLinus Torvalds 	if (!asoc) {
54881da177e4SLinus Torvalds 		retval = -EINVAL;
54891da177e4SLinus Torvalds 		goto out;
54901da177e4SLinus Torvalds 	}
54911da177e4SLinus Torvalds 
54921da177e4SLinus Torvalds 	transport = asoc->peer.primary_path;
54931da177e4SLinus Torvalds 
54941da177e4SLinus Torvalds 	status.sstat_assoc_id = sctp_assoc2id(asoc);
549538ab1fa9SDaniel Borkmann 	status.sstat_state = sctp_assoc_to_state(asoc);
54961da177e4SLinus Torvalds 	status.sstat_rwnd =  asoc->peer.rwnd;
54971da177e4SLinus Torvalds 	status.sstat_unackdata = asoc->unack_data;
54981da177e4SLinus Torvalds 
54991da177e4SLinus Torvalds 	status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
5500cee360abSXin Long 	status.sstat_instrms = asoc->stream.incnt;
5501cee360abSXin Long 	status.sstat_outstrms = asoc->stream.outcnt;
55021da177e4SLinus Torvalds 	status.sstat_fragmentation_point = asoc->frag_point;
55031da177e4SLinus Torvalds 	status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
55048cec6b80SAl Viro 	memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr,
55058cec6b80SAl Viro 			transport->af_specific->sockaddr_len);
55061da177e4SLinus Torvalds 	/* Map ipv4 address into v4-mapped-on-v6 address.  */
5507299ee123SJason Gunthorpe 	sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk),
55081da177e4SLinus Torvalds 		(union sctp_addr *)&status.sstat_primary.spinfo_address);
55093f7a87d2SFrank Filz 	status.sstat_primary.spinfo_state = transport->state;
55101da177e4SLinus Torvalds 	status.sstat_primary.spinfo_cwnd = transport->cwnd;
55111da177e4SLinus Torvalds 	status.sstat_primary.spinfo_srtt = transport->srtt;
55121da177e4SLinus Torvalds 	status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto);
551352ccb8e9SFrank Filz 	status.sstat_primary.spinfo_mtu = transport->pathmtu;
55141da177e4SLinus Torvalds 
55153f7a87d2SFrank Filz 	if (status.sstat_primary.spinfo_state == SCTP_UNKNOWN)
55163f7a87d2SFrank Filz 		status.sstat_primary.spinfo_state = SCTP_ACTIVE;
55173f7a87d2SFrank Filz 
55181da177e4SLinus Torvalds 	if (put_user(len, optlen)) {
55191da177e4SLinus Torvalds 		retval = -EFAULT;
55201da177e4SLinus Torvalds 		goto out;
55211da177e4SLinus Torvalds 	}
55221da177e4SLinus Torvalds 
5523bb33381dSDaniel Borkmann 	pr_debug("%s: len:%d, state:%d, rwnd:%d, assoc_id:%d\n",
5524bb33381dSDaniel Borkmann 		 __func__, len, status.sstat_state, status.sstat_rwnd,
55251da177e4SLinus Torvalds 		 status.sstat_assoc_id);
55261da177e4SLinus Torvalds 
55271da177e4SLinus Torvalds 	if (copy_to_user(optval, &status, len)) {
55281da177e4SLinus Torvalds 		retval = -EFAULT;
55291da177e4SLinus Torvalds 		goto out;
55301da177e4SLinus Torvalds 	}
55311da177e4SLinus Torvalds 
55321da177e4SLinus Torvalds out:
5533a02cec21SEric Dumazet 	return retval;
55341da177e4SLinus Torvalds }
55351da177e4SLinus Torvalds 
55361da177e4SLinus Torvalds 
55371da177e4SLinus Torvalds /* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO)
55381da177e4SLinus Torvalds  *
55391da177e4SLinus Torvalds  * Applications can retrieve information about a specific peer address
55401da177e4SLinus Torvalds  * of an association, including its reachability state, congestion
55411da177e4SLinus Torvalds  * window, and retransmission timer values.  This information is
55421da177e4SLinus Torvalds  * read-only.
55431da177e4SLinus Torvalds  */
55441da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
55451da177e4SLinus Torvalds 					  char __user *optval,
55461da177e4SLinus Torvalds 					  int __user *optlen)
55471da177e4SLinus Torvalds {
55481da177e4SLinus Torvalds 	struct sctp_paddrinfo pinfo;
55491da177e4SLinus Torvalds 	struct sctp_transport *transport;
55501da177e4SLinus Torvalds 	int retval = 0;
55511da177e4SLinus Torvalds 
5552408f22e8SNeil Horman 	if (len < sizeof(pinfo)) {
55531da177e4SLinus Torvalds 		retval = -EINVAL;
55541da177e4SLinus Torvalds 		goto out;
55551da177e4SLinus Torvalds 	}
55561da177e4SLinus Torvalds 
5557408f22e8SNeil Horman 	len = sizeof(pinfo);
5558408f22e8SNeil Horman 	if (copy_from_user(&pinfo, optval, len)) {
55591da177e4SLinus Torvalds 		retval = -EFAULT;
55601da177e4SLinus Torvalds 		goto out;
55611da177e4SLinus Torvalds 	}
55621da177e4SLinus Torvalds 
55631da177e4SLinus Torvalds 	transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address,
55641da177e4SLinus Torvalds 					   pinfo.spinfo_assoc_id);
5565aef587beSXin Long 	if (!transport) {
5566aef587beSXin Long 		retval = -EINVAL;
5567aef587beSXin Long 		goto out;
5568aef587beSXin Long 	}
5569aef587beSXin Long 
5570aef587beSXin Long 	if (transport->state == SCTP_PF &&
5571aef587beSXin Long 	    transport->asoc->pf_expose == SCTP_PF_EXPOSE_DISABLE) {
5572aef587beSXin Long 		retval = -EACCES;
5573aef587beSXin Long 		goto out;
5574aef587beSXin Long 	}
55751da177e4SLinus Torvalds 
55761da177e4SLinus Torvalds 	pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
55773f7a87d2SFrank Filz 	pinfo.spinfo_state = transport->state;
55781da177e4SLinus Torvalds 	pinfo.spinfo_cwnd = transport->cwnd;
55791da177e4SLinus Torvalds 	pinfo.spinfo_srtt = transport->srtt;
55801da177e4SLinus Torvalds 	pinfo.spinfo_rto = jiffies_to_msecs(transport->rto);
558152ccb8e9SFrank Filz 	pinfo.spinfo_mtu = transport->pathmtu;
55821da177e4SLinus Torvalds 
55833f7a87d2SFrank Filz 	if (pinfo.spinfo_state == SCTP_UNKNOWN)
55843f7a87d2SFrank Filz 		pinfo.spinfo_state = SCTP_ACTIVE;
55853f7a87d2SFrank Filz 
55861da177e4SLinus Torvalds 	if (put_user(len, optlen)) {
55871da177e4SLinus Torvalds 		retval = -EFAULT;
55881da177e4SLinus Torvalds 		goto out;
55891da177e4SLinus Torvalds 	}
55901da177e4SLinus Torvalds 
55911da177e4SLinus Torvalds 	if (copy_to_user(optval, &pinfo, len)) {
55921da177e4SLinus Torvalds 		retval = -EFAULT;
55931da177e4SLinus Torvalds 		goto out;
55941da177e4SLinus Torvalds 	}
55951da177e4SLinus Torvalds 
55961da177e4SLinus Torvalds out:
5597a02cec21SEric Dumazet 	return retval;
55981da177e4SLinus Torvalds }
55991da177e4SLinus Torvalds 
56001da177e4SLinus Torvalds /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
56011da177e4SLinus Torvalds  *
56021da177e4SLinus Torvalds  * This option is a on/off flag.  If enabled no SCTP message
56031da177e4SLinus Torvalds  * fragmentation will be performed.  Instead if a message being sent
56041da177e4SLinus Torvalds  * exceeds the current PMTU size, the message will NOT be sent and
56051da177e4SLinus Torvalds  * instead a error will be indicated to the user.
56061da177e4SLinus Torvalds  */
56071da177e4SLinus Torvalds static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
56081da177e4SLinus Torvalds 					char __user *optval, int __user *optlen)
56091da177e4SLinus Torvalds {
56101da177e4SLinus Torvalds 	int val;
56111da177e4SLinus Torvalds 
56121da177e4SLinus Torvalds 	if (len < sizeof(int))
56131da177e4SLinus Torvalds 		return -EINVAL;
56141da177e4SLinus Torvalds 
56151da177e4SLinus Torvalds 	len = sizeof(int);
56161da177e4SLinus Torvalds 	val = (sctp_sk(sk)->disable_fragments == 1);
56171da177e4SLinus Torvalds 	if (put_user(len, optlen))
56181da177e4SLinus Torvalds 		return -EFAULT;
56191da177e4SLinus Torvalds 	if (copy_to_user(optval, &val, len))
56201da177e4SLinus Torvalds 		return -EFAULT;
56211da177e4SLinus Torvalds 	return 0;
56221da177e4SLinus Torvalds }
56231da177e4SLinus Torvalds 
56241da177e4SLinus Torvalds /* 7.1.15 Set notification and ancillary events (SCTP_EVENTS)
56251da177e4SLinus Torvalds  *
56261da177e4SLinus Torvalds  * This socket option is used to specify various notifications and
56271da177e4SLinus Torvalds  * ancillary data the user wishes to receive.
56281da177e4SLinus Torvalds  */
56291da177e4SLinus Torvalds static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval,
56301da177e4SLinus Torvalds 				  int __user *optlen)
56311da177e4SLinus Torvalds {
56322cc0eeb6SXin Long 	struct sctp_event_subscribe subscribe;
56332cc0eeb6SXin Long 	__u8 *sn_type = (__u8 *)&subscribe;
56342cc0eeb6SXin Long 	int i;
56352cc0eeb6SXin Long 
5636a4b8e71bSJiri Slaby 	if (len == 0)
56371da177e4SLinus Torvalds 		return -EINVAL;
5638acdd5985SThomas Graf 	if (len > sizeof(struct sctp_event_subscribe))
5639408f22e8SNeil Horman 		len = sizeof(struct sctp_event_subscribe);
5640408f22e8SNeil Horman 	if (put_user(len, optlen))
5641408f22e8SNeil Horman 		return -EFAULT;
56422cc0eeb6SXin Long 
56432cc0eeb6SXin Long 	for (i = 0; i < len; i++)
56442cc0eeb6SXin Long 		sn_type[i] = sctp_ulpevent_type_enabled(sctp_sk(sk)->subscribe,
56452cc0eeb6SXin Long 							SCTP_SN_TYPE_BASE + i);
56462cc0eeb6SXin Long 
56472cc0eeb6SXin Long 	if (copy_to_user(optval, &subscribe, len))
56481da177e4SLinus Torvalds 		return -EFAULT;
56492cc0eeb6SXin Long 
56501da177e4SLinus Torvalds 	return 0;
56511da177e4SLinus Torvalds }
56521da177e4SLinus Torvalds 
56531da177e4SLinus Torvalds /* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE)
56541da177e4SLinus Torvalds  *
56551da177e4SLinus Torvalds  * This socket option is applicable to the UDP-style socket only.  When
56561da177e4SLinus Torvalds  * set it will cause associations that are idle for more than the
56571da177e4SLinus Torvalds  * specified number of seconds to automatically close.  An association
56581da177e4SLinus Torvalds  * being idle is defined an association that has NOT sent or received
56591da177e4SLinus Torvalds  * user data.  The special value of '0' indicates that no automatic
56601da177e4SLinus Torvalds  * close of any associations should be performed.  The option expects an
56611da177e4SLinus Torvalds  * integer defining the number of seconds of idle time before an
56621da177e4SLinus Torvalds  * association is closed.
56631da177e4SLinus Torvalds  */
56641da177e4SLinus Torvalds static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optval, int __user *optlen)
56651da177e4SLinus Torvalds {
56661da177e4SLinus Torvalds 	/* Applicable to UDP-style socket only */
56671da177e4SLinus Torvalds 	if (sctp_style(sk, TCP))
56681da177e4SLinus Torvalds 		return -EOPNOTSUPP;
5669408f22e8SNeil Horman 	if (len < sizeof(int))
56701da177e4SLinus Torvalds 		return -EINVAL;
5671408f22e8SNeil Horman 	len = sizeof(int);
5672408f22e8SNeil Horman 	if (put_user(len, optlen))
5673408f22e8SNeil Horman 		return -EFAULT;
5674b2ce04c2SDavid Windsor 	if (put_user(sctp_sk(sk)->autoclose, (int __user *)optval))
56751da177e4SLinus Torvalds 		return -EFAULT;
56761da177e4SLinus Torvalds 	return 0;
56771da177e4SLinus Torvalds }
56781da177e4SLinus Torvalds 
56791da177e4SLinus Torvalds /* Helper routine to branch off an association to a new socket.  */
56800343c554SBenjamin Poirier int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
56811da177e4SLinus Torvalds {
56820343c554SBenjamin Poirier 	struct sctp_association *asoc = sctp_id2assoc(sk, id);
5683299ee123SJason Gunthorpe 	struct sctp_sock *sp = sctp_sk(sk);
56841da177e4SLinus Torvalds 	struct socket *sock;
56851da177e4SLinus Torvalds 	int err = 0;
56861da177e4SLinus Torvalds 
5687df80cd9bSXin Long 	/* Do not peel off from one netns to another one. */
5688df80cd9bSXin Long 	if (!net_eq(current->nsproxy->net_ns, sock_net(sk)))
5689df80cd9bSXin Long 		return -EINVAL;
5690df80cd9bSXin Long 
56910343c554SBenjamin Poirier 	if (!asoc)
56920343c554SBenjamin Poirier 		return -EINVAL;
56930343c554SBenjamin Poirier 
56941da177e4SLinus Torvalds 	/* An association cannot be branched off from an already peeled-off
56951da177e4SLinus Torvalds 	 * socket, nor is this supported for tcp style sockets.
56961da177e4SLinus Torvalds 	 */
56971da177e4SLinus Torvalds 	if (!sctp_style(sk, UDP))
56981da177e4SLinus Torvalds 		return -EINVAL;
56991da177e4SLinus Torvalds 
57001da177e4SLinus Torvalds 	/* Create a new socket.  */
57011da177e4SLinus Torvalds 	err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
57021da177e4SLinus Torvalds 	if (err < 0)
57031da177e4SLinus Torvalds 		return err;
57041da177e4SLinus Torvalds 
5705914e1c8bSVlad Yasevich 	sctp_copy_sock(sock->sk, sk, asoc);
57064f444308SVlad Yasevich 
57074f444308SVlad Yasevich 	/* Make peeled-off sockets more like 1-1 accepted sockets.
5708b7e10c25SRichard Haines 	 * Set the daddr and initialize id to something more random and also
5709b7e10c25SRichard Haines 	 * copy over any ip options.
57104f444308SVlad Yasevich 	 */
5711299ee123SJason Gunthorpe 	sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk);
5712b7e10c25SRichard Haines 	sp->pf->copy_ip_options(sk, sock->sk);
5713914e1c8bSVlad Yasevich 
5714914e1c8bSVlad Yasevich 	/* Populate the fields of the newsk from the oldsk and migrate the
5715914e1c8bSVlad Yasevich 	 * asoc to the newsk.
5716914e1c8bSVlad Yasevich 	 */
571789664c62SXin Long 	err = sctp_sock_migrate(sk, sock->sk, asoc,
571889664c62SXin Long 				SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
571989664c62SXin Long 	if (err) {
572089664c62SXin Long 		sock_release(sock);
572189664c62SXin Long 		sock = NULL;
572289664c62SXin Long 	}
57234f444308SVlad Yasevich 
57241da177e4SLinus Torvalds 	*sockp = sock;
57251da177e4SLinus Torvalds 
57261da177e4SLinus Torvalds 	return err;
57271da177e4SLinus Torvalds }
57280343c554SBenjamin Poirier EXPORT_SYMBOL(sctp_do_peeloff);
57291da177e4SLinus Torvalds 
57302cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *peeloff,
57312cb5c8e3SNeil Horman 					  struct file **newfile, unsigned flags)
57322cb5c8e3SNeil Horman {
57332cb5c8e3SNeil Horman 	struct socket *newsock;
57342cb5c8e3SNeil Horman 	int retval;
57352cb5c8e3SNeil Horman 
57362cb5c8e3SNeil Horman 	retval = sctp_do_peeloff(sk, peeloff->associd, &newsock);
57372cb5c8e3SNeil Horman 	if (retval < 0)
57382cb5c8e3SNeil Horman 		goto out;
57392cb5c8e3SNeil Horman 
57402cb5c8e3SNeil Horman 	/* Map the socket to an unused fd that can be returned to the user.  */
57412cb5c8e3SNeil Horman 	retval = get_unused_fd_flags(flags & SOCK_CLOEXEC);
57422cb5c8e3SNeil Horman 	if (retval < 0) {
57432cb5c8e3SNeil Horman 		sock_release(newsock);
57442cb5c8e3SNeil Horman 		goto out;
57452cb5c8e3SNeil Horman 	}
57462cb5c8e3SNeil Horman 
57472cb5c8e3SNeil Horman 	*newfile = sock_alloc_file(newsock, 0, NULL);
57482cb5c8e3SNeil Horman 	if (IS_ERR(*newfile)) {
57492cb5c8e3SNeil Horman 		put_unused_fd(retval);
57502cb5c8e3SNeil Horman 		retval = PTR_ERR(*newfile);
57512cb5c8e3SNeil Horman 		*newfile = NULL;
57522cb5c8e3SNeil Horman 		return retval;
57532cb5c8e3SNeil Horman 	}
57542cb5c8e3SNeil Horman 
57552cb5c8e3SNeil Horman 	pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk,
57562cb5c8e3SNeil Horman 		 retval);
57572cb5c8e3SNeil Horman 
57582cb5c8e3SNeil Horman 	peeloff->sd = retval;
57592cb5c8e3SNeil Horman 
57602cb5c8e3SNeil Horman 	if (flags & SOCK_NONBLOCK)
57612cb5c8e3SNeil Horman 		(*newfile)->f_flags |= O_NONBLOCK;
57622cb5c8e3SNeil Horman out:
57632cb5c8e3SNeil Horman 	return retval;
57642cb5c8e3SNeil Horman }
57652cb5c8e3SNeil Horman 
57661da177e4SLinus Torvalds static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen)
57671da177e4SLinus Torvalds {
57681da177e4SLinus Torvalds 	sctp_peeloff_arg_t peeloff;
57692cb5c8e3SNeil Horman 	struct file *newfile = NULL;
57701da177e4SLinus Torvalds 	int retval = 0;
57711da177e4SLinus Torvalds 
5772408f22e8SNeil Horman 	if (len < sizeof(sctp_peeloff_arg_t))
57731da177e4SLinus Torvalds 		return -EINVAL;
5774408f22e8SNeil Horman 	len = sizeof(sctp_peeloff_arg_t);
57751da177e4SLinus Torvalds 	if (copy_from_user(&peeloff, optval, len))
57761da177e4SLinus Torvalds 		return -EFAULT;
57771da177e4SLinus Torvalds 
57782cb5c8e3SNeil Horman 	retval = sctp_getsockopt_peeloff_common(sk, &peeloff, &newfile, 0);
57791da177e4SLinus Torvalds 	if (retval < 0)
57801da177e4SLinus Torvalds 		goto out;
57811da177e4SLinus Torvalds 
57821da177e4SLinus Torvalds 	/* Return the fd mapped to the new socket.  */
578356b31d1cSAl Viro 	if (put_user(len, optlen)) {
578456b31d1cSAl Viro 		fput(newfile);
578556b31d1cSAl Viro 		put_unused_fd(retval);
5786408f22e8SNeil Horman 		return -EFAULT;
578756b31d1cSAl Viro 	}
57882cb5c8e3SNeil Horman 
57892cb5c8e3SNeil Horman 	if (copy_to_user(optval, &peeloff, len)) {
57902cb5c8e3SNeil Horman 		fput(newfile);
57912cb5c8e3SNeil Horman 		put_unused_fd(retval);
57922cb5c8e3SNeil Horman 		return -EFAULT;
57932cb5c8e3SNeil Horman 	}
57942cb5c8e3SNeil Horman 	fd_install(retval, newfile);
57952cb5c8e3SNeil Horman out:
57962cb5c8e3SNeil Horman 	return retval;
57972cb5c8e3SNeil Horman }
57982cb5c8e3SNeil Horman 
57992cb5c8e3SNeil Horman static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len,
58002cb5c8e3SNeil Horman 					 char __user *optval, int __user *optlen)
58012cb5c8e3SNeil Horman {
58022cb5c8e3SNeil Horman 	sctp_peeloff_flags_arg_t peeloff;
58032cb5c8e3SNeil Horman 	struct file *newfile = NULL;
58042cb5c8e3SNeil Horman 	int retval = 0;
58052cb5c8e3SNeil Horman 
58062cb5c8e3SNeil Horman 	if (len < sizeof(sctp_peeloff_flags_arg_t))
58072cb5c8e3SNeil Horman 		return -EINVAL;
58082cb5c8e3SNeil Horman 	len = sizeof(sctp_peeloff_flags_arg_t);
58092cb5c8e3SNeil Horman 	if (copy_from_user(&peeloff, optval, len))
58102cb5c8e3SNeil Horman 		return -EFAULT;
58112cb5c8e3SNeil Horman 
58122cb5c8e3SNeil Horman 	retval = sctp_getsockopt_peeloff_common(sk, &peeloff.p_arg,
58132cb5c8e3SNeil Horman 						&newfile, peeloff.flags);
58142cb5c8e3SNeil Horman 	if (retval < 0)
58152cb5c8e3SNeil Horman 		goto out;
58162cb5c8e3SNeil Horman 
58172cb5c8e3SNeil Horman 	/* Return the fd mapped to the new socket.  */
58182cb5c8e3SNeil Horman 	if (put_user(len, optlen)) {
58192cb5c8e3SNeil Horman 		fput(newfile);
58202cb5c8e3SNeil Horman 		put_unused_fd(retval);
58212cb5c8e3SNeil Horman 		return -EFAULT;
58222cb5c8e3SNeil Horman 	}
58232cb5c8e3SNeil Horman 
582456b31d1cSAl Viro 	if (copy_to_user(optval, &peeloff, len)) {
582556b31d1cSAl Viro 		fput(newfile);
582656b31d1cSAl Viro 		put_unused_fd(retval);
582756b31d1cSAl Viro 		return -EFAULT;
582856b31d1cSAl Viro 	}
582956b31d1cSAl Viro 	fd_install(retval, newfile);
58301da177e4SLinus Torvalds out:
58311da177e4SLinus Torvalds 	return retval;
58321da177e4SLinus Torvalds }
58331da177e4SLinus Torvalds 
58341da177e4SLinus Torvalds /* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS)
58351da177e4SLinus Torvalds  *
58361da177e4SLinus Torvalds  * Applications can enable or disable heartbeats for any peer address of
58371da177e4SLinus Torvalds  * an association, modify an address's heartbeat interval, force a
58381da177e4SLinus Torvalds  * heartbeat to be sent immediately, and adjust the address's maximum
58391da177e4SLinus Torvalds  * number of retransmissions sent before an address is considered
58401da177e4SLinus Torvalds  * unreachable.  The following structure is used to access and modify an
58411da177e4SLinus Torvalds  * address's parameters:
58421da177e4SLinus Torvalds  *
58431da177e4SLinus Torvalds  *  struct sctp_paddrparams {
58441da177e4SLinus Torvalds  *     sctp_assoc_t            spp_assoc_id;
58451da177e4SLinus Torvalds  *     struct sockaddr_storage spp_address;
58461da177e4SLinus Torvalds  *     uint32_t                spp_hbinterval;
58471da177e4SLinus Torvalds  *     uint16_t                spp_pathmaxrxt;
584852ccb8e9SFrank Filz  *     uint32_t                spp_pathmtu;
584952ccb8e9SFrank Filz  *     uint32_t                spp_sackdelay;
585052ccb8e9SFrank Filz  *     uint32_t                spp_flags;
58511da177e4SLinus Torvalds  * };
58521da177e4SLinus Torvalds  *
585352ccb8e9SFrank Filz  *   spp_assoc_id    - (one-to-many style socket) This is filled in the
585452ccb8e9SFrank Filz  *                     application, and identifies the association for
585552ccb8e9SFrank Filz  *                     this query.
58561da177e4SLinus Torvalds  *   spp_address     - This specifies which address is of interest.
58571da177e4SLinus Torvalds  *   spp_hbinterval  - This contains the value of the heartbeat interval,
585852ccb8e9SFrank Filz  *                     in milliseconds.  If a  value of zero
585952ccb8e9SFrank Filz  *                     is present in this field then no changes are to
586052ccb8e9SFrank Filz  *                     be made to this parameter.
58611da177e4SLinus Torvalds  *   spp_pathmaxrxt  - This contains the maximum number of
58621da177e4SLinus Torvalds  *                     retransmissions before this address shall be
586352ccb8e9SFrank Filz  *                     considered unreachable. If a  value of zero
586452ccb8e9SFrank Filz  *                     is present in this field then no changes are to
586552ccb8e9SFrank Filz  *                     be made to this parameter.
586652ccb8e9SFrank Filz  *   spp_pathmtu     - When Path MTU discovery is disabled the value
586752ccb8e9SFrank Filz  *                     specified here will be the "fixed" path mtu.
586852ccb8e9SFrank Filz  *                     Note that if the spp_address field is empty
586952ccb8e9SFrank Filz  *                     then all associations on this address will
587052ccb8e9SFrank Filz  *                     have this fixed path mtu set upon them.
587152ccb8e9SFrank Filz  *
587252ccb8e9SFrank Filz  *   spp_sackdelay   - When delayed sack is enabled, this value specifies
587352ccb8e9SFrank Filz  *                     the number of milliseconds that sacks will be delayed
587452ccb8e9SFrank Filz  *                     for. This value will apply to all addresses of an
587552ccb8e9SFrank Filz  *                     association if the spp_address field is empty. Note
587652ccb8e9SFrank Filz  *                     also, that if delayed sack is enabled and this
587752ccb8e9SFrank Filz  *                     value is set to 0, no change is made to the last
587852ccb8e9SFrank Filz  *                     recorded delayed sack timer value.
587952ccb8e9SFrank Filz  *
588052ccb8e9SFrank Filz  *   spp_flags       - These flags are used to control various features
588152ccb8e9SFrank Filz  *                     on an association. The flag field may contain
588252ccb8e9SFrank Filz  *                     zero or more of the following options.
588352ccb8e9SFrank Filz  *
588452ccb8e9SFrank Filz  *                     SPP_HB_ENABLE  - Enable heartbeats on the
588552ccb8e9SFrank Filz  *                     specified address. Note that if the address
588652ccb8e9SFrank Filz  *                     field is empty all addresses for the association
588752ccb8e9SFrank Filz  *                     have heartbeats enabled upon them.
588852ccb8e9SFrank Filz  *
588952ccb8e9SFrank Filz  *                     SPP_HB_DISABLE - Disable heartbeats on the
589052ccb8e9SFrank Filz  *                     speicifed address. Note that if the address
589152ccb8e9SFrank Filz  *                     field is empty all addresses for the association
589252ccb8e9SFrank Filz  *                     will have their heartbeats disabled. Note also
589352ccb8e9SFrank Filz  *                     that SPP_HB_ENABLE and SPP_HB_DISABLE are
589452ccb8e9SFrank Filz  *                     mutually exclusive, only one of these two should
589552ccb8e9SFrank Filz  *                     be specified. Enabling both fields will have
589652ccb8e9SFrank Filz  *                     undetermined results.
589752ccb8e9SFrank Filz  *
589852ccb8e9SFrank Filz  *                     SPP_HB_DEMAND - Request a user initiated heartbeat
589952ccb8e9SFrank Filz  *                     to be made immediately.
590052ccb8e9SFrank Filz  *
590152ccb8e9SFrank Filz  *                     SPP_PMTUD_ENABLE - This field will enable PMTU
590252ccb8e9SFrank Filz  *                     discovery upon the specified address. Note that
590352ccb8e9SFrank Filz  *                     if the address feild is empty then all addresses
590452ccb8e9SFrank Filz  *                     on the association are effected.
590552ccb8e9SFrank Filz  *
590652ccb8e9SFrank Filz  *                     SPP_PMTUD_DISABLE - This field will disable PMTU
590752ccb8e9SFrank Filz  *                     discovery upon the specified address. Note that
590852ccb8e9SFrank Filz  *                     if the address feild is empty then all addresses
590952ccb8e9SFrank Filz  *                     on the association are effected. Not also that
591052ccb8e9SFrank Filz  *                     SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually
591152ccb8e9SFrank Filz  *                     exclusive. Enabling both will have undetermined
591252ccb8e9SFrank Filz  *                     results.
591352ccb8e9SFrank Filz  *
591452ccb8e9SFrank Filz  *                     SPP_SACKDELAY_ENABLE - Setting this flag turns
591552ccb8e9SFrank Filz  *                     on delayed sack. The time specified in spp_sackdelay
591652ccb8e9SFrank Filz  *                     is used to specify the sack delay for this address. Note
591752ccb8e9SFrank Filz  *                     that if spp_address is empty then all addresses will
591852ccb8e9SFrank Filz  *                     enable delayed sack and take on the sack delay
591952ccb8e9SFrank Filz  *                     value specified in spp_sackdelay.
592052ccb8e9SFrank Filz  *                     SPP_SACKDELAY_DISABLE - Setting this flag turns
592152ccb8e9SFrank Filz  *                     off delayed sack. If the spp_address field is blank then
592252ccb8e9SFrank Filz  *                     delayed sack is disabled for the entire association. Note
592352ccb8e9SFrank Filz  *                     also that this field is mutually exclusive to
592452ccb8e9SFrank Filz  *                     SPP_SACKDELAY_ENABLE, setting both will have undefined
592552ccb8e9SFrank Filz  *                     results.
59260b0dce7aSXin Long  *
59270b0dce7aSXin Long  *                     SPP_IPV6_FLOWLABEL:  Setting this flag enables the
59280b0dce7aSXin Long  *                     setting of the IPV6 flow label value.  The value is
59290b0dce7aSXin Long  *                     contained in the spp_ipv6_flowlabel field.
59300b0dce7aSXin Long  *                     Upon retrieval, this flag will be set to indicate that
59310b0dce7aSXin Long  *                     the spp_ipv6_flowlabel field has a valid value returned.
59320b0dce7aSXin Long  *                     If a specific destination address is set (in the
59330b0dce7aSXin Long  *                     spp_address field), then the value returned is that of
59340b0dce7aSXin Long  *                     the address.  If just an association is specified (and
59350b0dce7aSXin Long  *                     no address), then the association's default flow label
59360b0dce7aSXin Long  *                     is returned.  If neither an association nor a destination
59370b0dce7aSXin Long  *                     is specified, then the socket's default flow label is
59380b0dce7aSXin Long  *                     returned.  For non-IPv6 sockets, this flag will be left
59390b0dce7aSXin Long  *                     cleared.
59400b0dce7aSXin Long  *
59410b0dce7aSXin Long  *                     SPP_DSCP:  Setting this flag enables the setting of the
59420b0dce7aSXin Long  *                     Differentiated Services Code Point (DSCP) value
59430b0dce7aSXin Long  *                     associated with either the association or a specific
59440b0dce7aSXin Long  *                     address.  The value is obtained in the spp_dscp field.
59450b0dce7aSXin Long  *                     Upon retrieval, this flag will be set to indicate that
59460b0dce7aSXin Long  *                     the spp_dscp field has a valid value returned.  If a
59470b0dce7aSXin Long  *                     specific destination address is set when called (in the
59480b0dce7aSXin Long  *                     spp_address field), then that specific destination
59490b0dce7aSXin Long  *                     address's DSCP value is returned.  If just an association
59500b0dce7aSXin Long  *                     is specified, then the association's default DSCP is
59510b0dce7aSXin Long  *                     returned.  If neither an association nor a destination is
59520b0dce7aSXin Long  *                     specified, then the socket's default DSCP is returned.
59530b0dce7aSXin Long  *
59540b0dce7aSXin Long  *   spp_ipv6_flowlabel
59550b0dce7aSXin Long  *                   - This field is used in conjunction with the
59560b0dce7aSXin Long  *                     SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label.
59570b0dce7aSXin Long  *                     The 20 least significant bits are used for the flow
59580b0dce7aSXin Long  *                     label.  This setting has precedence over any IPv6-layer
59590b0dce7aSXin Long  *                     setting.
59600b0dce7aSXin Long  *
59610b0dce7aSXin Long  *   spp_dscp        - This field is used in conjunction with the SPP_DSCP flag
59620b0dce7aSXin Long  *                     and contains the DSCP.  The 6 most significant bits are
59630b0dce7aSXin Long  *                     used for the DSCP.  This setting has precedence over any
59640b0dce7aSXin Long  *                     IPv4- or IPv6- layer setting.
59651da177e4SLinus Torvalds  */
59661da177e4SLinus Torvalds static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
59671da177e4SLinus Torvalds 					    char __user *optval, int __user *optlen)
59681da177e4SLinus Torvalds {
59691da177e4SLinus Torvalds 	struct sctp_paddrparams  params;
597052ccb8e9SFrank Filz 	struct sctp_transport   *trans = NULL;
597152ccb8e9SFrank Filz 	struct sctp_association *asoc = NULL;
597252ccb8e9SFrank Filz 	struct sctp_sock        *sp = sctp_sk(sk);
59731da177e4SLinus Torvalds 
59740b0dce7aSXin Long 	if (len >= sizeof(params))
59750b0dce7aSXin Long 		len = sizeof(params);
59760b0dce7aSXin Long 	else if (len >= ALIGN(offsetof(struct sctp_paddrparams,
59770b0dce7aSXin Long 				       spp_ipv6_flowlabel), 4))
59780b0dce7aSXin Long 		len = ALIGN(offsetof(struct sctp_paddrparams,
59790b0dce7aSXin Long 				     spp_ipv6_flowlabel), 4);
59800b0dce7aSXin Long 	else
59811da177e4SLinus Torvalds 		return -EINVAL;
59820b0dce7aSXin Long 
59831da177e4SLinus Torvalds 	if (copy_from_user(&params, optval, len))
59841da177e4SLinus Torvalds 		return -EFAULT;
59851da177e4SLinus Torvalds 
598652ccb8e9SFrank Filz 	/* If an address other than INADDR_ANY is specified, and
598752ccb8e9SFrank Filz 	 * no transport is found, then the request is invalid.
59881da177e4SLinus Torvalds 	 */
598952cae8f0SVlad Yasevich 	if (!sctp_is_any(sk, (union sctp_addr *)&params.spp_address)) {
59901da177e4SLinus Torvalds 		trans = sctp_addr_id2transport(sk, &params.spp_address,
59911da177e4SLinus Torvalds 					       params.spp_assoc_id);
599252ccb8e9SFrank Filz 		if (!trans) {
5993bb33381dSDaniel Borkmann 			pr_debug("%s: failed no transport\n", __func__);
59941da177e4SLinus Torvalds 			return -EINVAL;
599552ccb8e9SFrank Filz 		}
599652ccb8e9SFrank Filz 	}
59971da177e4SLinus Torvalds 
5998b99e5e02SXin Long 	/* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the
5999b99e5e02SXin Long 	 * socket is a one to many style socket, and an association
6000b99e5e02SXin Long 	 * was not found, then the id was invalid.
60011da177e4SLinus Torvalds 	 */
600252ccb8e9SFrank Filz 	asoc = sctp_id2assoc(sk, params.spp_assoc_id);
6003b99e5e02SXin Long 	if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC &&
6004b99e5e02SXin Long 	    sctp_style(sk, UDP)) {
6005bb33381dSDaniel Borkmann 		pr_debug("%s: failed no association\n", __func__);
600652ccb8e9SFrank Filz 		return -EINVAL;
600752ccb8e9SFrank Filz 	}
60081da177e4SLinus Torvalds 
600952ccb8e9SFrank Filz 	if (trans) {
601052ccb8e9SFrank Filz 		/* Fetch transport values. */
601152ccb8e9SFrank Filz 		params.spp_hbinterval = jiffies_to_msecs(trans->hbinterval);
601252ccb8e9SFrank Filz 		params.spp_pathmtu    = trans->pathmtu;
601352ccb8e9SFrank Filz 		params.spp_pathmaxrxt = trans->pathmaxrxt;
601452ccb8e9SFrank Filz 		params.spp_sackdelay  = jiffies_to_msecs(trans->sackdelay);
60151da177e4SLinus Torvalds 
601652ccb8e9SFrank Filz 		/*draft-11 doesn't say what to return in spp_flags*/
601752ccb8e9SFrank Filz 		params.spp_flags      = trans->param_flags;
60180b0dce7aSXin Long 		if (trans->flowlabel & SCTP_FLOWLABEL_SET_MASK) {
60190b0dce7aSXin Long 			params.spp_ipv6_flowlabel = trans->flowlabel &
60200b0dce7aSXin Long 						    SCTP_FLOWLABEL_VAL_MASK;
60210b0dce7aSXin Long 			params.spp_flags |= SPP_IPV6_FLOWLABEL;
60220b0dce7aSXin Long 		}
60230b0dce7aSXin Long 		if (trans->dscp & SCTP_DSCP_SET_MASK) {
60240b0dce7aSXin Long 			params.spp_dscp	= trans->dscp & SCTP_DSCP_VAL_MASK;
60250b0dce7aSXin Long 			params.spp_flags |= SPP_DSCP;
60260b0dce7aSXin Long 		}
602752ccb8e9SFrank Filz 	} else if (asoc) {
602852ccb8e9SFrank Filz 		/* Fetch association values. */
602952ccb8e9SFrank Filz 		params.spp_hbinterval = jiffies_to_msecs(asoc->hbinterval);
603052ccb8e9SFrank Filz 		params.spp_pathmtu    = asoc->pathmtu;
603152ccb8e9SFrank Filz 		params.spp_pathmaxrxt = asoc->pathmaxrxt;
603252ccb8e9SFrank Filz 		params.spp_sackdelay  = jiffies_to_msecs(asoc->sackdelay);
603352ccb8e9SFrank Filz 
603452ccb8e9SFrank Filz 		/*draft-11 doesn't say what to return in spp_flags*/
603552ccb8e9SFrank Filz 		params.spp_flags      = asoc->param_flags;
60360b0dce7aSXin Long 		if (asoc->flowlabel & SCTP_FLOWLABEL_SET_MASK) {
60370b0dce7aSXin Long 			params.spp_ipv6_flowlabel = asoc->flowlabel &
60380b0dce7aSXin Long 						    SCTP_FLOWLABEL_VAL_MASK;
60390b0dce7aSXin Long 			params.spp_flags |= SPP_IPV6_FLOWLABEL;
60400b0dce7aSXin Long 		}
60410b0dce7aSXin Long 		if (asoc->dscp & SCTP_DSCP_SET_MASK) {
60420b0dce7aSXin Long 			params.spp_dscp	= asoc->dscp & SCTP_DSCP_VAL_MASK;
60430b0dce7aSXin Long 			params.spp_flags |= SPP_DSCP;
60440b0dce7aSXin Long 		}
604552ccb8e9SFrank Filz 	} else {
604652ccb8e9SFrank Filz 		/* Fetch socket values. */
604752ccb8e9SFrank Filz 		params.spp_hbinterval = sp->hbinterval;
604852ccb8e9SFrank Filz 		params.spp_pathmtu    = sp->pathmtu;
604952ccb8e9SFrank Filz 		params.spp_sackdelay  = sp->sackdelay;
605052ccb8e9SFrank Filz 		params.spp_pathmaxrxt = sp->pathmaxrxt;
605152ccb8e9SFrank Filz 
605252ccb8e9SFrank Filz 		/*draft-11 doesn't say what to return in spp_flags*/
605352ccb8e9SFrank Filz 		params.spp_flags      = sp->param_flags;
60540b0dce7aSXin Long 		if (sp->flowlabel & SCTP_FLOWLABEL_SET_MASK) {
60550b0dce7aSXin Long 			params.spp_ipv6_flowlabel = sp->flowlabel &
60560b0dce7aSXin Long 						    SCTP_FLOWLABEL_VAL_MASK;
60570b0dce7aSXin Long 			params.spp_flags |= SPP_IPV6_FLOWLABEL;
60580b0dce7aSXin Long 		}
60590b0dce7aSXin Long 		if (sp->dscp & SCTP_DSCP_SET_MASK) {
60600b0dce7aSXin Long 			params.spp_dscp	= sp->dscp & SCTP_DSCP_VAL_MASK;
60610b0dce7aSXin Long 			params.spp_flags |= SPP_DSCP;
60620b0dce7aSXin Long 		}
606352ccb8e9SFrank Filz 	}
606452ccb8e9SFrank Filz 
60651da177e4SLinus Torvalds 	if (copy_to_user(optval, &params, len))
60661da177e4SLinus Torvalds 		return -EFAULT;
60671da177e4SLinus Torvalds 
60681da177e4SLinus Torvalds 	if (put_user(len, optlen))
60691da177e4SLinus Torvalds 		return -EFAULT;
60701da177e4SLinus Torvalds 
60711da177e4SLinus Torvalds 	return 0;
60721da177e4SLinus Torvalds }
60731da177e4SLinus Torvalds 
6074d364d927SWei Yongjun /*
6075d364d927SWei Yongjun  * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
60767708610bSFrank Filz  *
6077d364d927SWei Yongjun  * This option will effect the way delayed acks are performed.  This
6078d364d927SWei Yongjun  * option allows you to get or set the delayed ack time, in
6079d364d927SWei Yongjun  * milliseconds.  It also allows changing the delayed ack frequency.
6080d364d927SWei Yongjun  * Changing the frequency to 1 disables the delayed sack algorithm.  If
6081d364d927SWei Yongjun  * the assoc_id is 0, then this sets or gets the endpoints default
6082d364d927SWei Yongjun  * values.  If the assoc_id field is non-zero, then the set or get
6083d364d927SWei Yongjun  * effects the specified association for the one to many model (the
6084d364d927SWei Yongjun  * assoc_id field is ignored by the one to one model).  Note that if
6085d364d927SWei Yongjun  * sack_delay or sack_freq are 0 when setting this option, then the
6086d364d927SWei Yongjun  * current values will remain unchanged.
60877708610bSFrank Filz  *
6088d364d927SWei Yongjun  * struct sctp_sack_info {
6089d364d927SWei Yongjun  *     sctp_assoc_t            sack_assoc_id;
6090d364d927SWei Yongjun  *     uint32_t                sack_delay;
6091d364d927SWei Yongjun  *     uint32_t                sack_freq;
60927708610bSFrank Filz  * };
60937708610bSFrank Filz  *
6094d364d927SWei Yongjun  * sack_assoc_id -  This parameter, indicates which association the user
6095d364d927SWei Yongjun  *    is performing an action upon.  Note that if this field's value is
6096d364d927SWei Yongjun  *    zero then the endpoints default value is changed (effecting future
60977708610bSFrank Filz  *    associations only).
60987708610bSFrank Filz  *
6099d364d927SWei Yongjun  * sack_delay -  This parameter contains the number of milliseconds that
6100d364d927SWei Yongjun  *    the user is requesting the delayed ACK timer be set to.  Note that
6101d364d927SWei Yongjun  *    this value is defined in the standard to be between 200 and 500
6102d364d927SWei Yongjun  *    milliseconds.
61037708610bSFrank Filz  *
6104d364d927SWei Yongjun  * sack_freq -  This parameter contains the number of packets that must
6105d364d927SWei Yongjun  *    be received before a sack is sent without waiting for the delay
6106d364d927SWei Yongjun  *    timer to expire.  The default value for this is 2, setting this
6107d364d927SWei Yongjun  *    value to 1 will disable the delayed sack algorithm.
61087708610bSFrank Filz  */
6109d364d927SWei Yongjun static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
61107708610bSFrank Filz 					    char __user *optval,
61117708610bSFrank Filz 					    int __user *optlen)
61127708610bSFrank Filz {
6113d364d927SWei Yongjun 	struct sctp_sack_info    params;
61147708610bSFrank Filz 	struct sctp_association *asoc = NULL;
61157708610bSFrank Filz 	struct sctp_sock        *sp = sctp_sk(sk);
61167708610bSFrank Filz 
6117d364d927SWei Yongjun 	if (len >= sizeof(struct sctp_sack_info)) {
6118d364d927SWei Yongjun 		len = sizeof(struct sctp_sack_info);
6119408f22e8SNeil Horman 
61207708610bSFrank Filz 		if (copy_from_user(&params, optval, len))
61217708610bSFrank Filz 			return -EFAULT;
6122d364d927SWei Yongjun 	} else if (len == sizeof(struct sctp_assoc_value)) {
612394f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
6124f916ec96SNeil Horman 				    "%s (pid %d) "
612594f65193SNeil Horman 				    "Use of struct sctp_assoc_value in delayed_ack socket option.\n"
6126f916ec96SNeil Horman 				    "Use struct sctp_sack_info instead\n",
6127f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
6128d364d927SWei Yongjun 		if (copy_from_user(&params, optval, len))
6129d364d927SWei Yongjun 			return -EFAULT;
6130d364d927SWei Yongjun 	} else
6131d364d927SWei Yongjun 		return -EINVAL;
61327708610bSFrank Filz 
61339c5829e1SXin Long 	/* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the
61349c5829e1SXin Long 	 * socket is a one to many style socket, and an association
61359c5829e1SXin Long 	 * was not found, then the id was invalid.
61367708610bSFrank Filz 	 */
6137d364d927SWei Yongjun 	asoc = sctp_id2assoc(sk, params.sack_assoc_id);
61389c5829e1SXin Long 	if (!asoc && params.sack_assoc_id != SCTP_FUTURE_ASSOC &&
61399c5829e1SXin Long 	    sctp_style(sk, UDP))
61407708610bSFrank Filz 		return -EINVAL;
61417708610bSFrank Filz 
61427708610bSFrank Filz 	if (asoc) {
61437708610bSFrank Filz 		/* Fetch association values. */
6144d364d927SWei Yongjun 		if (asoc->param_flags & SPP_SACKDELAY_ENABLE) {
61459c5829e1SXin Long 			params.sack_delay = jiffies_to_msecs(asoc->sackdelay);
6146d364d927SWei Yongjun 			params.sack_freq = asoc->sackfreq;
6147d364d927SWei Yongjun 
6148d364d927SWei Yongjun 		} else {
6149d364d927SWei Yongjun 			params.sack_delay = 0;
6150d364d927SWei Yongjun 			params.sack_freq = 1;
6151d364d927SWei Yongjun 		}
61527708610bSFrank Filz 	} else {
61537708610bSFrank Filz 		/* Fetch socket values. */
6154d364d927SWei Yongjun 		if (sp->param_flags & SPP_SACKDELAY_ENABLE) {
6155d364d927SWei Yongjun 			params.sack_delay  = sp->sackdelay;
6156d364d927SWei Yongjun 			params.sack_freq = sp->sackfreq;
6157d364d927SWei Yongjun 		} else {
6158d364d927SWei Yongjun 			params.sack_delay  = 0;
6159d364d927SWei Yongjun 			params.sack_freq = 1;
6160d364d927SWei Yongjun 		}
61617708610bSFrank Filz 	}
61627708610bSFrank Filz 
61637708610bSFrank Filz 	if (copy_to_user(optval, &params, len))
61647708610bSFrank Filz 		return -EFAULT;
61657708610bSFrank Filz 
61667708610bSFrank Filz 	if (put_user(len, optlen))
61677708610bSFrank Filz 		return -EFAULT;
61687708610bSFrank Filz 
61697708610bSFrank Filz 	return 0;
61707708610bSFrank Filz }
61717708610bSFrank Filz 
61721da177e4SLinus Torvalds /* 7.1.3 Initialization Parameters (SCTP_INITMSG)
61731da177e4SLinus Torvalds  *
61741da177e4SLinus Torvalds  * Applications can specify protocol parameters for the default association
61751da177e4SLinus Torvalds  * initialization.  The option name argument to setsockopt() and getsockopt()
61761da177e4SLinus Torvalds  * is SCTP_INITMSG.
61771da177e4SLinus Torvalds  *
61781da177e4SLinus Torvalds  * Setting initialization parameters is effective only on an unconnected
61791da177e4SLinus Torvalds  * socket (for UDP-style sockets only future associations are effected
61801da177e4SLinus Torvalds  * by the change).  With TCP-style sockets, this option is inherited by
61811da177e4SLinus Torvalds  * sockets derived from a listener socket.
61821da177e4SLinus Torvalds  */
61831da177e4SLinus Torvalds static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen)
61841da177e4SLinus Torvalds {
6185408f22e8SNeil Horman 	if (len < sizeof(struct sctp_initmsg))
61861da177e4SLinus Torvalds 		return -EINVAL;
6187408f22e8SNeil Horman 	len = sizeof(struct sctp_initmsg);
6188408f22e8SNeil Horman 	if (put_user(len, optlen))
6189408f22e8SNeil Horman 		return -EFAULT;
61901da177e4SLinus Torvalds 	if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len))
61911da177e4SLinus Torvalds 		return -EFAULT;
61921da177e4SLinus Torvalds 	return 0;
61931da177e4SLinus Torvalds }
61941da177e4SLinus Torvalds 
61951da177e4SLinus Torvalds 
61965fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
61975fe467eeSIvan Skytte Jørgensen 				      char __user *optval, int __user *optlen)
61985fe467eeSIvan Skytte Jørgensen {
61995fe467eeSIvan Skytte Jørgensen 	struct sctp_association *asoc;
62005fe467eeSIvan Skytte Jørgensen 	int cnt = 0;
62015fe467eeSIvan Skytte Jørgensen 	struct sctp_getaddrs getaddrs;
62025fe467eeSIvan Skytte Jørgensen 	struct sctp_transport *from;
62035fe467eeSIvan Skytte Jørgensen 	void __user *to;
62045fe467eeSIvan Skytte Jørgensen 	union sctp_addr temp;
62055fe467eeSIvan Skytte Jørgensen 	struct sctp_sock *sp = sctp_sk(sk);
62065fe467eeSIvan Skytte Jørgensen 	int addrlen;
62075fe467eeSIvan Skytte Jørgensen 	size_t space_left;
62085fe467eeSIvan Skytte Jørgensen 	int bytes_copied;
62095fe467eeSIvan Skytte Jørgensen 
62105fe467eeSIvan Skytte Jørgensen 	if (len < sizeof(struct sctp_getaddrs))
62115fe467eeSIvan Skytte Jørgensen 		return -EINVAL;
62125fe467eeSIvan Skytte Jørgensen 
62135fe467eeSIvan Skytte Jørgensen 	if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
62145fe467eeSIvan Skytte Jørgensen 		return -EFAULT;
62155fe467eeSIvan Skytte Jørgensen 
62165fe467eeSIvan Skytte Jørgensen 	/* For UDP-style sockets, id specifies the association to query.  */
62175fe467eeSIvan Skytte Jørgensen 	asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
62185fe467eeSIvan Skytte Jørgensen 	if (!asoc)
62195fe467eeSIvan Skytte Jørgensen 		return -EINVAL;
62205fe467eeSIvan Skytte Jørgensen 
62215fe467eeSIvan Skytte Jørgensen 	to = optval + offsetof(struct sctp_getaddrs, addrs);
6222186e2343SNeil Horman 	space_left = len - offsetof(struct sctp_getaddrs, addrs);
62235fe467eeSIvan Skytte Jørgensen 
62249dbc15f0SRobert P. J. Day 	list_for_each_entry(from, &asoc->peer.transport_addr_list,
62259dbc15f0SRobert P. J. Day 				transports) {
6226b3f5b3b6SAl Viro 		memcpy(&temp, &from->ipaddr, sizeof(temp));
6227299ee123SJason Gunthorpe 		addrlen = sctp_get_pf_specific(sk->sk_family)
6228299ee123SJason Gunthorpe 			      ->addr_to_user(sp, &temp);
62295fe467eeSIvan Skytte Jørgensen 		if (space_left < addrlen)
62305fe467eeSIvan Skytte Jørgensen 			return -ENOMEM;
62315fe467eeSIvan Skytte Jørgensen 		if (copy_to_user(to, &temp, addrlen))
62325fe467eeSIvan Skytte Jørgensen 			return -EFAULT;
62335fe467eeSIvan Skytte Jørgensen 		to += addrlen;
62345fe467eeSIvan Skytte Jørgensen 		cnt++;
62355fe467eeSIvan Skytte Jørgensen 		space_left -= addrlen;
62365fe467eeSIvan Skytte Jørgensen 	}
62375fe467eeSIvan Skytte Jørgensen 
62385fe467eeSIvan Skytte Jørgensen 	if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num))
62395fe467eeSIvan Skytte Jørgensen 		return -EFAULT;
62405fe467eeSIvan Skytte Jørgensen 	bytes_copied = ((char __user *)to) - optval;
62415fe467eeSIvan Skytte Jørgensen 	if (put_user(bytes_copied, optlen))
62425fe467eeSIvan Skytte Jørgensen 		return -EFAULT;
62435fe467eeSIvan Skytte Jørgensen 
62445fe467eeSIvan Skytte Jørgensen 	return 0;
62455fe467eeSIvan Skytte Jørgensen }
62465fe467eeSIvan Skytte Jørgensen 
6247aad97f38SVlad Yasevich static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
6248aad97f38SVlad Yasevich 			    size_t space_left, int *bytes_copied)
62495fe467eeSIvan Skytte Jørgensen {
62505fe467eeSIvan Skytte Jørgensen 	struct sctp_sockaddr_entry *addr;
62515fe467eeSIvan Skytte Jørgensen 	union sctp_addr temp;
62525fe467eeSIvan Skytte Jørgensen 	int cnt = 0;
62535fe467eeSIvan Skytte Jørgensen 	int addrlen;
62544db67e80SEric W. Biederman 	struct net *net = sock_net(sk);
62555fe467eeSIvan Skytte Jørgensen 
625629303547SVlad Yasevich 	rcu_read_lock();
62574db67e80SEric W. Biederman 	list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) {
625829303547SVlad Yasevich 		if (!addr->valid)
625929303547SVlad Yasevich 			continue;
626029303547SVlad Yasevich 
62615fe467eeSIvan Skytte Jørgensen 		if ((PF_INET == sk->sk_family) &&
62626244be4eSAl Viro 		    (AF_INET6 == addr->a.sa.sa_family))
62635fe467eeSIvan Skytte Jørgensen 			continue;
62647dab83deSVlad Yasevich 		if ((PF_INET6 == sk->sk_family) &&
62657dab83deSVlad Yasevich 		    inet_v6_ipv6only(sk) &&
62667dab83deSVlad Yasevich 		    (AF_INET == addr->a.sa.sa_family))
62677dab83deSVlad Yasevich 			continue;
62686244be4eSAl Viro 		memcpy(&temp, &addr->a, sizeof(temp));
6269b46ae36dSVlad Yasevich 		if (!temp.v4.sin_port)
6270b46ae36dSVlad Yasevich 			temp.v4.sin_port = htons(port);
6271b46ae36dSVlad Yasevich 
6272299ee123SJason Gunthorpe 		addrlen = sctp_get_pf_specific(sk->sk_family)
6273299ee123SJason Gunthorpe 			      ->addr_to_user(sctp_sk(sk), &temp);
6274299ee123SJason Gunthorpe 
627529303547SVlad Yasevich 		if (space_left < addrlen) {
627629303547SVlad Yasevich 			cnt =  -ENOMEM;
627729303547SVlad Yasevich 			break;
627829303547SVlad Yasevich 		}
6279aad97f38SVlad Yasevich 		memcpy(to, &temp, addrlen);
628029c7cf96SSridhar Samudrala 
6281aad97f38SVlad Yasevich 		to += addrlen;
62825fe467eeSIvan Skytte Jørgensen 		cnt++;
62835fe467eeSIvan Skytte Jørgensen 		space_left -= addrlen;
62843663c306SVlad Yasevich 		*bytes_copied += addrlen;
62855fe467eeSIvan Skytte Jørgensen 	}
628629303547SVlad Yasevich 	rcu_read_unlock();
62875fe467eeSIvan Skytte Jørgensen 
62885fe467eeSIvan Skytte Jørgensen 	return cnt;
62895fe467eeSIvan Skytte Jørgensen }
62905fe467eeSIvan Skytte Jørgensen 
62911da177e4SLinus Torvalds 
62925fe467eeSIvan Skytte Jørgensen static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
62935fe467eeSIvan Skytte Jørgensen 				       char __user *optval, int __user *optlen)
62945fe467eeSIvan Skytte Jørgensen {
62955fe467eeSIvan Skytte Jørgensen 	struct sctp_bind_addr *bp;
62965fe467eeSIvan Skytte Jørgensen 	struct sctp_association *asoc;
62975fe467eeSIvan Skytte Jørgensen 	int cnt = 0;
62985fe467eeSIvan Skytte Jørgensen 	struct sctp_getaddrs getaddrs;
62995fe467eeSIvan Skytte Jørgensen 	struct sctp_sockaddr_entry *addr;
63005fe467eeSIvan Skytte Jørgensen 	void __user *to;
63015fe467eeSIvan Skytte Jørgensen 	union sctp_addr temp;
63025fe467eeSIvan Skytte Jørgensen 	struct sctp_sock *sp = sctp_sk(sk);
63035fe467eeSIvan Skytte Jørgensen 	int addrlen;
63045fe467eeSIvan Skytte Jørgensen 	int err = 0;
63055fe467eeSIvan Skytte Jørgensen 	size_t space_left;
6306aad97f38SVlad Yasevich 	int bytes_copied = 0;
6307aad97f38SVlad Yasevich 	void *addrs;
630870b57b81SVlad Yasevich 	void *buf;
63095fe467eeSIvan Skytte Jørgensen 
6310408f22e8SNeil Horman 	if (len < sizeof(struct sctp_getaddrs))
63115fe467eeSIvan Skytte Jørgensen 		return -EINVAL;
63125fe467eeSIvan Skytte Jørgensen 
63135fe467eeSIvan Skytte Jørgensen 	if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
63145fe467eeSIvan Skytte Jørgensen 		return -EFAULT;
63155fe467eeSIvan Skytte Jørgensen 
63165fe467eeSIvan Skytte Jørgensen 	/*
63175fe467eeSIvan Skytte Jørgensen 	 *  For UDP-style sockets, id specifies the association to query.
63185fe467eeSIvan Skytte Jørgensen 	 *  If the id field is set to the value '0' then the locally bound
63195fe467eeSIvan Skytte Jørgensen 	 *  addresses are returned without regard to any particular
63205fe467eeSIvan Skytte Jørgensen 	 *  association.
63215fe467eeSIvan Skytte Jørgensen 	 */
63225fe467eeSIvan Skytte Jørgensen 	if (0 == getaddrs.assoc_id) {
63235fe467eeSIvan Skytte Jørgensen 		bp = &sctp_sk(sk)->ep->base.bind_addr;
63245fe467eeSIvan Skytte Jørgensen 	} else {
63255fe467eeSIvan Skytte Jørgensen 		asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
63265fe467eeSIvan Skytte Jørgensen 		if (!asoc)
63275fe467eeSIvan Skytte Jørgensen 			return -EINVAL;
63285fe467eeSIvan Skytte Jørgensen 		bp = &asoc->base.bind_addr;
63295fe467eeSIvan Skytte Jørgensen 	}
63305fe467eeSIvan Skytte Jørgensen 
63315fe467eeSIvan Skytte Jørgensen 	to = optval + offsetof(struct sctp_getaddrs, addrs);
6332186e2343SNeil Horman 	space_left = len - offsetof(struct sctp_getaddrs, addrs);
6333186e2343SNeil Horman 
6334cacc0621SMarcelo Ricardo Leitner 	addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN);
6335aad97f38SVlad Yasevich 	if (!addrs)
6336aad97f38SVlad Yasevich 		return -ENOMEM;
63375fe467eeSIvan Skytte Jørgensen 
63385fe467eeSIvan Skytte Jørgensen 	/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
63395fe467eeSIvan Skytte Jørgensen 	 * addresses from the global local address list.
63405fe467eeSIvan Skytte Jørgensen 	 */
63415fe467eeSIvan Skytte Jørgensen 	if (sctp_list_single_entry(&bp->address_list)) {
63425fe467eeSIvan Skytte Jørgensen 		addr = list_entry(bp->address_list.next,
63435fe467eeSIvan Skytte Jørgensen 				  struct sctp_sockaddr_entry, list);
634452cae8f0SVlad Yasevich 		if (sctp_is_any(sk, &addr->a)) {
6345aad97f38SVlad Yasevich 			cnt = sctp_copy_laddrs(sk, bp->port, addrs,
6346aad97f38SVlad Yasevich 						space_left, &bytes_copied);
63475fe467eeSIvan Skytte Jørgensen 			if (cnt < 0) {
63485fe467eeSIvan Skytte Jørgensen 				err = cnt;
6349559cf710SVlad Yasevich 				goto out;
63505fe467eeSIvan Skytte Jørgensen 			}
63515fe467eeSIvan Skytte Jørgensen 			goto copy_getaddrs;
63525fe467eeSIvan Skytte Jørgensen 		}
63535fe467eeSIvan Skytte Jørgensen 	}
63545fe467eeSIvan Skytte Jørgensen 
635570b57b81SVlad Yasevich 	buf = addrs;
6356559cf710SVlad Yasevich 	/* Protection on the bound address list is not needed since
6357559cf710SVlad Yasevich 	 * in the socket option context we hold a socket lock and
6358559cf710SVlad Yasevich 	 * thus the bound address list can't change.
6359559cf710SVlad Yasevich 	 */
6360559cf710SVlad Yasevich 	list_for_each_entry(addr, &bp->address_list, list) {
63616244be4eSAl Viro 		memcpy(&temp, &addr->a, sizeof(temp));
6362299ee123SJason Gunthorpe 		addrlen = sctp_get_pf_specific(sk->sk_family)
6363299ee123SJason Gunthorpe 			      ->addr_to_user(sp, &temp);
6364aad97f38SVlad Yasevich 		if (space_left < addrlen) {
6365aad97f38SVlad Yasevich 			err =  -ENOMEM; /*fixme: right error?*/
6366559cf710SVlad Yasevich 			goto out;
63675fe467eeSIvan Skytte Jørgensen 		}
636870b57b81SVlad Yasevich 		memcpy(buf, &temp, addrlen);
636970b57b81SVlad Yasevich 		buf += addrlen;
6370aad97f38SVlad Yasevich 		bytes_copied += addrlen;
63715fe467eeSIvan Skytte Jørgensen 		cnt++;
63725fe467eeSIvan Skytte Jørgensen 		space_left -= addrlen;
63735fe467eeSIvan Skytte Jørgensen 	}
63745fe467eeSIvan Skytte Jørgensen 
63755fe467eeSIvan Skytte Jørgensen copy_getaddrs:
6376aad97f38SVlad Yasevich 	if (copy_to_user(to, addrs, bytes_copied)) {
6377aad97f38SVlad Yasevich 		err = -EFAULT;
6378d6f9fdafSSebastian Siewior 		goto out;
6379aad97f38SVlad Yasevich 	}
6380fe979ac1SVlad Yasevich 	if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) {
6381fe979ac1SVlad Yasevich 		err = -EFAULT;
6382d6f9fdafSSebastian Siewior 		goto out;
6383fe979ac1SVlad Yasevich 	}
6384c76f97c9SMarcelo Ricardo Leitner 	/* XXX: We should have accounted for sizeof(struct sctp_getaddrs) too,
6385c76f97c9SMarcelo Ricardo Leitner 	 * but we can't change it anymore.
6386c76f97c9SMarcelo Ricardo Leitner 	 */
63875fe467eeSIvan Skytte Jørgensen 	if (put_user(bytes_copied, optlen))
6388fe979ac1SVlad Yasevich 		err = -EFAULT;
6389d6f9fdafSSebastian Siewior out:
6390aad97f38SVlad Yasevich 	kfree(addrs);
63915fe467eeSIvan Skytte Jørgensen 	return err;
63925fe467eeSIvan Skytte Jørgensen }
63935fe467eeSIvan Skytte Jørgensen 
63941da177e4SLinus Torvalds /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
63951da177e4SLinus Torvalds  *
63961da177e4SLinus Torvalds  * Requests that the local SCTP stack use the enclosed peer address as
63971da177e4SLinus Torvalds  * the association primary.  The enclosed address must be one of the
63981da177e4SLinus Torvalds  * association peer's addresses.
63991da177e4SLinus Torvalds  */
64001da177e4SLinus Torvalds static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
64011da177e4SLinus Torvalds 					char __user *optval, int __user *optlen)
64021da177e4SLinus Torvalds {
64031da177e4SLinus Torvalds 	struct sctp_prim prim;
64041da177e4SLinus Torvalds 	struct sctp_association *asoc;
64051da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
64061da177e4SLinus Torvalds 
6407408f22e8SNeil Horman 	if (len < sizeof(struct sctp_prim))
64081da177e4SLinus Torvalds 		return -EINVAL;
64091da177e4SLinus Torvalds 
6410408f22e8SNeil Horman 	len = sizeof(struct sctp_prim);
6411408f22e8SNeil Horman 
6412408f22e8SNeil Horman 	if (copy_from_user(&prim, optval, len))
64131da177e4SLinus Torvalds 		return -EFAULT;
64141da177e4SLinus Torvalds 
64151da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, prim.ssp_assoc_id);
64161da177e4SLinus Torvalds 	if (!asoc)
64171da177e4SLinus Torvalds 		return -EINVAL;
64181da177e4SLinus Torvalds 
64191da177e4SLinus Torvalds 	if (!asoc->peer.primary_path)
64201da177e4SLinus Torvalds 		return -ENOTCONN;
64211da177e4SLinus Torvalds 
64228cec6b80SAl Viro 	memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr,
64238cec6b80SAl Viro 		asoc->peer.primary_path->af_specific->sockaddr_len);
64241da177e4SLinus Torvalds 
6425299ee123SJason Gunthorpe 	sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp,
64261da177e4SLinus Torvalds 			(union sctp_addr *)&prim.ssp_addr);
64271da177e4SLinus Torvalds 
6428408f22e8SNeil Horman 	if (put_user(len, optlen))
6429408f22e8SNeil Horman 		return -EFAULT;
6430408f22e8SNeil Horman 	if (copy_to_user(optval, &prim, len))
64311da177e4SLinus Torvalds 		return -EFAULT;
64321da177e4SLinus Torvalds 
64331da177e4SLinus Torvalds 	return 0;
64341da177e4SLinus Torvalds }
64351da177e4SLinus Torvalds 
64361da177e4SLinus Torvalds /*
64370f3fffd8SIvan Skytte Jorgensen  * 7.1.11  Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER)
64381da177e4SLinus Torvalds  *
64390f3fffd8SIvan Skytte Jorgensen  * Requests that the local endpoint set the specified Adaptation Layer
64401da177e4SLinus Torvalds  * Indication parameter for all future INIT and INIT-ACK exchanges.
64411da177e4SLinus Torvalds  */
64420f3fffd8SIvan Skytte Jorgensen static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
64431da177e4SLinus Torvalds 				  char __user *optval, int __user *optlen)
64441da177e4SLinus Torvalds {
64450f3fffd8SIvan Skytte Jorgensen 	struct sctp_setadaptation adaptation;
64461da177e4SLinus Torvalds 
6447408f22e8SNeil Horman 	if (len < sizeof(struct sctp_setadaptation))
64481da177e4SLinus Torvalds 		return -EINVAL;
64491da177e4SLinus Torvalds 
6450408f22e8SNeil Horman 	len = sizeof(struct sctp_setadaptation);
6451408f22e8SNeil Horman 
64520f3fffd8SIvan Skytte Jorgensen 	adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind;
6453408f22e8SNeil Horman 
6454408f22e8SNeil Horman 	if (put_user(len, optlen))
6455408f22e8SNeil Horman 		return -EFAULT;
64560f3fffd8SIvan Skytte Jorgensen 	if (copy_to_user(optval, &adaptation, len))
64571da177e4SLinus Torvalds 		return -EFAULT;
6458a1ab3582SIvan Skytte Jorgensen 
64591da177e4SLinus Torvalds 	return 0;
64601da177e4SLinus Torvalds }
64611da177e4SLinus Torvalds 
64621da177e4SLinus Torvalds /*
64631da177e4SLinus Torvalds  *
64641da177e4SLinus Torvalds  * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM)
64651da177e4SLinus Torvalds  *
64661da177e4SLinus Torvalds  *   Applications that wish to use the sendto() system call may wish to
64671da177e4SLinus Torvalds  *   specify a default set of parameters that would normally be supplied
64681da177e4SLinus Torvalds  *   through the inclusion of ancillary data.  This socket option allows
64691da177e4SLinus Torvalds  *   such an application to set the default sctp_sndrcvinfo structure.
64701da177e4SLinus Torvalds 
64711da177e4SLinus Torvalds 
64721da177e4SLinus Torvalds  *   The application that wishes to use this socket option simply passes
64731da177e4SLinus Torvalds  *   in to this call the sctp_sndrcvinfo structure defined in Section
64741da177e4SLinus Torvalds  *   5.2.2) The input parameters accepted by this call include
64751da177e4SLinus Torvalds  *   sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
64761da177e4SLinus Torvalds  *   sinfo_timetolive.  The user must provide the sinfo_assoc_id field in
64771da177e4SLinus Torvalds  *   to this call if the caller is using the UDP model.
64781da177e4SLinus Torvalds  *
64791da177e4SLinus Torvalds  *   For getsockopt, it get the default sctp_sndrcvinfo structure.
64801da177e4SLinus Torvalds  */
64811da177e4SLinus Torvalds static int sctp_getsockopt_default_send_param(struct sock *sk,
64821da177e4SLinus Torvalds 					int len, char __user *optval,
64831da177e4SLinus Torvalds 					int __user *optlen)
64841da177e4SLinus Torvalds {
64851da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
64866b3fd5f3SGeir Ola Vaagland 	struct sctp_association *asoc;
64876b3fd5f3SGeir Ola Vaagland 	struct sctp_sndrcvinfo info;
64881da177e4SLinus Torvalds 
64896b3fd5f3SGeir Ola Vaagland 	if (len < sizeof(info))
64901da177e4SLinus Torvalds 		return -EINVAL;
6491408f22e8SNeil Horman 
64926b3fd5f3SGeir Ola Vaagland 	len = sizeof(info);
6493408f22e8SNeil Horman 
6494408f22e8SNeil Horman 	if (copy_from_user(&info, optval, len))
64951da177e4SLinus Torvalds 		return -EFAULT;
64961da177e4SLinus Torvalds 
64971da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
6498707e45b3SXin Long 	if (!asoc && info.sinfo_assoc_id != SCTP_FUTURE_ASSOC &&
6499707e45b3SXin Long 	    sctp_style(sk, UDP))
65001da177e4SLinus Torvalds 		return -EINVAL;
6501707e45b3SXin Long 
65021da177e4SLinus Torvalds 	if (asoc) {
65031da177e4SLinus Torvalds 		info.sinfo_stream = asoc->default_stream;
65041da177e4SLinus Torvalds 		info.sinfo_flags = asoc->default_flags;
65051da177e4SLinus Torvalds 		info.sinfo_ppid = asoc->default_ppid;
65061da177e4SLinus Torvalds 		info.sinfo_context = asoc->default_context;
65071da177e4SLinus Torvalds 		info.sinfo_timetolive = asoc->default_timetolive;
65081da177e4SLinus Torvalds 	} else {
65091da177e4SLinus Torvalds 		info.sinfo_stream = sp->default_stream;
65101da177e4SLinus Torvalds 		info.sinfo_flags = sp->default_flags;
65111da177e4SLinus Torvalds 		info.sinfo_ppid = sp->default_ppid;
65121da177e4SLinus Torvalds 		info.sinfo_context = sp->default_context;
65131da177e4SLinus Torvalds 		info.sinfo_timetolive = sp->default_timetolive;
65141da177e4SLinus Torvalds 	}
65151da177e4SLinus Torvalds 
6516408f22e8SNeil Horman 	if (put_user(len, optlen))
6517408f22e8SNeil Horman 		return -EFAULT;
6518408f22e8SNeil Horman 	if (copy_to_user(optval, &info, len))
65191da177e4SLinus Torvalds 		return -EFAULT;
65201da177e4SLinus Torvalds 
65211da177e4SLinus Torvalds 	return 0;
65221da177e4SLinus Torvalds }
65231da177e4SLinus Torvalds 
65246b3fd5f3SGeir Ola Vaagland /* RFC6458, Section 8.1.31. Set/get Default Send Parameters
65256b3fd5f3SGeir Ola Vaagland  * (SCTP_DEFAULT_SNDINFO)
65266b3fd5f3SGeir Ola Vaagland  */
65276b3fd5f3SGeir Ola Vaagland static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len,
65286b3fd5f3SGeir Ola Vaagland 					   char __user *optval,
65296b3fd5f3SGeir Ola Vaagland 					   int __user *optlen)
65306b3fd5f3SGeir Ola Vaagland {
65316b3fd5f3SGeir Ola Vaagland 	struct sctp_sock *sp = sctp_sk(sk);
65326b3fd5f3SGeir Ola Vaagland 	struct sctp_association *asoc;
65336b3fd5f3SGeir Ola Vaagland 	struct sctp_sndinfo info;
65346b3fd5f3SGeir Ola Vaagland 
65356b3fd5f3SGeir Ola Vaagland 	if (len < sizeof(info))
65366b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
65376b3fd5f3SGeir Ola Vaagland 
65386b3fd5f3SGeir Ola Vaagland 	len = sizeof(info);
65396b3fd5f3SGeir Ola Vaagland 
65406b3fd5f3SGeir Ola Vaagland 	if (copy_from_user(&info, optval, len))
65416b3fd5f3SGeir Ola Vaagland 		return -EFAULT;
65426b3fd5f3SGeir Ola Vaagland 
65436b3fd5f3SGeir Ola Vaagland 	asoc = sctp_id2assoc(sk, info.snd_assoc_id);
654492fc3bd9SXin Long 	if (!asoc && info.snd_assoc_id != SCTP_FUTURE_ASSOC &&
654592fc3bd9SXin Long 	    sctp_style(sk, UDP))
65466b3fd5f3SGeir Ola Vaagland 		return -EINVAL;
654792fc3bd9SXin Long 
65486b3fd5f3SGeir Ola Vaagland 	if (asoc) {
65496b3fd5f3SGeir Ola Vaagland 		info.snd_sid = asoc->default_stream;
65506b3fd5f3SGeir Ola Vaagland 		info.snd_flags = asoc->default_flags;
65516b3fd5f3SGeir Ola Vaagland 		info.snd_ppid = asoc->default_ppid;
65526b3fd5f3SGeir Ola Vaagland 		info.snd_context = asoc->default_context;
65536b3fd5f3SGeir Ola Vaagland 	} else {
65546b3fd5f3SGeir Ola Vaagland 		info.snd_sid = sp->default_stream;
65556b3fd5f3SGeir Ola Vaagland 		info.snd_flags = sp->default_flags;
65566b3fd5f3SGeir Ola Vaagland 		info.snd_ppid = sp->default_ppid;
65576b3fd5f3SGeir Ola Vaagland 		info.snd_context = sp->default_context;
65586b3fd5f3SGeir Ola Vaagland 	}
65596b3fd5f3SGeir Ola Vaagland 
65606b3fd5f3SGeir Ola Vaagland 	if (put_user(len, optlen))
65616b3fd5f3SGeir Ola Vaagland 		return -EFAULT;
65626b3fd5f3SGeir Ola Vaagland 	if (copy_to_user(optval, &info, len))
65636b3fd5f3SGeir Ola Vaagland 		return -EFAULT;
65646b3fd5f3SGeir Ola Vaagland 
65656b3fd5f3SGeir Ola Vaagland 	return 0;
65666b3fd5f3SGeir Ola Vaagland }
65676b3fd5f3SGeir Ola Vaagland 
65681da177e4SLinus Torvalds /*
65691da177e4SLinus Torvalds  *
65701da177e4SLinus Torvalds  * 7.1.5 SCTP_NODELAY
65711da177e4SLinus Torvalds  *
65721da177e4SLinus Torvalds  * Turn on/off any Nagle-like algorithm.  This means that packets are
65731da177e4SLinus Torvalds  * generally sent as soon as possible and no unnecessary delays are
65741da177e4SLinus Torvalds  * introduced, at the cost of more packets in the network.  Expects an
65751da177e4SLinus Torvalds  * integer boolean flag.
65761da177e4SLinus Torvalds  */
65771da177e4SLinus Torvalds 
65781da177e4SLinus Torvalds static int sctp_getsockopt_nodelay(struct sock *sk, int len,
65791da177e4SLinus Torvalds 				   char __user *optval, int __user *optlen)
65801da177e4SLinus Torvalds {
65811da177e4SLinus Torvalds 	int val;
65821da177e4SLinus Torvalds 
65831da177e4SLinus Torvalds 	if (len < sizeof(int))
65841da177e4SLinus Torvalds 		return -EINVAL;
65851da177e4SLinus Torvalds 
65861da177e4SLinus Torvalds 	len = sizeof(int);
65871da177e4SLinus Torvalds 	val = (sctp_sk(sk)->nodelay == 1);
65881da177e4SLinus Torvalds 	if (put_user(len, optlen))
65891da177e4SLinus Torvalds 		return -EFAULT;
65901da177e4SLinus Torvalds 	if (copy_to_user(optval, &val, len))
65911da177e4SLinus Torvalds 		return -EFAULT;
65921da177e4SLinus Torvalds 	return 0;
65931da177e4SLinus Torvalds }
65941da177e4SLinus Torvalds 
65951da177e4SLinus Torvalds /*
65961da177e4SLinus Torvalds  *
65971da177e4SLinus Torvalds  * 7.1.1 SCTP_RTOINFO
65981da177e4SLinus Torvalds  *
65991da177e4SLinus Torvalds  * The protocol parameters used to initialize and bound retransmission
66001da177e4SLinus Torvalds  * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access
66011da177e4SLinus Torvalds  * and modify these parameters.
66021da177e4SLinus Torvalds  * All parameters are time values, in milliseconds.  A value of 0, when
66031da177e4SLinus Torvalds  * modifying the parameters, indicates that the current value should not
66041da177e4SLinus Torvalds  * be changed.
66051da177e4SLinus Torvalds  *
66061da177e4SLinus Torvalds  */
66071da177e4SLinus Torvalds static int sctp_getsockopt_rtoinfo(struct sock *sk, int len,
66081da177e4SLinus Torvalds 				char __user *optval,
66091da177e4SLinus Torvalds 				int __user *optlen) {
66101da177e4SLinus Torvalds 	struct sctp_rtoinfo rtoinfo;
66111da177e4SLinus Torvalds 	struct sctp_association *asoc;
66121da177e4SLinus Torvalds 
6613408f22e8SNeil Horman 	if (len < sizeof (struct sctp_rtoinfo))
66141da177e4SLinus Torvalds 		return -EINVAL;
66151da177e4SLinus Torvalds 
6616408f22e8SNeil Horman 	len = sizeof(struct sctp_rtoinfo);
6617408f22e8SNeil Horman 
6618408f22e8SNeil Horman 	if (copy_from_user(&rtoinfo, optval, len))
66191da177e4SLinus Torvalds 		return -EFAULT;
66201da177e4SLinus Torvalds 
66211da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id);
66221da177e4SLinus Torvalds 
66237adb5ed5SXin Long 	if (!asoc && rtoinfo.srto_assoc_id != SCTP_FUTURE_ASSOC &&
66247adb5ed5SXin Long 	    sctp_style(sk, UDP))
66251da177e4SLinus Torvalds 		return -EINVAL;
66261da177e4SLinus Torvalds 
66271da177e4SLinus Torvalds 	/* Values corresponding to the specific association. */
66281da177e4SLinus Torvalds 	if (asoc) {
66291da177e4SLinus Torvalds 		rtoinfo.srto_initial = jiffies_to_msecs(asoc->rto_initial);
66301da177e4SLinus Torvalds 		rtoinfo.srto_max = jiffies_to_msecs(asoc->rto_max);
66311da177e4SLinus Torvalds 		rtoinfo.srto_min = jiffies_to_msecs(asoc->rto_min);
66321da177e4SLinus Torvalds 	} else {
66331da177e4SLinus Torvalds 		/* Values corresponding to the endpoint. */
66341da177e4SLinus Torvalds 		struct sctp_sock *sp = sctp_sk(sk);
66351da177e4SLinus Torvalds 
66361da177e4SLinus Torvalds 		rtoinfo.srto_initial = sp->rtoinfo.srto_initial;
66371da177e4SLinus Torvalds 		rtoinfo.srto_max = sp->rtoinfo.srto_max;
66381da177e4SLinus Torvalds 		rtoinfo.srto_min = sp->rtoinfo.srto_min;
66391da177e4SLinus Torvalds 	}
66401da177e4SLinus Torvalds 
66411da177e4SLinus Torvalds 	if (put_user(len, optlen))
66421da177e4SLinus Torvalds 		return -EFAULT;
66431da177e4SLinus Torvalds 
66441da177e4SLinus Torvalds 	if (copy_to_user(optval, &rtoinfo, len))
66451da177e4SLinus Torvalds 		return -EFAULT;
66461da177e4SLinus Torvalds 
66471da177e4SLinus Torvalds 	return 0;
66481da177e4SLinus Torvalds }
66491da177e4SLinus Torvalds 
66501da177e4SLinus Torvalds /*
66511da177e4SLinus Torvalds  *
66521da177e4SLinus Torvalds  * 7.1.2 SCTP_ASSOCINFO
66531da177e4SLinus Torvalds  *
665459c51591SMichael Opdenacker  * This option is used to tune the maximum retransmission attempts
66551da177e4SLinus Torvalds  * of the association.
66561da177e4SLinus Torvalds  * Returns an error if the new association retransmission value is
66571da177e4SLinus Torvalds  * greater than the sum of the retransmission value  of the peer.
66581da177e4SLinus Torvalds  * See [SCTP] for more information.
66591da177e4SLinus Torvalds  *
66601da177e4SLinus Torvalds  */
66611da177e4SLinus Torvalds static int sctp_getsockopt_associnfo(struct sock *sk, int len,
66621da177e4SLinus Torvalds 				     char __user *optval,
66631da177e4SLinus Torvalds 				     int __user *optlen)
66641da177e4SLinus Torvalds {
66651da177e4SLinus Torvalds 
66661da177e4SLinus Torvalds 	struct sctp_assocparams assocparams;
66671da177e4SLinus Torvalds 	struct sctp_association *asoc;
66681da177e4SLinus Torvalds 	struct list_head *pos;
66691da177e4SLinus Torvalds 	int cnt = 0;
66701da177e4SLinus Torvalds 
6671408f22e8SNeil Horman 	if (len < sizeof (struct sctp_assocparams))
66721da177e4SLinus Torvalds 		return -EINVAL;
66731da177e4SLinus Torvalds 
6674408f22e8SNeil Horman 	len = sizeof(struct sctp_assocparams);
6675408f22e8SNeil Horman 
6676408f22e8SNeil Horman 	if (copy_from_user(&assocparams, optval, len))
66771da177e4SLinus Torvalds 		return -EFAULT;
66781da177e4SLinus Torvalds 
66791da177e4SLinus Torvalds 	asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id);
66801da177e4SLinus Torvalds 
66818889394dSXin Long 	if (!asoc && assocparams.sasoc_assoc_id != SCTP_FUTURE_ASSOC &&
66828889394dSXin Long 	    sctp_style(sk, UDP))
66831da177e4SLinus Torvalds 		return -EINVAL;
66841da177e4SLinus Torvalds 
66851da177e4SLinus Torvalds 	/* Values correspoinding to the specific association */
668617337216SVladislav Yasevich 	if (asoc) {
66871da177e4SLinus Torvalds 		assocparams.sasoc_asocmaxrxt = asoc->max_retrans;
66881da177e4SLinus Torvalds 		assocparams.sasoc_peer_rwnd = asoc->peer.rwnd;
66891da177e4SLinus Torvalds 		assocparams.sasoc_local_rwnd = asoc->a_rwnd;
669052db882fSDaniel Borkmann 		assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life);
66911da177e4SLinus Torvalds 
66921da177e4SLinus Torvalds 		list_for_each(pos, &asoc->peer.transport_addr_list) {
66931da177e4SLinus Torvalds 			cnt++;
66941da177e4SLinus Torvalds 		}
66951da177e4SLinus Torvalds 
66961da177e4SLinus Torvalds 		assocparams.sasoc_number_peer_destinations = cnt;
66971da177e4SLinus Torvalds 	} else {
66981da177e4SLinus Torvalds 		/* Values corresponding to the endpoint */
66991da177e4SLinus Torvalds 		struct sctp_sock *sp = sctp_sk(sk);
67001da177e4SLinus Torvalds 
67011da177e4SLinus Torvalds 		assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt;
67021da177e4SLinus Torvalds 		assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd;
67031da177e4SLinus Torvalds 		assocparams.sasoc_local_rwnd = sp->assocparams.sasoc_local_rwnd;
67041da177e4SLinus Torvalds 		assocparams.sasoc_cookie_life =
67051da177e4SLinus Torvalds 					sp->assocparams.sasoc_cookie_life;
67061da177e4SLinus Torvalds 		assocparams.sasoc_number_peer_destinations =
67071da177e4SLinus Torvalds 					sp->assocparams.
67081da177e4SLinus Torvalds 					sasoc_number_peer_destinations;
67091da177e4SLinus Torvalds 	}
67101da177e4SLinus Torvalds 
67111da177e4SLinus Torvalds 	if (put_user(len, optlen))
67121da177e4SLinus Torvalds 		return -EFAULT;
67131da177e4SLinus Torvalds 
67141da177e4SLinus Torvalds 	if (copy_to_user(optval, &assocparams, len))
67151da177e4SLinus Torvalds 		return -EFAULT;
67161da177e4SLinus Torvalds 
67171da177e4SLinus Torvalds 	return 0;
67181da177e4SLinus Torvalds }
67191da177e4SLinus Torvalds 
67201da177e4SLinus Torvalds /*
67211da177e4SLinus Torvalds  * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
67221da177e4SLinus Torvalds  *
67231da177e4SLinus Torvalds  * This socket option is a boolean flag which turns on or off mapped V4
67241da177e4SLinus Torvalds  * addresses.  If this option is turned on and the socket is type
67251da177e4SLinus Torvalds  * PF_INET6, then IPv4 addresses will be mapped to V6 representation.
67261da177e4SLinus Torvalds  * If this option is turned off, then no mapping will be done of V4
67271da177e4SLinus Torvalds  * addresses and a user will receive both PF_INET6 and PF_INET type
67281da177e4SLinus Torvalds  * addresses on the socket.
67291da177e4SLinus Torvalds  */
67301da177e4SLinus Torvalds static int sctp_getsockopt_mappedv4(struct sock *sk, int len,
67311da177e4SLinus Torvalds 				    char __user *optval, int __user *optlen)
67321da177e4SLinus Torvalds {
67331da177e4SLinus Torvalds 	int val;
67341da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
67351da177e4SLinus Torvalds 
67361da177e4SLinus Torvalds 	if (len < sizeof(int))
67371da177e4SLinus Torvalds 		return -EINVAL;
67381da177e4SLinus Torvalds 
67391da177e4SLinus Torvalds 	len = sizeof(int);
67401da177e4SLinus Torvalds 	val = sp->v4mapped;
67411da177e4SLinus Torvalds 	if (put_user(len, optlen))
67421da177e4SLinus Torvalds 		return -EFAULT;
67431da177e4SLinus Torvalds 	if (copy_to_user(optval, &val, len))
67441da177e4SLinus Torvalds 		return -EFAULT;
67451da177e4SLinus Torvalds 
67461da177e4SLinus Torvalds 	return 0;
67471da177e4SLinus Torvalds }
67481da177e4SLinus Torvalds 
67491da177e4SLinus Torvalds /*
67506ab792f5SIvan Skytte Jorgensen  * 7.1.29.  Set or Get the default context (SCTP_CONTEXT)
67516ab792f5SIvan Skytte Jorgensen  * (chapter and verse is quoted at sctp_setsockopt_context())
67526ab792f5SIvan Skytte Jorgensen  */
67536ab792f5SIvan Skytte Jorgensen static int sctp_getsockopt_context(struct sock *sk, int len,
67546ab792f5SIvan Skytte Jorgensen 				   char __user *optval, int __user *optlen)
67556ab792f5SIvan Skytte Jorgensen {
67566ab792f5SIvan Skytte Jorgensen 	struct sctp_assoc_value params;
67576ab792f5SIvan Skytte Jorgensen 	struct sctp_association *asoc;
67586ab792f5SIvan Skytte Jorgensen 
6759408f22e8SNeil Horman 	if (len < sizeof(struct sctp_assoc_value))
67606ab792f5SIvan Skytte Jorgensen 		return -EINVAL;
67616ab792f5SIvan Skytte Jorgensen 
6762408f22e8SNeil Horman 	len = sizeof(struct sctp_assoc_value);
6763408f22e8SNeil Horman 
67646ab792f5SIvan Skytte Jorgensen 	if (copy_from_user(&params, optval, len))
67656ab792f5SIvan Skytte Jorgensen 		return -EFAULT;
67666ab792f5SIvan Skytte Jorgensen 
67676ab792f5SIvan Skytte Jorgensen 	asoc = sctp_id2assoc(sk, params.assoc_id);
676849b037acSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
676949b037acSXin Long 	    sctp_style(sk, UDP))
67706ab792f5SIvan Skytte Jorgensen 		return -EINVAL;
677149b037acSXin Long 
677249b037acSXin Long 	params.assoc_value = asoc ? asoc->default_rcv_context
677349b037acSXin Long 				  : sctp_sk(sk)->default_rcv_context;
67746ab792f5SIvan Skytte Jorgensen 
67756ab792f5SIvan Skytte Jorgensen 	if (put_user(len, optlen))
67766ab792f5SIvan Skytte Jorgensen 		return -EFAULT;
67776ab792f5SIvan Skytte Jorgensen 	if (copy_to_user(optval, &params, len))
67786ab792f5SIvan Skytte Jorgensen 		return -EFAULT;
67796ab792f5SIvan Skytte Jorgensen 
67806ab792f5SIvan Skytte Jorgensen 	return 0;
67816ab792f5SIvan Skytte Jorgensen }
67826ab792f5SIvan Skytte Jorgensen 
67836ab792f5SIvan Skytte Jorgensen /*
6784e89c2095SWei Yongjun  * 8.1.16.  Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
6785e89c2095SWei Yongjun  * This option will get or set the maximum size to put in any outgoing
6786e89c2095SWei Yongjun  * SCTP DATA chunk.  If a message is larger than this size it will be
67871da177e4SLinus Torvalds  * fragmented by SCTP into the specified size.  Note that the underlying
67881da177e4SLinus Torvalds  * SCTP implementation may fragment into smaller sized chunks when the
67891da177e4SLinus Torvalds  * PMTU of the underlying association is smaller than the value set by
6790e89c2095SWei Yongjun  * the user.  The default value for this option is '0' which indicates
6791e89c2095SWei Yongjun  * the user is NOT limiting fragmentation and only the PMTU will effect
6792e89c2095SWei Yongjun  * SCTP's choice of DATA chunk size.  Note also that values set larger
6793e89c2095SWei Yongjun  * than the maximum size of an IP datagram will effectively let SCTP
6794e89c2095SWei Yongjun  * control fragmentation (i.e. the same as setting this option to 0).
6795e89c2095SWei Yongjun  *
6796e89c2095SWei Yongjun  * The following structure is used to access and modify this parameter:
6797e89c2095SWei Yongjun  *
6798e89c2095SWei Yongjun  * struct sctp_assoc_value {
6799e89c2095SWei Yongjun  *   sctp_assoc_t assoc_id;
6800e89c2095SWei Yongjun  *   uint32_t assoc_value;
6801e89c2095SWei Yongjun  * };
6802e89c2095SWei Yongjun  *
6803e89c2095SWei Yongjun  * assoc_id:  This parameter is ignored for one-to-one style sockets.
6804e89c2095SWei Yongjun  *    For one-to-many style sockets this parameter indicates which
6805e89c2095SWei Yongjun  *    association the user is performing an action upon.  Note that if
6806e89c2095SWei Yongjun  *    this field's value is zero then the endpoints default value is
6807e89c2095SWei Yongjun  *    changed (effecting future associations only).
6808e89c2095SWei Yongjun  * assoc_value:  This parameter specifies the maximum size in bytes.
68091da177e4SLinus Torvalds  */
68101da177e4SLinus Torvalds static int sctp_getsockopt_maxseg(struct sock *sk, int len,
68111da177e4SLinus Torvalds 				  char __user *optval, int __user *optlen)
68121da177e4SLinus Torvalds {
6813e89c2095SWei Yongjun 	struct sctp_assoc_value params;
6814e89c2095SWei Yongjun 	struct sctp_association *asoc;
68151da177e4SLinus Torvalds 
6816e89c2095SWei Yongjun 	if (len == sizeof(int)) {
681794f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
6818f916ec96SNeil Horman 				    "%s (pid %d) "
681994f65193SNeil Horman 				    "Use of int in maxseg socket option.\n"
6820f916ec96SNeil Horman 				    "Use struct sctp_assoc_value instead\n",
6821f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
68226fd769beSXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
6823e89c2095SWei Yongjun 	} else if (len >= sizeof(struct sctp_assoc_value)) {
6824e89c2095SWei Yongjun 		len = sizeof(struct sctp_assoc_value);
6825c76f97c9SMarcelo Ricardo Leitner 		if (copy_from_user(&params, optval, len))
6826e89c2095SWei Yongjun 			return -EFAULT;
6827e89c2095SWei Yongjun 	} else
68281da177e4SLinus Torvalds 		return -EINVAL;
68291da177e4SLinus Torvalds 
6830e89c2095SWei Yongjun 	asoc = sctp_id2assoc(sk, params.assoc_id);
68316fd769beSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
68326fd769beSXin Long 	    sctp_style(sk, UDP))
6833e89c2095SWei Yongjun 		return -EINVAL;
68341da177e4SLinus Torvalds 
6835e89c2095SWei Yongjun 	if (asoc)
6836e89c2095SWei Yongjun 		params.assoc_value = asoc->frag_point;
6837e89c2095SWei Yongjun 	else
6838e89c2095SWei Yongjun 		params.assoc_value = sctp_sk(sk)->user_frag;
6839e89c2095SWei Yongjun 
68401da177e4SLinus Torvalds 	if (put_user(len, optlen))
68411da177e4SLinus Torvalds 		return -EFAULT;
6842e89c2095SWei Yongjun 	if (len == sizeof(int)) {
6843e89c2095SWei Yongjun 		if (copy_to_user(optval, &params.assoc_value, len))
68441da177e4SLinus Torvalds 			return -EFAULT;
6845e89c2095SWei Yongjun 	} else {
6846e89c2095SWei Yongjun 		if (copy_to_user(optval, &params, len))
6847e89c2095SWei Yongjun 			return -EFAULT;
6848e89c2095SWei Yongjun 	}
68491da177e4SLinus Torvalds 
68501da177e4SLinus Torvalds 	return 0;
68511da177e4SLinus Torvalds }
68521da177e4SLinus Torvalds 
6853b6e1331fSVlad Yasevich /*
6854b6e1331fSVlad Yasevich  * 7.1.24.  Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE)
6855b6e1331fSVlad Yasevich  * (chapter and verse is quoted at sctp_setsockopt_fragment_interleave())
6856b6e1331fSVlad Yasevich  */
6857b6e1331fSVlad Yasevich static int sctp_getsockopt_fragment_interleave(struct sock *sk, int len,
6858b6e1331fSVlad Yasevich 					       char __user *optval, int __user *optlen)
6859b6e1331fSVlad Yasevich {
6860b6e1331fSVlad Yasevich 	int val;
6861b6e1331fSVlad Yasevich 
6862b6e1331fSVlad Yasevich 	if (len < sizeof(int))
6863b6e1331fSVlad Yasevich 		return -EINVAL;
6864b6e1331fSVlad Yasevich 
6865b6e1331fSVlad Yasevich 	len = sizeof(int);
6866b6e1331fSVlad Yasevich 
6867b6e1331fSVlad Yasevich 	val = sctp_sk(sk)->frag_interleave;
6868b6e1331fSVlad Yasevich 	if (put_user(len, optlen))
6869b6e1331fSVlad Yasevich 		return -EFAULT;
6870b6e1331fSVlad Yasevich 	if (copy_to_user(optval, &val, len))
6871b6e1331fSVlad Yasevich 		return -EFAULT;
6872b6e1331fSVlad Yasevich 
6873b6e1331fSVlad Yasevich 	return 0;
6874b6e1331fSVlad Yasevich }
6875b6e1331fSVlad Yasevich 
6876d49d91d7SVlad Yasevich /*
6877d49d91d7SVlad Yasevich  * 7.1.25.  Set or Get the sctp partial delivery point
6878d49d91d7SVlad Yasevich  * (chapter and verse is quoted at sctp_setsockopt_partial_delivery_point())
6879d49d91d7SVlad Yasevich  */
6880d49d91d7SVlad Yasevich static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len,
6881d49d91d7SVlad Yasevich 						  char __user *optval,
6882d49d91d7SVlad Yasevich 						  int __user *optlen)
6883d49d91d7SVlad Yasevich {
6884d49d91d7SVlad Yasevich 	u32 val;
6885d49d91d7SVlad Yasevich 
6886d49d91d7SVlad Yasevich 	if (len < sizeof(u32))
6887d49d91d7SVlad Yasevich 		return -EINVAL;
6888d49d91d7SVlad Yasevich 
6889d49d91d7SVlad Yasevich 	len = sizeof(u32);
6890d49d91d7SVlad Yasevich 
6891d49d91d7SVlad Yasevich 	val = sctp_sk(sk)->pd_point;
6892d49d91d7SVlad Yasevich 	if (put_user(len, optlen))
6893d49d91d7SVlad Yasevich 		return -EFAULT;
6894d49d91d7SVlad Yasevich 	if (copy_to_user(optval, &val, len))
6895d49d91d7SVlad Yasevich 		return -EFAULT;
6896d49d91d7SVlad Yasevich 
68977d743b7eSWei Yongjun 	return 0;
6898d49d91d7SVlad Yasevich }
6899d49d91d7SVlad Yasevich 
690070331571SVlad Yasevich /*
690170331571SVlad Yasevich  * 7.1.28.  Set or Get the maximum burst (SCTP_MAX_BURST)
690270331571SVlad Yasevich  * (chapter and verse is quoted at sctp_setsockopt_maxburst())
690370331571SVlad Yasevich  */
690470331571SVlad Yasevich static int sctp_getsockopt_maxburst(struct sock *sk, int len,
690570331571SVlad Yasevich 				    char __user *optval,
690670331571SVlad Yasevich 				    int __user *optlen)
690770331571SVlad Yasevich {
6908219b99a9SNeil Horman 	struct sctp_assoc_value params;
6909219b99a9SNeil Horman 	struct sctp_association *asoc;
691070331571SVlad Yasevich 
6911219b99a9SNeil Horman 	if (len == sizeof(int)) {
691294f65193SNeil Horman 		pr_warn_ratelimited(DEPRECATED
6913f916ec96SNeil Horman 				    "%s (pid %d) "
691494f65193SNeil Horman 				    "Use of int in max_burst socket option.\n"
6915f916ec96SNeil Horman 				    "Use struct sctp_assoc_value instead\n",
6916f916ec96SNeil Horman 				    current->comm, task_pid_nr(current));
6917e0651a0dSXin Long 		params.assoc_id = SCTP_FUTURE_ASSOC;
6918c6db93a5SWei Yongjun 	} else if (len >= sizeof(struct sctp_assoc_value)) {
6919c6db93a5SWei Yongjun 		len = sizeof(struct sctp_assoc_value);
6920219b99a9SNeil Horman 		if (copy_from_user(&params, optval, len))
692170331571SVlad Yasevich 			return -EFAULT;
6922219b99a9SNeil Horman 	} else
6923219b99a9SNeil Horman 		return -EINVAL;
692470331571SVlad Yasevich 
6925219b99a9SNeil Horman 	asoc = sctp_id2assoc(sk, params.assoc_id);
6926e0651a0dSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
6927e0651a0dSXin Long 	    sctp_style(sk, UDP))
6928219b99a9SNeil Horman 		return -EINVAL;
6929e0651a0dSXin Long 
6930e0651a0dSXin Long 	params.assoc_value = asoc ? asoc->max_burst : sctp_sk(sk)->max_burst;
6931219b99a9SNeil Horman 
6932219b99a9SNeil Horman 	if (len == sizeof(int)) {
6933219b99a9SNeil Horman 		if (copy_to_user(optval, &params.assoc_value, len))
6934219b99a9SNeil Horman 			return -EFAULT;
6935219b99a9SNeil Horman 	} else {
6936219b99a9SNeil Horman 		if (copy_to_user(optval, &params, len))
6937219b99a9SNeil Horman 			return -EFAULT;
6938219b99a9SNeil Horman 	}
6939219b99a9SNeil Horman 
6940219b99a9SNeil Horman 	return 0;
6941219b99a9SNeil Horman 
694270331571SVlad Yasevich }
694370331571SVlad Yasevich 
694465b07e5dSVlad Yasevich static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
694565b07e5dSVlad Yasevich 				    char __user *optval, int __user *optlen)
694665b07e5dSVlad Yasevich {
6947b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
69485e739d17SVlad Yasevich 	struct sctp_hmacalgo  __user *p = (void __user *)optval;
694965b07e5dSVlad Yasevich 	struct sctp_hmac_algo_param *hmacs;
69505e739d17SVlad Yasevich 	__u16 data_len = 0;
69515e739d17SVlad Yasevich 	u32 num_idents;
69527a84bd46SXin Long 	int i;
69535e739d17SVlad Yasevich 
6954b14878ccSVlad Yasevich 	if (!ep->auth_enable)
69555e739d17SVlad Yasevich 		return -EACCES;
695665b07e5dSVlad Yasevich 
6957b14878ccSVlad Yasevich 	hmacs = ep->auth_hmacs_list;
69583c918704SXin Long 	data_len = ntohs(hmacs->param_hdr.length) -
69593c918704SXin Long 		   sizeof(struct sctp_paramhdr);
696065b07e5dSVlad Yasevich 
69615e739d17SVlad Yasevich 	if (len < sizeof(struct sctp_hmacalgo) + data_len)
696265b07e5dSVlad Yasevich 		return -EINVAL;
69635e739d17SVlad Yasevich 
69645e739d17SVlad Yasevich 	len = sizeof(struct sctp_hmacalgo) + data_len;
69655e739d17SVlad Yasevich 	num_idents = data_len / sizeof(u16);
69665e739d17SVlad Yasevich 
696765b07e5dSVlad Yasevich 	if (put_user(len, optlen))
696865b07e5dSVlad Yasevich 		return -EFAULT;
69695e739d17SVlad Yasevich 	if (put_user(num_idents, &p->shmac_num_idents))
697065b07e5dSVlad Yasevich 		return -EFAULT;
69717a84bd46SXin Long 	for (i = 0; i < num_idents; i++) {
69727a84bd46SXin Long 		__u16 hmacid = ntohs(hmacs->hmac_ids[i]);
69737a84bd46SXin Long 
69747a84bd46SXin Long 		if (copy_to_user(&p->shmac_idents[i], &hmacid, sizeof(__u16)))
69755e739d17SVlad Yasevich 			return -EFAULT;
69767a84bd46SXin Long 	}
697765b07e5dSVlad Yasevich 	return 0;
697865b07e5dSVlad Yasevich }
697965b07e5dSVlad Yasevich 
698065b07e5dSVlad Yasevich static int sctp_getsockopt_active_key(struct sock *sk, int len,
698165b07e5dSVlad Yasevich 				    char __user *optval, int __user *optlen)
698265b07e5dSVlad Yasevich {
6983b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
698465b07e5dSVlad Yasevich 	struct sctp_authkeyid val;
698565b07e5dSVlad Yasevich 	struct sctp_association *asoc;
698665b07e5dSVlad Yasevich 
698765b07e5dSVlad Yasevich 	if (len < sizeof(struct sctp_authkeyid))
698865b07e5dSVlad Yasevich 		return -EINVAL;
6989c76f97c9SMarcelo Ricardo Leitner 
6990c76f97c9SMarcelo Ricardo Leitner 	len = sizeof(struct sctp_authkeyid);
6991c76f97c9SMarcelo Ricardo Leitner 	if (copy_from_user(&val, optval, len))
699265b07e5dSVlad Yasevich 		return -EFAULT;
699365b07e5dSVlad Yasevich 
699465b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, val.scact_assoc_id);
699565b07e5dSVlad Yasevich 	if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
699665b07e5dSVlad Yasevich 		return -EINVAL;
699765b07e5dSVlad Yasevich 
6998219f9ea4SXin Long 	if (asoc) {
6999219f9ea4SXin Long 		if (!asoc->peer.auth_capable)
7000219f9ea4SXin Long 			return -EACCES;
700165b07e5dSVlad Yasevich 		val.scact_keynumber = asoc->active_key_id;
7002219f9ea4SXin Long 	} else {
7003219f9ea4SXin Long 		if (!ep->auth_enable)
7004219f9ea4SXin Long 			return -EACCES;
7005b14878ccSVlad Yasevich 		val.scact_keynumber = ep->active_key_id;
7006219f9ea4SXin Long 	}
700765b07e5dSVlad Yasevich 
70085e739d17SVlad Yasevich 	if (put_user(len, optlen))
70095e739d17SVlad Yasevich 		return -EFAULT;
70105e739d17SVlad Yasevich 	if (copy_to_user(optval, &val, len))
70115e739d17SVlad Yasevich 		return -EFAULT;
70125e739d17SVlad Yasevich 
701365b07e5dSVlad Yasevich 	return 0;
701465b07e5dSVlad Yasevich }
701565b07e5dSVlad Yasevich 
701665b07e5dSVlad Yasevich static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
701765b07e5dSVlad Yasevich 				    char __user *optval, int __user *optlen)
701865b07e5dSVlad Yasevich {
7019411223c0SAl Viro 	struct sctp_authchunks __user *p = (void __user *)optval;
702065b07e5dSVlad Yasevich 	struct sctp_authchunks val;
702165b07e5dSVlad Yasevich 	struct sctp_association *asoc;
702265b07e5dSVlad Yasevich 	struct sctp_chunks_param *ch;
70235e739d17SVlad Yasevich 	u32    num_chunks = 0;
702465b07e5dSVlad Yasevich 	char __user *to;
702565b07e5dSVlad Yasevich 
70265e739d17SVlad Yasevich 	if (len < sizeof(struct sctp_authchunks))
702765b07e5dSVlad Yasevich 		return -EINVAL;
702865b07e5dSVlad Yasevich 
7029c76f97c9SMarcelo Ricardo Leitner 	if (copy_from_user(&val, optval, sizeof(val)))
703065b07e5dSVlad Yasevich 		return -EFAULT;
703165b07e5dSVlad Yasevich 
7032411223c0SAl Viro 	to = p->gauth_chunks;
703365b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
703465b07e5dSVlad Yasevich 	if (!asoc)
703565b07e5dSVlad Yasevich 		return -EINVAL;
703665b07e5dSVlad Yasevich 
7037219f9ea4SXin Long 	if (!asoc->peer.auth_capable)
7038219f9ea4SXin Long 		return -EACCES;
7039219f9ea4SXin Long 
704065b07e5dSVlad Yasevich 	ch = asoc->peer.peer_chunks;
70415e739d17SVlad Yasevich 	if (!ch)
70425e739d17SVlad Yasevich 		goto num;
704365b07e5dSVlad Yasevich 
704465b07e5dSVlad Yasevich 	/* See if the user provided enough room for all the data */
70453c918704SXin Long 	num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr);
7046b40db684SVlad Yasevich 	if (len < num_chunks)
704765b07e5dSVlad Yasevich 		return -EINVAL;
704865b07e5dSVlad Yasevich 
70495e739d17SVlad Yasevich 	if (copy_to_user(to, ch->chunks, num_chunks))
705065b07e5dSVlad Yasevich 		return -EFAULT;
70515e739d17SVlad Yasevich num:
70525e739d17SVlad Yasevich 	len = sizeof(struct sctp_authchunks) + num_chunks;
70538d72651dSwangweidong 	if (put_user(len, optlen))
70548d72651dSwangweidong 		return -EFAULT;
70557e8616d8SVlad Yasevich 	if (put_user(num_chunks, &p->gauth_number_of_chunks))
70567e8616d8SVlad Yasevich 		return -EFAULT;
705765b07e5dSVlad Yasevich 	return 0;
705865b07e5dSVlad Yasevich }
705965b07e5dSVlad Yasevich 
706065b07e5dSVlad Yasevich static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
706165b07e5dSVlad Yasevich 				    char __user *optval, int __user *optlen)
706265b07e5dSVlad Yasevich {
7063b14878ccSVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
7064411223c0SAl Viro 	struct sctp_authchunks __user *p = (void __user *)optval;
706565b07e5dSVlad Yasevich 	struct sctp_authchunks val;
706665b07e5dSVlad Yasevich 	struct sctp_association *asoc;
706765b07e5dSVlad Yasevich 	struct sctp_chunks_param *ch;
70685e739d17SVlad Yasevich 	u32    num_chunks = 0;
706965b07e5dSVlad Yasevich 	char __user *to;
707065b07e5dSVlad Yasevich 
70715e739d17SVlad Yasevich 	if (len < sizeof(struct sctp_authchunks))
707265b07e5dSVlad Yasevich 		return -EINVAL;
707365b07e5dSVlad Yasevich 
7074c76f97c9SMarcelo Ricardo Leitner 	if (copy_from_user(&val, optval, sizeof(val)))
707565b07e5dSVlad Yasevich 		return -EFAULT;
707665b07e5dSVlad Yasevich 
7077411223c0SAl Viro 	to = p->gauth_chunks;
707865b07e5dSVlad Yasevich 	asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
707948c07217SXin Long 	if (!asoc && val.gauth_assoc_id != SCTP_FUTURE_ASSOC &&
708048c07217SXin Long 	    sctp_style(sk, UDP))
708165b07e5dSVlad Yasevich 		return -EINVAL;
708265b07e5dSVlad Yasevich 
7083219f9ea4SXin Long 	if (asoc) {
7084219f9ea4SXin Long 		if (!asoc->peer.auth_capable)
7085219f9ea4SXin Long 			return -EACCES;
7086219f9ea4SXin Long 		ch = (struct sctp_chunks_param *)asoc->c.auth_chunks;
7087219f9ea4SXin Long 	} else {
7088219f9ea4SXin Long 		if (!ep->auth_enable)
7089219f9ea4SXin Long 			return -EACCES;
7090219f9ea4SXin Long 		ch = ep->auth_chunk_list;
7091219f9ea4SXin Long 	}
70925e739d17SVlad Yasevich 	if (!ch)
70935e739d17SVlad Yasevich 		goto num;
70945e739d17SVlad Yasevich 
70953c918704SXin Long 	num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr);
70965e739d17SVlad Yasevich 	if (len < sizeof(struct sctp_authchunks) + num_chunks)
709765b07e5dSVlad Yasevich 		return -EINVAL;
709865b07e5dSVlad Yasevich 
70995e739d17SVlad Yasevich 	if (copy_to_user(to, ch->chunks, num_chunks))
71005e739d17SVlad Yasevich 		return -EFAULT;
71015e739d17SVlad Yasevich num:
71025e739d17SVlad Yasevich 	len = sizeof(struct sctp_authchunks) + num_chunks;
710365b07e5dSVlad Yasevich 	if (put_user(len, optlen))
710465b07e5dSVlad Yasevich 		return -EFAULT;
71057e8616d8SVlad Yasevich 	if (put_user(num_chunks, &p->gauth_number_of_chunks))
71067e8616d8SVlad Yasevich 		return -EFAULT;
710765b07e5dSVlad Yasevich 
710865b07e5dSVlad Yasevich 	return 0;
710965b07e5dSVlad Yasevich }
711065b07e5dSVlad Yasevich 
7111aea3c5c0SWei Yongjun /*
7112aea3c5c0SWei Yongjun  * 8.2.5.  Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER)
7113aea3c5c0SWei Yongjun  * This option gets the current number of associations that are attached
7114aea3c5c0SWei Yongjun  * to a one-to-many style socket.  The option value is an uint32_t.
7115aea3c5c0SWei Yongjun  */
7116aea3c5c0SWei Yongjun static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
7117aea3c5c0SWei Yongjun 				    char __user *optval, int __user *optlen)
7118aea3c5c0SWei Yongjun {
7119aea3c5c0SWei Yongjun 	struct sctp_sock *sp = sctp_sk(sk);
7120aea3c5c0SWei Yongjun 	struct sctp_association *asoc;
7121aea3c5c0SWei Yongjun 	u32 val = 0;
7122aea3c5c0SWei Yongjun 
7123aea3c5c0SWei Yongjun 	if (sctp_style(sk, TCP))
7124aea3c5c0SWei Yongjun 		return -EOPNOTSUPP;
7125aea3c5c0SWei Yongjun 
7126aea3c5c0SWei Yongjun 	if (len < sizeof(u32))
7127aea3c5c0SWei Yongjun 		return -EINVAL;
7128aea3c5c0SWei Yongjun 
7129aea3c5c0SWei Yongjun 	len = sizeof(u32);
7130aea3c5c0SWei Yongjun 
7131aea3c5c0SWei Yongjun 	list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
7132aea3c5c0SWei Yongjun 		val++;
7133aea3c5c0SWei Yongjun 	}
7134aea3c5c0SWei Yongjun 
7135aea3c5c0SWei Yongjun 	if (put_user(len, optlen))
7136aea3c5c0SWei Yongjun 		return -EFAULT;
7137aea3c5c0SWei Yongjun 	if (copy_to_user(optval, &val, len))
7138aea3c5c0SWei Yongjun 		return -EFAULT;
7139aea3c5c0SWei Yongjun 
7140aea3c5c0SWei Yongjun 	return 0;
7141aea3c5c0SWei Yongjun }
7142aea3c5c0SWei Yongjun 
7143209ba424SWei Yongjun /*
71447dc04d71SMichio Honda  * 8.1.23 SCTP_AUTO_ASCONF
71457dc04d71SMichio Honda  * See the corresponding setsockopt entry as description
71467dc04d71SMichio Honda  */
71477dc04d71SMichio Honda static int sctp_getsockopt_auto_asconf(struct sock *sk, int len,
71487dc04d71SMichio Honda 				   char __user *optval, int __user *optlen)
71497dc04d71SMichio Honda {
71507dc04d71SMichio Honda 	int val = 0;
71517dc04d71SMichio Honda 
71527dc04d71SMichio Honda 	if (len < sizeof(int))
71537dc04d71SMichio Honda 		return -EINVAL;
71547dc04d71SMichio Honda 
71557dc04d71SMichio Honda 	len = sizeof(int);
71567dc04d71SMichio Honda 	if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk))
71577dc04d71SMichio Honda 		val = 1;
71587dc04d71SMichio Honda 	if (put_user(len, optlen))
71597dc04d71SMichio Honda 		return -EFAULT;
71607dc04d71SMichio Honda 	if (copy_to_user(optval, &val, len))
71617dc04d71SMichio Honda 		return -EFAULT;
71627dc04d71SMichio Honda 	return 0;
71637dc04d71SMichio Honda }
71647dc04d71SMichio Honda 
71657dc04d71SMichio Honda /*
7166209ba424SWei Yongjun  * 8.2.6. Get the Current Identifiers of Associations
7167209ba424SWei Yongjun  *        (SCTP_GET_ASSOC_ID_LIST)
7168209ba424SWei Yongjun  *
7169209ba424SWei Yongjun  * This option gets the current list of SCTP association identifiers of
7170209ba424SWei Yongjun  * the SCTP associations handled by a one-to-many style socket.
7171209ba424SWei Yongjun  */
7172209ba424SWei Yongjun static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
7173209ba424SWei Yongjun 				    char __user *optval, int __user *optlen)
7174209ba424SWei Yongjun {
7175209ba424SWei Yongjun 	struct sctp_sock *sp = sctp_sk(sk);
7176209ba424SWei Yongjun 	struct sctp_association *asoc;
7177209ba424SWei Yongjun 	struct sctp_assoc_ids *ids;
7178209ba424SWei Yongjun 	u32 num = 0;
7179209ba424SWei Yongjun 
7180209ba424SWei Yongjun 	if (sctp_style(sk, TCP))
7181209ba424SWei Yongjun 		return -EOPNOTSUPP;
7182209ba424SWei Yongjun 
7183209ba424SWei Yongjun 	if (len < sizeof(struct sctp_assoc_ids))
7184209ba424SWei Yongjun 		return -EINVAL;
7185209ba424SWei Yongjun 
7186209ba424SWei Yongjun 	list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
7187209ba424SWei Yongjun 		num++;
7188209ba424SWei Yongjun 	}
7189209ba424SWei Yongjun 
7190209ba424SWei Yongjun 	if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num)
7191209ba424SWei Yongjun 		return -EINVAL;
7192209ba424SWei Yongjun 
7193209ba424SWei Yongjun 	len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num;
7194209ba424SWei Yongjun 
71959ba0b963SMarcelo Ricardo Leitner 	ids = kmalloc(len, GFP_USER | __GFP_NOWARN);
7196209ba424SWei Yongjun 	if (unlikely(!ids))
7197209ba424SWei Yongjun 		return -ENOMEM;
7198209ba424SWei Yongjun 
7199209ba424SWei Yongjun 	ids->gaids_number_of_ids = num;
7200209ba424SWei Yongjun 	num = 0;
7201209ba424SWei Yongjun 	list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
7202209ba424SWei Yongjun 		ids->gaids_assoc_id[num++] = asoc->assoc_id;
7203209ba424SWei Yongjun 	}
7204209ba424SWei Yongjun 
7205209ba424SWei Yongjun 	if (put_user(len, optlen) || copy_to_user(optval, ids, len)) {
7206209ba424SWei Yongjun 		kfree(ids);
7207209ba424SWei Yongjun 		return -EFAULT;
7208209ba424SWei Yongjun 	}
7209209ba424SWei Yongjun 
7210209ba424SWei Yongjun 	kfree(ids);
7211209ba424SWei Yongjun 	return 0;
7212209ba424SWei Yongjun }
7213209ba424SWei Yongjun 
72145aa93bcfSNeil Horman /*
72155aa93bcfSNeil Horman  * SCTP_PEER_ADDR_THLDS
72165aa93bcfSNeil Horman  *
72175aa93bcfSNeil Horman  * This option allows us to fetch the partially failed threshold for one or all
72185aa93bcfSNeil Horman  * transports in an association.  See Section 6.1 of:
72195aa93bcfSNeil Horman  * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt
72205aa93bcfSNeil Horman  */
72215aa93bcfSNeil Horman static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
7222d467ac0aSXin Long 					    char __user *optval, int len,
7223d467ac0aSXin Long 					    int __user *optlen, bool v2)
72245aa93bcfSNeil Horman {
7225d467ac0aSXin Long 	struct sctp_paddrthlds_v2 val;
72265aa93bcfSNeil Horman 	struct sctp_transport *trans;
72275aa93bcfSNeil Horman 	struct sctp_association *asoc;
7228d467ac0aSXin Long 	int min;
72295aa93bcfSNeil Horman 
7230d467ac0aSXin Long 	min = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds);
7231d467ac0aSXin Long 	if (len < min)
72325aa93bcfSNeil Horman 		return -EINVAL;
7233d467ac0aSXin Long 	len = min;
7234d467ac0aSXin Long 	if (copy_from_user(&val, optval, len))
72355aa93bcfSNeil Horman 		return -EFAULT;
72365aa93bcfSNeil Horman 
72378add543eSXin Long 	if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) {
72385aa93bcfSNeil Horman 		trans = sctp_addr_id2transport(sk, &val.spt_address,
72395aa93bcfSNeil Horman 					       val.spt_assoc_id);
72405aa93bcfSNeil Horman 		if (!trans)
72415aa93bcfSNeil Horman 			return -ENOENT;
72425aa93bcfSNeil Horman 
72435aa93bcfSNeil Horman 		val.spt_pathmaxrxt = trans->pathmaxrxt;
72445aa93bcfSNeil Horman 		val.spt_pathpfthld = trans->pf_retrans;
7245d467ac0aSXin Long 		val.spt_pathcpthld = trans->ps_retrans;
72468add543eSXin Long 
7247f794dc23SXin Long 		goto out;
72488add543eSXin Long 	}
72498add543eSXin Long 
72508add543eSXin Long 	asoc = sctp_id2assoc(sk, val.spt_assoc_id);
72518add543eSXin Long 	if (!asoc && val.spt_assoc_id != SCTP_FUTURE_ASSOC &&
72528add543eSXin Long 	    sctp_style(sk, UDP))
72538add543eSXin Long 		return -EINVAL;
72548add543eSXin Long 
72558add543eSXin Long 	if (asoc) {
72568add543eSXin Long 		val.spt_pathpfthld = asoc->pf_retrans;
72578add543eSXin Long 		val.spt_pathmaxrxt = asoc->pathmaxrxt;
7258d467ac0aSXin Long 		val.spt_pathcpthld = asoc->ps_retrans;
72598add543eSXin Long 	} else {
72608add543eSXin Long 		struct sctp_sock *sp = sctp_sk(sk);
72618add543eSXin Long 
72628add543eSXin Long 		val.spt_pathpfthld = sp->pf_retrans;
72638add543eSXin Long 		val.spt_pathmaxrxt = sp->pathmaxrxt;
7264d467ac0aSXin Long 		val.spt_pathcpthld = sp->ps_retrans;
72655aa93bcfSNeil Horman 	}
72665aa93bcfSNeil Horman 
7267f794dc23SXin Long out:
72685aa93bcfSNeil Horman 	if (put_user(len, optlen) || copy_to_user(optval, &val, len))
72695aa93bcfSNeil Horman 		return -EFAULT;
72705aa93bcfSNeil Horman 
72715aa93bcfSNeil Horman 	return 0;
72725aa93bcfSNeil Horman }
72735aa93bcfSNeil Horman 
7274196d6759SMichele Baldessari /*
7275196d6759SMichele Baldessari  * SCTP_GET_ASSOC_STATS
7276196d6759SMichele Baldessari  *
7277196d6759SMichele Baldessari  * This option retrieves local per endpoint statistics. It is modeled
7278196d6759SMichele Baldessari  * after OpenSolaris' implementation
7279196d6759SMichele Baldessari  */
7280196d6759SMichele Baldessari static int sctp_getsockopt_assoc_stats(struct sock *sk, int len,
7281196d6759SMichele Baldessari 				       char __user *optval,
7282196d6759SMichele Baldessari 				       int __user *optlen)
7283196d6759SMichele Baldessari {
7284196d6759SMichele Baldessari 	struct sctp_assoc_stats sas;
7285196d6759SMichele Baldessari 	struct sctp_association *asoc = NULL;
7286196d6759SMichele Baldessari 
7287196d6759SMichele Baldessari 	/* User must provide at least the assoc id */
7288196d6759SMichele Baldessari 	if (len < sizeof(sctp_assoc_t))
7289196d6759SMichele Baldessari 		return -EINVAL;
7290196d6759SMichele Baldessari 
7291726bc6b0SGuenter Roeck 	/* Allow the struct to grow and fill in as much as possible */
7292726bc6b0SGuenter Roeck 	len = min_t(size_t, len, sizeof(sas));
7293726bc6b0SGuenter Roeck 
7294196d6759SMichele Baldessari 	if (copy_from_user(&sas, optval, len))
7295196d6759SMichele Baldessari 		return -EFAULT;
7296196d6759SMichele Baldessari 
7297196d6759SMichele Baldessari 	asoc = sctp_id2assoc(sk, sas.sas_assoc_id);
7298196d6759SMichele Baldessari 	if (!asoc)
7299196d6759SMichele Baldessari 		return -EINVAL;
7300196d6759SMichele Baldessari 
7301196d6759SMichele Baldessari 	sas.sas_rtxchunks = asoc->stats.rtxchunks;
7302196d6759SMichele Baldessari 	sas.sas_gapcnt = asoc->stats.gapcnt;
7303196d6759SMichele Baldessari 	sas.sas_outofseqtsns = asoc->stats.outofseqtsns;
7304196d6759SMichele Baldessari 	sas.sas_osacks = asoc->stats.osacks;
7305196d6759SMichele Baldessari 	sas.sas_isacks = asoc->stats.isacks;
7306196d6759SMichele Baldessari 	sas.sas_octrlchunks = asoc->stats.octrlchunks;
7307196d6759SMichele Baldessari 	sas.sas_ictrlchunks = asoc->stats.ictrlchunks;
7308196d6759SMichele Baldessari 	sas.sas_oodchunks = asoc->stats.oodchunks;
7309196d6759SMichele Baldessari 	sas.sas_iodchunks = asoc->stats.iodchunks;
7310196d6759SMichele Baldessari 	sas.sas_ouodchunks = asoc->stats.ouodchunks;
7311196d6759SMichele Baldessari 	sas.sas_iuodchunks = asoc->stats.iuodchunks;
7312196d6759SMichele Baldessari 	sas.sas_idupchunks = asoc->stats.idupchunks;
7313196d6759SMichele Baldessari 	sas.sas_opackets = asoc->stats.opackets;
7314196d6759SMichele Baldessari 	sas.sas_ipackets = asoc->stats.ipackets;
7315196d6759SMichele Baldessari 
7316196d6759SMichele Baldessari 	/* New high max rto observed, will return 0 if not a single
7317196d6759SMichele Baldessari 	 * RTO update took place. obs_rto_ipaddr will be bogus
7318196d6759SMichele Baldessari 	 * in such a case
7319196d6759SMichele Baldessari 	 */
7320196d6759SMichele Baldessari 	sas.sas_maxrto = asoc->stats.max_obs_rto;
7321196d6759SMichele Baldessari 	memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr,
7322196d6759SMichele Baldessari 		sizeof(struct sockaddr_storage));
7323196d6759SMichele Baldessari 
7324196d6759SMichele Baldessari 	/* Mark beginning of a new observation period */
7325196d6759SMichele Baldessari 	asoc->stats.max_obs_rto = asoc->rto_min;
7326196d6759SMichele Baldessari 
7327196d6759SMichele Baldessari 	if (put_user(len, optlen))
7328196d6759SMichele Baldessari 		return -EFAULT;
7329196d6759SMichele Baldessari 
7330bb33381dSDaniel Borkmann 	pr_debug("%s: len:%d, assoc_id:%d\n", __func__, len, sas.sas_assoc_id);
7331196d6759SMichele Baldessari 
7332196d6759SMichele Baldessari 	if (copy_to_user(optval, &sas, len))
7333196d6759SMichele Baldessari 		return -EFAULT;
7334196d6759SMichele Baldessari 
7335196d6759SMichele Baldessari 	return 0;
7336196d6759SMichele Baldessari }
7337196d6759SMichele Baldessari 
73380d3a421dSGeir Ola Vaagland static int sctp_getsockopt_recvrcvinfo(struct sock *sk,	int len,
73390d3a421dSGeir Ola Vaagland 				       char __user *optval,
73400d3a421dSGeir Ola Vaagland 				       int __user *optlen)
73410d3a421dSGeir Ola Vaagland {
73420d3a421dSGeir Ola Vaagland 	int val = 0;
73430d3a421dSGeir Ola Vaagland 
73440d3a421dSGeir Ola Vaagland 	if (len < sizeof(int))
73450d3a421dSGeir Ola Vaagland 		return -EINVAL;
73460d3a421dSGeir Ola Vaagland 
73470d3a421dSGeir Ola Vaagland 	len = sizeof(int);
73480d3a421dSGeir Ola Vaagland 	if (sctp_sk(sk)->recvrcvinfo)
73490d3a421dSGeir Ola Vaagland 		val = 1;
73500d3a421dSGeir Ola Vaagland 	if (put_user(len, optlen))
73510d3a421dSGeir Ola Vaagland 		return -EFAULT;
73520d3a421dSGeir Ola Vaagland 	if (copy_to_user(optval, &val, len))
73530d3a421dSGeir Ola Vaagland 		return -EFAULT;
73540d3a421dSGeir Ola Vaagland 
73550d3a421dSGeir Ola Vaagland 	return 0;
73560d3a421dSGeir Ola Vaagland }
73570d3a421dSGeir Ola Vaagland 
73582347c80fSGeir Ola Vaagland static int sctp_getsockopt_recvnxtinfo(struct sock *sk,	int len,
73592347c80fSGeir Ola Vaagland 				       char __user *optval,
73602347c80fSGeir Ola Vaagland 				       int __user *optlen)
73612347c80fSGeir Ola Vaagland {
73622347c80fSGeir Ola Vaagland 	int val = 0;
73632347c80fSGeir Ola Vaagland 
73642347c80fSGeir Ola Vaagland 	if (len < sizeof(int))
73652347c80fSGeir Ola Vaagland 		return -EINVAL;
73662347c80fSGeir Ola Vaagland 
73672347c80fSGeir Ola Vaagland 	len = sizeof(int);
73682347c80fSGeir Ola Vaagland 	if (sctp_sk(sk)->recvnxtinfo)
73692347c80fSGeir Ola Vaagland 		val = 1;
73702347c80fSGeir Ola Vaagland 	if (put_user(len, optlen))
73712347c80fSGeir Ola Vaagland 		return -EFAULT;
73722347c80fSGeir Ola Vaagland 	if (copy_to_user(optval, &val, len))
73732347c80fSGeir Ola Vaagland 		return -EFAULT;
73742347c80fSGeir Ola Vaagland 
73752347c80fSGeir Ola Vaagland 	return 0;
73762347c80fSGeir Ola Vaagland }
73772347c80fSGeir Ola Vaagland 
737828aa4c26SXin Long static int sctp_getsockopt_pr_supported(struct sock *sk, int len,
737928aa4c26SXin Long 					char __user *optval,
738028aa4c26SXin Long 					int __user *optlen)
738128aa4c26SXin Long {
738228aa4c26SXin Long 	struct sctp_assoc_value params;
738328aa4c26SXin Long 	struct sctp_association *asoc;
738428aa4c26SXin Long 	int retval = -EFAULT;
738528aa4c26SXin Long 
738628aa4c26SXin Long 	if (len < sizeof(params)) {
738728aa4c26SXin Long 		retval = -EINVAL;
738828aa4c26SXin Long 		goto out;
738928aa4c26SXin Long 	}
739028aa4c26SXin Long 
739128aa4c26SXin Long 	len = sizeof(params);
739228aa4c26SXin Long 	if (copy_from_user(&params, optval, len))
739328aa4c26SXin Long 		goto out;
739428aa4c26SXin Long 
739528aa4c26SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
7396fb195605SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
7397fb195605SXin Long 	    sctp_style(sk, UDP)) {
739828aa4c26SXin Long 		retval = -EINVAL;
739928aa4c26SXin Long 		goto out;
740028aa4c26SXin Long 	}
740128aa4c26SXin Long 
74021c134753SXin Long 	params.assoc_value = asoc ? asoc->peer.prsctp_capable
7403fb195605SXin Long 				  : sctp_sk(sk)->ep->prsctp_enable;
7404fb195605SXin Long 
740528aa4c26SXin Long 	if (put_user(len, optlen))
740628aa4c26SXin Long 		goto out;
740728aa4c26SXin Long 
740828aa4c26SXin Long 	if (copy_to_user(optval, &params, len))
740928aa4c26SXin Long 		goto out;
741028aa4c26SXin Long 
741128aa4c26SXin Long 	retval = 0;
741228aa4c26SXin Long 
741328aa4c26SXin Long out:
741428aa4c26SXin Long 	return retval;
741528aa4c26SXin Long }
741628aa4c26SXin Long 
7417f959fb44SXin Long static int sctp_getsockopt_default_prinfo(struct sock *sk, int len,
7418f959fb44SXin Long 					  char __user *optval,
7419f959fb44SXin Long 					  int __user *optlen)
7420f959fb44SXin Long {
7421f959fb44SXin Long 	struct sctp_default_prinfo info;
7422f959fb44SXin Long 	struct sctp_association *asoc;
7423f959fb44SXin Long 	int retval = -EFAULT;
7424f959fb44SXin Long 
7425f959fb44SXin Long 	if (len < sizeof(info)) {
7426f959fb44SXin Long 		retval = -EINVAL;
7427f959fb44SXin Long 		goto out;
7428f959fb44SXin Long 	}
7429f959fb44SXin Long 
7430f959fb44SXin Long 	len = sizeof(info);
7431f959fb44SXin Long 	if (copy_from_user(&info, optval, len))
7432f959fb44SXin Long 		goto out;
7433f959fb44SXin Long 
7434f959fb44SXin Long 	asoc = sctp_id2assoc(sk, info.pr_assoc_id);
74353a583059SXin Long 	if (!asoc && info.pr_assoc_id != SCTP_FUTURE_ASSOC &&
74363a583059SXin Long 	    sctp_style(sk, UDP)) {
74373a583059SXin Long 		retval = -EINVAL;
74383a583059SXin Long 		goto out;
74393a583059SXin Long 	}
74403a583059SXin Long 
7441f959fb44SXin Long 	if (asoc) {
7442f959fb44SXin Long 		info.pr_policy = SCTP_PR_POLICY(asoc->default_flags);
7443f959fb44SXin Long 		info.pr_value = asoc->default_timetolive;
74443a583059SXin Long 	} else {
7445f959fb44SXin Long 		struct sctp_sock *sp = sctp_sk(sk);
7446f959fb44SXin Long 
7447f959fb44SXin Long 		info.pr_policy = SCTP_PR_POLICY(sp->default_flags);
7448f959fb44SXin Long 		info.pr_value = sp->default_timetolive;
7449f959fb44SXin Long 	}
7450f959fb44SXin Long 
7451f959fb44SXin Long 	if (put_user(len, optlen))
7452f959fb44SXin Long 		goto out;
7453f959fb44SXin Long 
7454f959fb44SXin Long 	if (copy_to_user(optval, &info, len))
7455f959fb44SXin Long 		goto out;
7456f959fb44SXin Long 
7457f959fb44SXin Long 	retval = 0;
7458f959fb44SXin Long 
7459f959fb44SXin Long out:
7460f959fb44SXin Long 	return retval;
7461f959fb44SXin Long }
7462f959fb44SXin Long 
7463826d253dSXin Long static int sctp_getsockopt_pr_assocstatus(struct sock *sk, int len,
7464826d253dSXin Long 					  char __user *optval,
7465826d253dSXin Long 					  int __user *optlen)
7466826d253dSXin Long {
7467826d253dSXin Long 	struct sctp_prstatus params;
7468826d253dSXin Long 	struct sctp_association *asoc;
7469826d253dSXin Long 	int policy;
7470826d253dSXin Long 	int retval = -EINVAL;
7471826d253dSXin Long 
7472826d253dSXin Long 	if (len < sizeof(params))
7473826d253dSXin Long 		goto out;
7474826d253dSXin Long 
7475826d253dSXin Long 	len = sizeof(params);
7476826d253dSXin Long 	if (copy_from_user(&params, optval, len)) {
7477826d253dSXin Long 		retval = -EFAULT;
7478826d253dSXin Long 		goto out;
7479826d253dSXin Long 	}
7480826d253dSXin Long 
7481826d253dSXin Long 	policy = params.sprstat_policy;
748271335836SXin Long 	if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) ||
748371335836SXin Long 	    ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK)))
7484826d253dSXin Long 		goto out;
7485826d253dSXin Long 
7486826d253dSXin Long 	asoc = sctp_id2assoc(sk, params.sprstat_assoc_id);
7487826d253dSXin Long 	if (!asoc)
7488826d253dSXin Long 		goto out;
7489826d253dSXin Long 
749071335836SXin Long 	if (policy == SCTP_PR_SCTP_ALL) {
7491826d253dSXin Long 		params.sprstat_abandoned_unsent = 0;
7492826d253dSXin Long 		params.sprstat_abandoned_sent = 0;
7493826d253dSXin Long 		for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) {
7494826d253dSXin Long 			params.sprstat_abandoned_unsent +=
7495826d253dSXin Long 				asoc->abandoned_unsent[policy];
7496826d253dSXin Long 			params.sprstat_abandoned_sent +=
7497826d253dSXin Long 				asoc->abandoned_sent[policy];
7498826d253dSXin Long 		}
7499826d253dSXin Long 	} else {
7500826d253dSXin Long 		params.sprstat_abandoned_unsent =
7501826d253dSXin Long 			asoc->abandoned_unsent[__SCTP_PR_INDEX(policy)];
7502826d253dSXin Long 		params.sprstat_abandoned_sent =
7503826d253dSXin Long 			asoc->abandoned_sent[__SCTP_PR_INDEX(policy)];
7504826d253dSXin Long 	}
7505826d253dSXin Long 
7506826d253dSXin Long 	if (put_user(len, optlen)) {
7507826d253dSXin Long 		retval = -EFAULT;
7508826d253dSXin Long 		goto out;
7509826d253dSXin Long 	}
7510826d253dSXin Long 
7511826d253dSXin Long 	if (copy_to_user(optval, &params, len)) {
7512826d253dSXin Long 		retval = -EFAULT;
7513826d253dSXin Long 		goto out;
7514826d253dSXin Long 	}
7515826d253dSXin Long 
7516826d253dSXin Long 	retval = 0;
7517826d253dSXin Long 
7518826d253dSXin Long out:
7519826d253dSXin Long 	return retval;
7520826d253dSXin Long }
7521826d253dSXin Long 
7522d229d48dSXin Long static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len,
7523d229d48dSXin Long 					   char __user *optval,
7524d229d48dSXin Long 					   int __user *optlen)
7525d229d48dSXin Long {
7526f952be79SMarcelo Ricardo Leitner 	struct sctp_stream_out_ext *streamoute;
7527d229d48dSXin Long 	struct sctp_association *asoc;
7528d229d48dSXin Long 	struct sctp_prstatus params;
7529d229d48dSXin Long 	int retval = -EINVAL;
7530d229d48dSXin Long 	int policy;
7531d229d48dSXin Long 
7532d229d48dSXin Long 	if (len < sizeof(params))
7533d229d48dSXin Long 		goto out;
7534d229d48dSXin Long 
7535d229d48dSXin Long 	len = sizeof(params);
7536d229d48dSXin Long 	if (copy_from_user(&params, optval, len)) {
7537d229d48dSXin Long 		retval = -EFAULT;
7538d229d48dSXin Long 		goto out;
7539d229d48dSXin Long 	}
7540d229d48dSXin Long 
7541d229d48dSXin Long 	policy = params.sprstat_policy;
754271335836SXin Long 	if (!policy || (policy & ~(SCTP_PR_SCTP_MASK | SCTP_PR_SCTP_ALL)) ||
754371335836SXin Long 	    ((policy & SCTP_PR_SCTP_ALL) && (policy & SCTP_PR_SCTP_MASK)))
7544d229d48dSXin Long 		goto out;
7545d229d48dSXin Long 
7546d229d48dSXin Long 	asoc = sctp_id2assoc(sk, params.sprstat_assoc_id);
7547cee360abSXin Long 	if (!asoc || params.sprstat_sid >= asoc->stream.outcnt)
7548d229d48dSXin Long 		goto out;
7549d229d48dSXin Long 
755005364ca0SKonstantin Khorenko 	streamoute = SCTP_SO(&asoc->stream, params.sprstat_sid)->ext;
7551f952be79SMarcelo Ricardo Leitner 	if (!streamoute) {
7552f952be79SMarcelo Ricardo Leitner 		/* Not allocated yet, means all stats are 0 */
7553f952be79SMarcelo Ricardo Leitner 		params.sprstat_abandoned_unsent = 0;
7554f952be79SMarcelo Ricardo Leitner 		params.sprstat_abandoned_sent = 0;
7555f952be79SMarcelo Ricardo Leitner 		retval = 0;
7556f952be79SMarcelo Ricardo Leitner 		goto out;
7557f952be79SMarcelo Ricardo Leitner 	}
7558f952be79SMarcelo Ricardo Leitner 
75590ac1077eSXin Long 	if (policy == SCTP_PR_SCTP_ALL) {
7560d229d48dSXin Long 		params.sprstat_abandoned_unsent = 0;
7561d229d48dSXin Long 		params.sprstat_abandoned_sent = 0;
7562d229d48dSXin Long 		for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) {
7563d229d48dSXin Long 			params.sprstat_abandoned_unsent +=
7564f952be79SMarcelo Ricardo Leitner 				streamoute->abandoned_unsent[policy];
7565d229d48dSXin Long 			params.sprstat_abandoned_sent +=
7566f952be79SMarcelo Ricardo Leitner 				streamoute->abandoned_sent[policy];
7567d229d48dSXin Long 		}
7568d229d48dSXin Long 	} else {
7569d229d48dSXin Long 		params.sprstat_abandoned_unsent =
7570f952be79SMarcelo Ricardo Leitner 			streamoute->abandoned_unsent[__SCTP_PR_INDEX(policy)];
7571d229d48dSXin Long 		params.sprstat_abandoned_sent =
7572f952be79SMarcelo Ricardo Leitner 			streamoute->abandoned_sent[__SCTP_PR_INDEX(policy)];
7573d229d48dSXin Long 	}
7574d229d48dSXin Long 
7575d229d48dSXin Long 	if (put_user(len, optlen) || copy_to_user(optval, &params, len)) {
7576d229d48dSXin Long 		retval = -EFAULT;
7577d229d48dSXin Long 		goto out;
7578d229d48dSXin Long 	}
7579d229d48dSXin Long 
7580d229d48dSXin Long 	retval = 0;
7581d229d48dSXin Long 
7582d229d48dSXin Long out:
7583d229d48dSXin Long 	return retval;
7584d229d48dSXin Long }
7585d229d48dSXin Long 
7586c0d8bab6SXin Long static int sctp_getsockopt_reconfig_supported(struct sock *sk, int len,
7587c0d8bab6SXin Long 					      char __user *optval,
7588c0d8bab6SXin Long 					      int __user *optlen)
7589c0d8bab6SXin Long {
7590c0d8bab6SXin Long 	struct sctp_assoc_value params;
7591c0d8bab6SXin Long 	struct sctp_association *asoc;
7592c0d8bab6SXin Long 	int retval = -EFAULT;
7593c0d8bab6SXin Long 
7594c0d8bab6SXin Long 	if (len < sizeof(params)) {
7595c0d8bab6SXin Long 		retval = -EINVAL;
7596c0d8bab6SXin Long 		goto out;
7597c0d8bab6SXin Long 	}
7598c0d8bab6SXin Long 
7599c0d8bab6SXin Long 	len = sizeof(params);
7600c0d8bab6SXin Long 	if (copy_from_user(&params, optval, len))
7601c0d8bab6SXin Long 		goto out;
7602c0d8bab6SXin Long 
7603c0d8bab6SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
7604acce7f3bSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
7605acce7f3bSXin Long 	    sctp_style(sk, UDP)) {
7606c0d8bab6SXin Long 		retval = -EINVAL;
7607c0d8bab6SXin Long 		goto out;
7608c0d8bab6SXin Long 	}
7609c0d8bab6SXin Long 
7610a96701fbSXin Long 	params.assoc_value = asoc ? asoc->peer.reconf_capable
7611acce7f3bSXin Long 				  : sctp_sk(sk)->ep->reconf_enable;
7612acce7f3bSXin Long 
7613c0d8bab6SXin Long 	if (put_user(len, optlen))
7614c0d8bab6SXin Long 		goto out;
7615c0d8bab6SXin Long 
7616c0d8bab6SXin Long 	if (copy_to_user(optval, &params, len))
7617c0d8bab6SXin Long 		goto out;
7618c0d8bab6SXin Long 
7619c0d8bab6SXin Long 	retval = 0;
7620c0d8bab6SXin Long 
7621c0d8bab6SXin Long out:
7622c0d8bab6SXin Long 	return retval;
7623c0d8bab6SXin Long }
7624c0d8bab6SXin Long 
76259fb657aeSXin Long static int sctp_getsockopt_enable_strreset(struct sock *sk, int len,
76269fb657aeSXin Long 					   char __user *optval,
76279fb657aeSXin Long 					   int __user *optlen)
76289fb657aeSXin Long {
76299fb657aeSXin Long 	struct sctp_assoc_value params;
76309fb657aeSXin Long 	struct sctp_association *asoc;
76319fb657aeSXin Long 	int retval = -EFAULT;
76329fb657aeSXin Long 
76339fb657aeSXin Long 	if (len < sizeof(params)) {
76349fb657aeSXin Long 		retval = -EINVAL;
76359fb657aeSXin Long 		goto out;
76369fb657aeSXin Long 	}
76379fb657aeSXin Long 
76389fb657aeSXin Long 	len = sizeof(params);
76399fb657aeSXin Long 	if (copy_from_user(&params, optval, len))
76409fb657aeSXin Long 		goto out;
76419fb657aeSXin Long 
76429fb657aeSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
764399a62135SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
764499a62135SXin Long 	    sctp_style(sk, UDP)) {
76459fb657aeSXin Long 		retval = -EINVAL;
76469fb657aeSXin Long 		goto out;
76479fb657aeSXin Long 	}
76489fb657aeSXin Long 
764999a62135SXin Long 	params.assoc_value = asoc ? asoc->strreset_enable
765099a62135SXin Long 				  : sctp_sk(sk)->ep->strreset_enable;
765199a62135SXin Long 
76529fb657aeSXin Long 	if (put_user(len, optlen))
76539fb657aeSXin Long 		goto out;
76549fb657aeSXin Long 
76559fb657aeSXin Long 	if (copy_to_user(optval, &params, len))
76569fb657aeSXin Long 		goto out;
76579fb657aeSXin Long 
76589fb657aeSXin Long 	retval = 0;
76599fb657aeSXin Long 
76609fb657aeSXin Long out:
76619fb657aeSXin Long 	return retval;
76629fb657aeSXin Long }
76639fb657aeSXin Long 
766413aa8770SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler(struct sock *sk, int len,
766513aa8770SMarcelo Ricardo Leitner 				     char __user *optval,
766613aa8770SMarcelo Ricardo Leitner 				     int __user *optlen)
766713aa8770SMarcelo Ricardo Leitner {
766813aa8770SMarcelo Ricardo Leitner 	struct sctp_assoc_value params;
766913aa8770SMarcelo Ricardo Leitner 	struct sctp_association *asoc;
767013aa8770SMarcelo Ricardo Leitner 	int retval = -EFAULT;
767113aa8770SMarcelo Ricardo Leitner 
767213aa8770SMarcelo Ricardo Leitner 	if (len < sizeof(params)) {
767313aa8770SMarcelo Ricardo Leitner 		retval = -EINVAL;
767413aa8770SMarcelo Ricardo Leitner 		goto out;
767513aa8770SMarcelo Ricardo Leitner 	}
767613aa8770SMarcelo Ricardo Leitner 
767713aa8770SMarcelo Ricardo Leitner 	len = sizeof(params);
767813aa8770SMarcelo Ricardo Leitner 	if (copy_from_user(&params, optval, len))
767913aa8770SMarcelo Ricardo Leitner 		goto out;
768013aa8770SMarcelo Ricardo Leitner 
768113aa8770SMarcelo Ricardo Leitner 	asoc = sctp_id2assoc(sk, params.assoc_id);
76827efba10dSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
76837efba10dSXin Long 	    sctp_style(sk, UDP)) {
768413aa8770SMarcelo Ricardo Leitner 		retval = -EINVAL;
768513aa8770SMarcelo Ricardo Leitner 		goto out;
768613aa8770SMarcelo Ricardo Leitner 	}
768713aa8770SMarcelo Ricardo Leitner 
76887efba10dSXin Long 	params.assoc_value = asoc ? sctp_sched_get_sched(asoc)
76897efba10dSXin Long 				  : sctp_sk(sk)->default_ss;
769013aa8770SMarcelo Ricardo Leitner 
769113aa8770SMarcelo Ricardo Leitner 	if (put_user(len, optlen))
769213aa8770SMarcelo Ricardo Leitner 		goto out;
769313aa8770SMarcelo Ricardo Leitner 
769413aa8770SMarcelo Ricardo Leitner 	if (copy_to_user(optval, &params, len))
769513aa8770SMarcelo Ricardo Leitner 		goto out;
769613aa8770SMarcelo Ricardo Leitner 
769713aa8770SMarcelo Ricardo Leitner 	retval = 0;
769813aa8770SMarcelo Ricardo Leitner 
769913aa8770SMarcelo Ricardo Leitner out:
770013aa8770SMarcelo Ricardo Leitner 	return retval;
770113aa8770SMarcelo Ricardo Leitner }
770213aa8770SMarcelo Ricardo Leitner 
77030ccdf3c7SMarcelo Ricardo Leitner static int sctp_getsockopt_scheduler_value(struct sock *sk, int len,
77040ccdf3c7SMarcelo Ricardo Leitner 					   char __user *optval,
77050ccdf3c7SMarcelo Ricardo Leitner 					   int __user *optlen)
77060ccdf3c7SMarcelo Ricardo Leitner {
77070ccdf3c7SMarcelo Ricardo Leitner 	struct sctp_stream_value params;
77080ccdf3c7SMarcelo Ricardo Leitner 	struct sctp_association *asoc;
77090ccdf3c7SMarcelo Ricardo Leitner 	int retval = -EFAULT;
77100ccdf3c7SMarcelo Ricardo Leitner 
77110ccdf3c7SMarcelo Ricardo Leitner 	if (len < sizeof(params)) {
77120ccdf3c7SMarcelo Ricardo Leitner 		retval = -EINVAL;
77130ccdf3c7SMarcelo Ricardo Leitner 		goto out;
77140ccdf3c7SMarcelo Ricardo Leitner 	}
77150ccdf3c7SMarcelo Ricardo Leitner 
77160ccdf3c7SMarcelo Ricardo Leitner 	len = sizeof(params);
77170ccdf3c7SMarcelo Ricardo Leitner 	if (copy_from_user(&params, optval, len))
77180ccdf3c7SMarcelo Ricardo Leitner 		goto out;
77190ccdf3c7SMarcelo Ricardo Leitner 
77200ccdf3c7SMarcelo Ricardo Leitner 	asoc = sctp_id2assoc(sk, params.assoc_id);
77210ccdf3c7SMarcelo Ricardo Leitner 	if (!asoc) {
77220ccdf3c7SMarcelo Ricardo Leitner 		retval = -EINVAL;
77230ccdf3c7SMarcelo Ricardo Leitner 		goto out;
77240ccdf3c7SMarcelo Ricardo Leitner 	}
77250ccdf3c7SMarcelo Ricardo Leitner 
77260ccdf3c7SMarcelo Ricardo Leitner 	retval = sctp_sched_get_value(asoc, params.stream_id,
77270ccdf3c7SMarcelo Ricardo Leitner 				      &params.stream_value);
77280ccdf3c7SMarcelo Ricardo Leitner 	if (retval)
77290ccdf3c7SMarcelo Ricardo Leitner 		goto out;
77300ccdf3c7SMarcelo Ricardo Leitner 
77310ccdf3c7SMarcelo Ricardo Leitner 	if (put_user(len, optlen)) {
77320ccdf3c7SMarcelo Ricardo Leitner 		retval = -EFAULT;
77330ccdf3c7SMarcelo Ricardo Leitner 		goto out;
77340ccdf3c7SMarcelo Ricardo Leitner 	}
77350ccdf3c7SMarcelo Ricardo Leitner 
77360ccdf3c7SMarcelo Ricardo Leitner 	if (copy_to_user(optval, &params, len)) {
77370ccdf3c7SMarcelo Ricardo Leitner 		retval = -EFAULT;
77380ccdf3c7SMarcelo Ricardo Leitner 		goto out;
77390ccdf3c7SMarcelo Ricardo Leitner 	}
77400ccdf3c7SMarcelo Ricardo Leitner 
77410ccdf3c7SMarcelo Ricardo Leitner out:
77420ccdf3c7SMarcelo Ricardo Leitner 	return retval;
77430ccdf3c7SMarcelo Ricardo Leitner }
77440ccdf3c7SMarcelo Ricardo Leitner 
7745772a5869SXin Long static int sctp_getsockopt_interleaving_supported(struct sock *sk, int len,
7746772a5869SXin Long 						  char __user *optval,
7747772a5869SXin Long 						  int __user *optlen)
7748772a5869SXin Long {
7749772a5869SXin Long 	struct sctp_assoc_value params;
7750772a5869SXin Long 	struct sctp_association *asoc;
7751772a5869SXin Long 	int retval = -EFAULT;
7752772a5869SXin Long 
7753772a5869SXin Long 	if (len < sizeof(params)) {
7754772a5869SXin Long 		retval = -EINVAL;
7755772a5869SXin Long 		goto out;
7756772a5869SXin Long 	}
7757772a5869SXin Long 
7758772a5869SXin Long 	len = sizeof(params);
7759772a5869SXin Long 	if (copy_from_user(&params, optval, len))
7760772a5869SXin Long 		goto out;
7761772a5869SXin Long 
7762772a5869SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
77632e7709d1SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
77642e7709d1SXin Long 	    sctp_style(sk, UDP)) {
7765772a5869SXin Long 		retval = -EINVAL;
7766772a5869SXin Long 		goto out;
7767772a5869SXin Long 	}
7768772a5869SXin Long 
7769da1f6d4dSXin Long 	params.assoc_value = asoc ? asoc->peer.intl_capable
7770e55f4b8bSXin Long 				  : sctp_sk(sk)->ep->intl_enable;
77712e7709d1SXin Long 
7772772a5869SXin Long 	if (put_user(len, optlen))
7773772a5869SXin Long 		goto out;
7774772a5869SXin Long 
7775772a5869SXin Long 	if (copy_to_user(optval, &params, len))
7776772a5869SXin Long 		goto out;
7777772a5869SXin Long 
7778772a5869SXin Long 	retval = 0;
7779772a5869SXin Long 
7780772a5869SXin Long out:
7781772a5869SXin Long 	return retval;
7782772a5869SXin Long }
7783772a5869SXin Long 
7784b0e9a2feSXin Long static int sctp_getsockopt_reuse_port(struct sock *sk, int len,
7785b0e9a2feSXin Long 				      char __user *optval,
7786b0e9a2feSXin Long 				      int __user *optlen)
7787b0e9a2feSXin Long {
7788b0e9a2feSXin Long 	int val;
7789b0e9a2feSXin Long 
7790b0e9a2feSXin Long 	if (len < sizeof(int))
7791b0e9a2feSXin Long 		return -EINVAL;
7792b0e9a2feSXin Long 
7793b0e9a2feSXin Long 	len = sizeof(int);
7794b0e9a2feSXin Long 	val = sctp_sk(sk)->reuse;
7795b0e9a2feSXin Long 	if (put_user(len, optlen))
7796b0e9a2feSXin Long 		return -EFAULT;
7797b0e9a2feSXin Long 
7798b0e9a2feSXin Long 	if (copy_to_user(optval, &val, len))
7799b0e9a2feSXin Long 		return -EFAULT;
7800b0e9a2feSXin Long 
7801b0e9a2feSXin Long 	return 0;
7802b0e9a2feSXin Long }
7803b0e9a2feSXin Long 
7804480ba9c1SXin Long static int sctp_getsockopt_event(struct sock *sk, int len, char __user *optval,
7805480ba9c1SXin Long 				 int __user *optlen)
7806480ba9c1SXin Long {
7807480ba9c1SXin Long 	struct sctp_association *asoc;
7808480ba9c1SXin Long 	struct sctp_event param;
7809480ba9c1SXin Long 	__u16 subscribe;
7810480ba9c1SXin Long 
7811480ba9c1SXin Long 	if (len < sizeof(param))
7812480ba9c1SXin Long 		return -EINVAL;
7813480ba9c1SXin Long 
7814480ba9c1SXin Long 	len = sizeof(param);
7815480ba9c1SXin Long 	if (copy_from_user(&param, optval, len))
7816480ba9c1SXin Long 		return -EFAULT;
7817480ba9c1SXin Long 
7818480ba9c1SXin Long 	if (param.se_type < SCTP_SN_TYPE_BASE ||
7819480ba9c1SXin Long 	    param.se_type > SCTP_SN_TYPE_MAX)
7820480ba9c1SXin Long 		return -EINVAL;
7821480ba9c1SXin Long 
7822480ba9c1SXin Long 	asoc = sctp_id2assoc(sk, param.se_assoc_id);
7823d251f05eSXin Long 	if (!asoc && param.se_assoc_id != SCTP_FUTURE_ASSOC &&
7824d251f05eSXin Long 	    sctp_style(sk, UDP))
7825d251f05eSXin Long 		return -EINVAL;
7826d251f05eSXin Long 
7827480ba9c1SXin Long 	subscribe = asoc ? asoc->subscribe : sctp_sk(sk)->subscribe;
7828480ba9c1SXin Long 	param.se_on = sctp_ulpevent_type_enabled(subscribe, param.se_type);
7829480ba9c1SXin Long 
7830480ba9c1SXin Long 	if (put_user(len, optlen))
7831480ba9c1SXin Long 		return -EFAULT;
7832480ba9c1SXin Long 
7833480ba9c1SXin Long 	if (copy_to_user(optval, &param, len))
7834480ba9c1SXin Long 		return -EFAULT;
7835480ba9c1SXin Long 
7836480ba9c1SXin Long 	return 0;
7837480ba9c1SXin Long }
7838480ba9c1SXin Long 
7839df2c71ffSXin Long static int sctp_getsockopt_asconf_supported(struct sock *sk, int len,
7840df2c71ffSXin Long 					    char __user *optval,
7841df2c71ffSXin Long 					    int __user *optlen)
7842df2c71ffSXin Long {
7843df2c71ffSXin Long 	struct sctp_assoc_value params;
7844df2c71ffSXin Long 	struct sctp_association *asoc;
7845df2c71ffSXin Long 	int retval = -EFAULT;
7846df2c71ffSXin Long 
7847df2c71ffSXin Long 	if (len < sizeof(params)) {
7848df2c71ffSXin Long 		retval = -EINVAL;
7849df2c71ffSXin Long 		goto out;
7850df2c71ffSXin Long 	}
7851df2c71ffSXin Long 
7852df2c71ffSXin Long 	len = sizeof(params);
7853df2c71ffSXin Long 	if (copy_from_user(&params, optval, len))
7854df2c71ffSXin Long 		goto out;
7855df2c71ffSXin Long 
7856df2c71ffSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
7857df2c71ffSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
7858df2c71ffSXin Long 	    sctp_style(sk, UDP)) {
7859df2c71ffSXin Long 		retval = -EINVAL;
7860df2c71ffSXin Long 		goto out;
7861df2c71ffSXin Long 	}
7862df2c71ffSXin Long 
7863df2c71ffSXin Long 	params.assoc_value = asoc ? asoc->peer.asconf_capable
7864df2c71ffSXin Long 				  : sctp_sk(sk)->ep->asconf_enable;
7865df2c71ffSXin Long 
7866df2c71ffSXin Long 	if (put_user(len, optlen))
7867df2c71ffSXin Long 		goto out;
7868df2c71ffSXin Long 
7869df2c71ffSXin Long 	if (copy_to_user(optval, &params, len))
7870df2c71ffSXin Long 		goto out;
7871df2c71ffSXin Long 
7872df2c71ffSXin Long 	retval = 0;
7873df2c71ffSXin Long 
7874df2c71ffSXin Long out:
7875df2c71ffSXin Long 	return retval;
7876df2c71ffSXin Long }
7877df2c71ffSXin Long 
787856dd525aSXin Long static int sctp_getsockopt_auth_supported(struct sock *sk, int len,
787956dd525aSXin Long 					  char __user *optval,
788056dd525aSXin Long 					  int __user *optlen)
788156dd525aSXin Long {
788256dd525aSXin Long 	struct sctp_assoc_value params;
788356dd525aSXin Long 	struct sctp_association *asoc;
788456dd525aSXin Long 	int retval = -EFAULT;
788556dd525aSXin Long 
788656dd525aSXin Long 	if (len < sizeof(params)) {
788756dd525aSXin Long 		retval = -EINVAL;
788856dd525aSXin Long 		goto out;
788956dd525aSXin Long 	}
789056dd525aSXin Long 
789156dd525aSXin Long 	len = sizeof(params);
789256dd525aSXin Long 	if (copy_from_user(&params, optval, len))
789356dd525aSXin Long 		goto out;
789456dd525aSXin Long 
789556dd525aSXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
789656dd525aSXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
789756dd525aSXin Long 	    sctp_style(sk, UDP)) {
789856dd525aSXin Long 		retval = -EINVAL;
789956dd525aSXin Long 		goto out;
790056dd525aSXin Long 	}
790156dd525aSXin Long 
790256dd525aSXin Long 	params.assoc_value = asoc ? asoc->peer.auth_capable
790356dd525aSXin Long 				  : sctp_sk(sk)->ep->auth_enable;
790456dd525aSXin Long 
790556dd525aSXin Long 	if (put_user(len, optlen))
790656dd525aSXin Long 		goto out;
790756dd525aSXin Long 
790856dd525aSXin Long 	if (copy_to_user(optval, &params, len))
790956dd525aSXin Long 		goto out;
791056dd525aSXin Long 
791156dd525aSXin Long 	retval = 0;
791256dd525aSXin Long 
791356dd525aSXin Long out:
791456dd525aSXin Long 	return retval;
791556dd525aSXin Long }
791656dd525aSXin Long 
7917d5886b91SXin Long static int sctp_getsockopt_ecn_supported(struct sock *sk, int len,
7918d5886b91SXin Long 					 char __user *optval,
7919d5886b91SXin Long 					 int __user *optlen)
7920d5886b91SXin Long {
7921d5886b91SXin Long 	struct sctp_assoc_value params;
7922d5886b91SXin Long 	struct sctp_association *asoc;
7923d5886b91SXin Long 	int retval = -EFAULT;
7924d5886b91SXin Long 
7925d5886b91SXin Long 	if (len < sizeof(params)) {
7926d5886b91SXin Long 		retval = -EINVAL;
7927d5886b91SXin Long 		goto out;
7928d5886b91SXin Long 	}
7929d5886b91SXin Long 
7930d5886b91SXin Long 	len = sizeof(params);
7931d5886b91SXin Long 	if (copy_from_user(&params, optval, len))
7932d5886b91SXin Long 		goto out;
7933d5886b91SXin Long 
7934d5886b91SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
7935d5886b91SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
7936d5886b91SXin Long 	    sctp_style(sk, UDP)) {
7937d5886b91SXin Long 		retval = -EINVAL;
7938d5886b91SXin Long 		goto out;
7939d5886b91SXin Long 	}
7940d5886b91SXin Long 
7941d5886b91SXin Long 	params.assoc_value = asoc ? asoc->peer.ecn_capable
7942d5886b91SXin Long 				  : sctp_sk(sk)->ep->ecn_enable;
7943d5886b91SXin Long 
7944d5886b91SXin Long 	if (put_user(len, optlen))
7945d5886b91SXin Long 		goto out;
7946d5886b91SXin Long 
7947d5886b91SXin Long 	if (copy_to_user(optval, &params, len))
7948d5886b91SXin Long 		goto out;
7949d5886b91SXin Long 
7950d5886b91SXin Long 	retval = 0;
7951d5886b91SXin Long 
7952d5886b91SXin Long out:
7953d5886b91SXin Long 	return retval;
7954d5886b91SXin Long }
7955d5886b91SXin Long 
79568d2a6935SXin Long static int sctp_getsockopt_pf_expose(struct sock *sk, int len,
79578d2a6935SXin Long 				     char __user *optval,
79588d2a6935SXin Long 				     int __user *optlen)
79598d2a6935SXin Long {
79608d2a6935SXin Long 	struct sctp_assoc_value params;
79618d2a6935SXin Long 	struct sctp_association *asoc;
79628d2a6935SXin Long 	int retval = -EFAULT;
79638d2a6935SXin Long 
79648d2a6935SXin Long 	if (len < sizeof(params)) {
79658d2a6935SXin Long 		retval = -EINVAL;
79668d2a6935SXin Long 		goto out;
79678d2a6935SXin Long 	}
79688d2a6935SXin Long 
79698d2a6935SXin Long 	len = sizeof(params);
79708d2a6935SXin Long 	if (copy_from_user(&params, optval, len))
79718d2a6935SXin Long 		goto out;
79728d2a6935SXin Long 
79738d2a6935SXin Long 	asoc = sctp_id2assoc(sk, params.assoc_id);
79748d2a6935SXin Long 	if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
79758d2a6935SXin Long 	    sctp_style(sk, UDP)) {
79768d2a6935SXin Long 		retval = -EINVAL;
79778d2a6935SXin Long 		goto out;
79788d2a6935SXin Long 	}
79798d2a6935SXin Long 
79808d2a6935SXin Long 	params.assoc_value = asoc ? asoc->pf_expose
79818d2a6935SXin Long 				  : sctp_sk(sk)->pf_expose;
79828d2a6935SXin Long 
79838d2a6935SXin Long 	if (put_user(len, optlen))
79848d2a6935SXin Long 		goto out;
79858d2a6935SXin Long 
79868d2a6935SXin Long 	if (copy_to_user(optval, &params, len))
79878d2a6935SXin Long 		goto out;
79888d2a6935SXin Long 
79898d2a6935SXin Long 	retval = 0;
79908d2a6935SXin Long 
79918d2a6935SXin Long out:
79928d2a6935SXin Long 	return retval;
79938d2a6935SXin Long }
79948d2a6935SXin Long 
7995dda91928SDaniel Borkmann static int sctp_getsockopt(struct sock *sk, int level, int optname,
79961da177e4SLinus Torvalds 			   char __user *optval, int __user *optlen)
79971da177e4SLinus Torvalds {
79981da177e4SLinus Torvalds 	int retval = 0;
79991da177e4SLinus Torvalds 	int len;
80001da177e4SLinus Torvalds 
8001bb33381dSDaniel Borkmann 	pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname);
80021da177e4SLinus Torvalds 
80031da177e4SLinus Torvalds 	/* I can hardly begin to describe how wrong this is.  This is
80041da177e4SLinus Torvalds 	 * so broken as to be worse than useless.  The API draft
80051da177e4SLinus Torvalds 	 * REALLY is NOT helpful here...  I am not convinced that the
80061da177e4SLinus Torvalds 	 * semantics of getsockopt() with a level OTHER THAN SOL_SCTP
80071da177e4SLinus Torvalds 	 * are at all well-founded.
80081da177e4SLinus Torvalds 	 */
80091da177e4SLinus Torvalds 	if (level != SOL_SCTP) {
80101da177e4SLinus Torvalds 		struct sctp_af *af = sctp_sk(sk)->pf->af;
80111da177e4SLinus Torvalds 
80121da177e4SLinus Torvalds 		retval = af->getsockopt(sk, level, optname, optval, optlen);
80131da177e4SLinus Torvalds 		return retval;
80141da177e4SLinus Torvalds 	}
80151da177e4SLinus Torvalds 
80161da177e4SLinus Torvalds 	if (get_user(len, optlen))
80171da177e4SLinus Torvalds 		return -EFAULT;
80181da177e4SLinus Torvalds 
8019a4b8e71bSJiri Slaby 	if (len < 0)
8020a4b8e71bSJiri Slaby 		return -EINVAL;
8021a4b8e71bSJiri Slaby 
8022048ed4b6Swangweidong 	lock_sock(sk);
80231da177e4SLinus Torvalds 
80241da177e4SLinus Torvalds 	switch (optname) {
80251da177e4SLinus Torvalds 	case SCTP_STATUS:
80261da177e4SLinus Torvalds 		retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen);
80271da177e4SLinus Torvalds 		break;
80281da177e4SLinus Torvalds 	case SCTP_DISABLE_FRAGMENTS:
80291da177e4SLinus Torvalds 		retval = sctp_getsockopt_disable_fragments(sk, len, optval,
80301da177e4SLinus Torvalds 							   optlen);
80311da177e4SLinus Torvalds 		break;
80321da177e4SLinus Torvalds 	case SCTP_EVENTS:
80331da177e4SLinus Torvalds 		retval = sctp_getsockopt_events(sk, len, optval, optlen);
80341da177e4SLinus Torvalds 		break;
80351da177e4SLinus Torvalds 	case SCTP_AUTOCLOSE:
80361da177e4SLinus Torvalds 		retval = sctp_getsockopt_autoclose(sk, len, optval, optlen);
80371da177e4SLinus Torvalds 		break;
80381da177e4SLinus Torvalds 	case SCTP_SOCKOPT_PEELOFF:
80391da177e4SLinus Torvalds 		retval = sctp_getsockopt_peeloff(sk, len, optval, optlen);
80401da177e4SLinus Torvalds 		break;
80412cb5c8e3SNeil Horman 	case SCTP_SOCKOPT_PEELOFF_FLAGS:
80422cb5c8e3SNeil Horman 		retval = sctp_getsockopt_peeloff_flags(sk, len, optval, optlen);
80432cb5c8e3SNeil Horman 		break;
80441da177e4SLinus Torvalds 	case SCTP_PEER_ADDR_PARAMS:
80451da177e4SLinus Torvalds 		retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
80461da177e4SLinus Torvalds 							  optlen);
80471da177e4SLinus Torvalds 		break;
80484580ccc0SShan Wei 	case SCTP_DELAYED_SACK:
8049d364d927SWei Yongjun 		retval = sctp_getsockopt_delayed_ack(sk, len, optval,
80507708610bSFrank Filz 							  optlen);
80517708610bSFrank Filz 		break;
80521da177e4SLinus Torvalds 	case SCTP_INITMSG:
80531da177e4SLinus Torvalds 		retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
80541da177e4SLinus Torvalds 		break;
80551da177e4SLinus Torvalds 	case SCTP_GET_PEER_ADDRS:
80561da177e4SLinus Torvalds 		retval = sctp_getsockopt_peer_addrs(sk, len, optval,
80571da177e4SLinus Torvalds 						    optlen);
80581da177e4SLinus Torvalds 		break;
80591da177e4SLinus Torvalds 	case SCTP_GET_LOCAL_ADDRS:
80601da177e4SLinus Torvalds 		retval = sctp_getsockopt_local_addrs(sk, len, optval,
80611da177e4SLinus Torvalds 						     optlen);
80621da177e4SLinus Torvalds 		break;
8063c6ba68a2SVlad Yasevich 	case SCTP_SOCKOPT_CONNECTX3:
8064c6ba68a2SVlad Yasevich 		retval = sctp_getsockopt_connectx3(sk, len, optval, optlen);
8065c6ba68a2SVlad Yasevich 		break;
80661da177e4SLinus Torvalds 	case SCTP_DEFAULT_SEND_PARAM:
80671da177e4SLinus Torvalds 		retval = sctp_getsockopt_default_send_param(sk, len,
80681da177e4SLinus Torvalds 							    optval, optlen);
80691da177e4SLinus Torvalds 		break;
80706b3fd5f3SGeir Ola Vaagland 	case SCTP_DEFAULT_SNDINFO:
80716b3fd5f3SGeir Ola Vaagland 		retval = sctp_getsockopt_default_sndinfo(sk, len,
80726b3fd5f3SGeir Ola Vaagland 							 optval, optlen);
80736b3fd5f3SGeir Ola Vaagland 		break;
80741da177e4SLinus Torvalds 	case SCTP_PRIMARY_ADDR:
80751da177e4SLinus Torvalds 		retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen);
80761da177e4SLinus Torvalds 		break;
80771da177e4SLinus Torvalds 	case SCTP_NODELAY:
80781da177e4SLinus Torvalds 		retval = sctp_getsockopt_nodelay(sk, len, optval, optlen);
80791da177e4SLinus Torvalds 		break;
80801da177e4SLinus Torvalds 	case SCTP_RTOINFO:
80811da177e4SLinus Torvalds 		retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen);
80821da177e4SLinus Torvalds 		break;
80831da177e4SLinus Torvalds 	case SCTP_ASSOCINFO:
80841da177e4SLinus Torvalds 		retval = sctp_getsockopt_associnfo(sk, len, optval, optlen);
80851da177e4SLinus Torvalds 		break;
80861da177e4SLinus Torvalds 	case SCTP_I_WANT_MAPPED_V4_ADDR:
80871da177e4SLinus Torvalds 		retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen);
80881da177e4SLinus Torvalds 		break;
80891da177e4SLinus Torvalds 	case SCTP_MAXSEG:
80901da177e4SLinus Torvalds 		retval = sctp_getsockopt_maxseg(sk, len, optval, optlen);
80911da177e4SLinus Torvalds 		break;
80921da177e4SLinus Torvalds 	case SCTP_GET_PEER_ADDR_INFO:
80931da177e4SLinus Torvalds 		retval = sctp_getsockopt_peer_addr_info(sk, len, optval,
80941da177e4SLinus Torvalds 							optlen);
80951da177e4SLinus Torvalds 		break;
80960f3fffd8SIvan Skytte Jorgensen 	case SCTP_ADAPTATION_LAYER:
80970f3fffd8SIvan Skytte Jorgensen 		retval = sctp_getsockopt_adaptation_layer(sk, len, optval,
80981da177e4SLinus Torvalds 							optlen);
80991da177e4SLinus Torvalds 		break;
81006ab792f5SIvan Skytte Jorgensen 	case SCTP_CONTEXT:
81016ab792f5SIvan Skytte Jorgensen 		retval = sctp_getsockopt_context(sk, len, optval, optlen);
81026ab792f5SIvan Skytte Jorgensen 		break;
8103b6e1331fSVlad Yasevich 	case SCTP_FRAGMENT_INTERLEAVE:
8104b6e1331fSVlad Yasevich 		retval = sctp_getsockopt_fragment_interleave(sk, len, optval,
8105b6e1331fSVlad Yasevich 							     optlen);
8106b6e1331fSVlad Yasevich 		break;
8107d49d91d7SVlad Yasevich 	case SCTP_PARTIAL_DELIVERY_POINT:
8108d49d91d7SVlad Yasevich 		retval = sctp_getsockopt_partial_delivery_point(sk, len, optval,
8109d49d91d7SVlad Yasevich 								optlen);
8110d49d91d7SVlad Yasevich 		break;
811170331571SVlad Yasevich 	case SCTP_MAX_BURST:
811270331571SVlad Yasevich 		retval = sctp_getsockopt_maxburst(sk, len, optval, optlen);
811370331571SVlad Yasevich 		break;
811465b07e5dSVlad Yasevich 	case SCTP_AUTH_KEY:
811565b07e5dSVlad Yasevich 	case SCTP_AUTH_CHUNK:
811665b07e5dSVlad Yasevich 	case SCTP_AUTH_DELETE_KEY:
8117601590ecSXin Long 	case SCTP_AUTH_DEACTIVATE_KEY:
811865b07e5dSVlad Yasevich 		retval = -EOPNOTSUPP;
811965b07e5dSVlad Yasevich 		break;
812065b07e5dSVlad Yasevich 	case SCTP_HMAC_IDENT:
812165b07e5dSVlad Yasevich 		retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen);
812265b07e5dSVlad Yasevich 		break;
812365b07e5dSVlad Yasevich 	case SCTP_AUTH_ACTIVE_KEY:
812465b07e5dSVlad Yasevich 		retval = sctp_getsockopt_active_key(sk, len, optval, optlen);
812565b07e5dSVlad Yasevich 		break;
812665b07e5dSVlad Yasevich 	case SCTP_PEER_AUTH_CHUNKS:
812765b07e5dSVlad Yasevich 		retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval,
812865b07e5dSVlad Yasevich 							optlen);
812965b07e5dSVlad Yasevich 		break;
813065b07e5dSVlad Yasevich 	case SCTP_LOCAL_AUTH_CHUNKS:
813165b07e5dSVlad Yasevich 		retval = sctp_getsockopt_local_auth_chunks(sk, len, optval,
813265b07e5dSVlad Yasevich 							optlen);
813365b07e5dSVlad Yasevich 		break;
8134aea3c5c0SWei Yongjun 	case SCTP_GET_ASSOC_NUMBER:
8135aea3c5c0SWei Yongjun 		retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
8136aea3c5c0SWei Yongjun 		break;
8137209ba424SWei Yongjun 	case SCTP_GET_ASSOC_ID_LIST:
8138209ba424SWei Yongjun 		retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen);
8139209ba424SWei Yongjun 		break;
81407dc04d71SMichio Honda 	case SCTP_AUTO_ASCONF:
81417dc04d71SMichio Honda 		retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);
81427dc04d71SMichio Honda 		break;
81435aa93bcfSNeil Horman 	case SCTP_PEER_ADDR_THLDS:
8144d467ac0aSXin Long 		retval = sctp_getsockopt_paddr_thresholds(sk, optval, len,
8145d467ac0aSXin Long 							  optlen, false);
8146d467ac0aSXin Long 		break;
8147d467ac0aSXin Long 	case SCTP_PEER_ADDR_THLDS_V2:
8148d467ac0aSXin Long 		retval = sctp_getsockopt_paddr_thresholds(sk, optval, len,
8149d467ac0aSXin Long 							  optlen, true);
81505aa93bcfSNeil Horman 		break;
8151196d6759SMichele Baldessari 	case SCTP_GET_ASSOC_STATS:
8152196d6759SMichele Baldessari 		retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen);
8153196d6759SMichele Baldessari 		break;
81540d3a421dSGeir Ola Vaagland 	case SCTP_RECVRCVINFO:
81550d3a421dSGeir Ola Vaagland 		retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen);
81560d3a421dSGeir Ola Vaagland 		break;
81572347c80fSGeir Ola Vaagland 	case SCTP_RECVNXTINFO:
81582347c80fSGeir Ola Vaagland 		retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen);
81592347c80fSGeir Ola Vaagland 		break;
816028aa4c26SXin Long 	case SCTP_PR_SUPPORTED:
816128aa4c26SXin Long 		retval = sctp_getsockopt_pr_supported(sk, len, optval, optlen);
816228aa4c26SXin Long 		break;
8163f959fb44SXin Long 	case SCTP_DEFAULT_PRINFO:
8164f959fb44SXin Long 		retval = sctp_getsockopt_default_prinfo(sk, len, optval,
8165f959fb44SXin Long 							optlen);
8166f959fb44SXin Long 		break;
8167826d253dSXin Long 	case SCTP_PR_ASSOC_STATUS:
8168826d253dSXin Long 		retval = sctp_getsockopt_pr_assocstatus(sk, len, optval,
8169826d253dSXin Long 							optlen);
8170826d253dSXin Long 		break;
8171d229d48dSXin Long 	case SCTP_PR_STREAM_STATUS:
8172d229d48dSXin Long 		retval = sctp_getsockopt_pr_streamstatus(sk, len, optval,
8173d229d48dSXin Long 							 optlen);
8174d229d48dSXin Long 		break;
8175c0d8bab6SXin Long 	case SCTP_RECONFIG_SUPPORTED:
8176c0d8bab6SXin Long 		retval = sctp_getsockopt_reconfig_supported(sk, len, optval,
8177c0d8bab6SXin Long 							    optlen);
8178c0d8bab6SXin Long 		break;
81799fb657aeSXin Long 	case SCTP_ENABLE_STREAM_RESET:
81809fb657aeSXin Long 		retval = sctp_getsockopt_enable_strreset(sk, len, optval,
81819fb657aeSXin Long 							 optlen);
81829fb657aeSXin Long 		break;
818313aa8770SMarcelo Ricardo Leitner 	case SCTP_STREAM_SCHEDULER:
818413aa8770SMarcelo Ricardo Leitner 		retval = sctp_getsockopt_scheduler(sk, len, optval,
818513aa8770SMarcelo Ricardo Leitner 						   optlen);
818613aa8770SMarcelo Ricardo Leitner 		break;
81870ccdf3c7SMarcelo Ricardo Leitner 	case SCTP_STREAM_SCHEDULER_VALUE:
81880ccdf3c7SMarcelo Ricardo Leitner 		retval = sctp_getsockopt_scheduler_value(sk, len, optval,
81890ccdf3c7SMarcelo Ricardo Leitner 							 optlen);
81900ccdf3c7SMarcelo Ricardo Leitner 		break;
8191772a5869SXin Long 	case SCTP_INTERLEAVING_SUPPORTED:
8192772a5869SXin Long 		retval = sctp_getsockopt_interleaving_supported(sk, len, optval,
8193772a5869SXin Long 								optlen);
8194772a5869SXin Long 		break;
8195b0e9a2feSXin Long 	case SCTP_REUSE_PORT:
8196b0e9a2feSXin Long 		retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen);
8197b0e9a2feSXin Long 		break;
8198480ba9c1SXin Long 	case SCTP_EVENT:
8199480ba9c1SXin Long 		retval = sctp_getsockopt_event(sk, len, optval, optlen);
8200480ba9c1SXin Long 		break;
8201df2c71ffSXin Long 	case SCTP_ASCONF_SUPPORTED:
8202df2c71ffSXin Long 		retval = sctp_getsockopt_asconf_supported(sk, len, optval,
8203df2c71ffSXin Long 							  optlen);
8204df2c71ffSXin Long 		break;
820556dd525aSXin Long 	case SCTP_AUTH_SUPPORTED:
820656dd525aSXin Long 		retval = sctp_getsockopt_auth_supported(sk, len, optval,
820756dd525aSXin Long 							optlen);
820856dd525aSXin Long 		break;
8209d5886b91SXin Long 	case SCTP_ECN_SUPPORTED:
8210d5886b91SXin Long 		retval = sctp_getsockopt_ecn_supported(sk, len, optval, optlen);
8211d5886b91SXin Long 		break;
82128d2a6935SXin Long 	case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
82138d2a6935SXin Long 		retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen);
82148d2a6935SXin Long 		break;
82151da177e4SLinus Torvalds 	default:
82161da177e4SLinus Torvalds 		retval = -ENOPROTOOPT;
82171da177e4SLinus Torvalds 		break;
82183ff50b79SStephen Hemminger 	}
82191da177e4SLinus Torvalds 
8220048ed4b6Swangweidong 	release_sock(sk);
82211da177e4SLinus Torvalds 	return retval;
82221da177e4SLinus Torvalds }
82231da177e4SLinus Torvalds 
8224086c653fSCraig Gallek static int sctp_hash(struct sock *sk)
82251da177e4SLinus Torvalds {
82261da177e4SLinus Torvalds 	/* STUB */
8227086c653fSCraig Gallek 	return 0;
82281da177e4SLinus Torvalds }
82291da177e4SLinus Torvalds 
82301da177e4SLinus Torvalds static void sctp_unhash(struct sock *sk)
82311da177e4SLinus Torvalds {
82321da177e4SLinus Torvalds 	/* STUB */
82331da177e4SLinus Torvalds }
82341da177e4SLinus Torvalds 
82351da177e4SLinus Torvalds /* Check if port is acceptable.  Possibly find first available port.
82361da177e4SLinus Torvalds  *
82371da177e4SLinus Torvalds  * The port hash table (contained in the 'global' SCTP protocol storage
82381da177e4SLinus Torvalds  * returned by struct sctp_protocol *sctp_get_protocol()). The hash
82391da177e4SLinus Torvalds  * table is an array of 4096 lists (sctp_bind_hashbucket). Each
82401da177e4SLinus Torvalds  * list (the list number is the port number hashed out, so as you
82411da177e4SLinus Torvalds  * would expect from a hash function, all the ports in a given list have
82421da177e4SLinus Torvalds  * such a number that hashes out to the same list number; you were
82431da177e4SLinus Torvalds  * expecting that, right?); so each list has a set of ports, with a
82441da177e4SLinus Torvalds  * link to the socket (struct sock) that uses it, the port number and
82451da177e4SLinus Torvalds  * a fastreuse flag (FIXME: NPI ipg).
82461da177e4SLinus Torvalds  */
82471da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create(
8248f1f43763SEric W. Biederman 	struct sctp_bind_hashbucket *head, struct net *, unsigned short snum);
82491da177e4SLinus Torvalds 
82508e2ef6abSMao Wenan static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
82511da177e4SLinus Torvalds {
82526ba84574SXin Long 	struct sctp_sock *sp = sctp_sk(sk);
82536ba84574SXin Long 	bool reuse = (sk->sk_reuse || sp->reuse);
82541da177e4SLinus Torvalds 	struct sctp_bind_hashbucket *head; /* hash list */
8255fb822388SMaciej Żenczykowski 	struct net *net = sock_net(sk);
82566ba84574SXin Long 	kuid_t uid = sock_i_uid(sk);
8257b67bfe0dSSasha Levin 	struct sctp_bind_bucket *pp;
82581da177e4SLinus Torvalds 	unsigned short snum;
82591da177e4SLinus Torvalds 	int ret;
82601da177e4SLinus Torvalds 
826104afd8b2SAl Viro 	snum = ntohs(addr->v4.sin_port);
82621da177e4SLinus Torvalds 
8263bb33381dSDaniel Borkmann 	pr_debug("%s: begins, snum:%d\n", __func__, snum);
8264bb33381dSDaniel Borkmann 
826579b91130Swangweidong 	local_bh_disable();
82661da177e4SLinus Torvalds 
82671da177e4SLinus Torvalds 	if (snum == 0) {
826806393009SStephen Hemminger 		/* Search for an available port. */
8269227b60f5SStephen Hemminger 		int low, high, remaining, index;
8270227b60f5SStephen Hemminger 		unsigned int rover;
8271227b60f5SStephen Hemminger 
8272122ff243SWANG Cong 		inet_get_local_port_range(net, &low, &high);
8273227b60f5SStephen Hemminger 		remaining = (high - low) + 1;
827463862b5bSAruna-Hewapathirane 		rover = prandom_u32() % remaining + low;
82751da177e4SLinus Torvalds 
82761da177e4SLinus Torvalds 		do {
82771da177e4SLinus Torvalds 			rover++;
82781da177e4SLinus Torvalds 			if ((rover < low) || (rover > high))
82791da177e4SLinus Torvalds 				rover = low;
8280122ff243SWANG Cong 			if (inet_is_local_reserved_port(net, rover))
8281e3826f1eSAmerigo Wang 				continue;
8282fb822388SMaciej Żenczykowski 			index = sctp_phashfn(net, rover);
82831da177e4SLinus Torvalds 			head = &sctp_port_hashtable[index];
82843c8e43baSwangweidong 			spin_lock(&head->lock);
8285b67bfe0dSSasha Levin 			sctp_for_each_hentry(pp, &head->chain)
8286f1f43763SEric W. Biederman 				if ((pp->port == rover) &&
8287fb822388SMaciej Żenczykowski 				    net_eq(net, pp->net))
82881da177e4SLinus Torvalds 					goto next;
82891da177e4SLinus Torvalds 			break;
82901da177e4SLinus Torvalds 		next:
82913c8e43baSwangweidong 			spin_unlock(&head->lock);
82921da177e4SLinus Torvalds 		} while (--remaining > 0);
82931da177e4SLinus Torvalds 
82941da177e4SLinus Torvalds 		/* Exhausted local port range during search? */
82951da177e4SLinus Torvalds 		ret = 1;
82961da177e4SLinus Torvalds 		if (remaining <= 0)
82971da177e4SLinus Torvalds 			goto fail;
82981da177e4SLinus Torvalds 
82991da177e4SLinus Torvalds 		/* OK, here is the one we will use.  HEAD (the port
83001da177e4SLinus Torvalds 		 * hash table list entry) is non-NULL and we hold it's
83011da177e4SLinus Torvalds 		 * mutex.
83021da177e4SLinus Torvalds 		 */
83031da177e4SLinus Torvalds 		snum = rover;
83041da177e4SLinus Torvalds 	} else {
83051da177e4SLinus Torvalds 		/* We are given an specific port number; we verify
83061da177e4SLinus Torvalds 		 * that it is not being used. If it is used, we will
83071da177e4SLinus Torvalds 		 * exahust the search in the hash list corresponding
83081da177e4SLinus Torvalds 		 * to the port number (snum) - we detect that with the
83091da177e4SLinus Torvalds 		 * port iterator, pp being NULL.
83101da177e4SLinus Torvalds 		 */
8311fb822388SMaciej Żenczykowski 		head = &sctp_port_hashtable[sctp_phashfn(net, snum)];
83123c8e43baSwangweidong 		spin_lock(&head->lock);
8313b67bfe0dSSasha Levin 		sctp_for_each_hentry(pp, &head->chain) {
8314fb822388SMaciej Żenczykowski 			if ((pp->port == snum) && net_eq(pp->net, net))
83151da177e4SLinus Torvalds 				goto pp_found;
83161da177e4SLinus Torvalds 		}
83171da177e4SLinus Torvalds 	}
83181da177e4SLinus Torvalds 	pp = NULL;
83191da177e4SLinus Torvalds 	goto pp_not_found;
83201da177e4SLinus Torvalds pp_found:
83211da177e4SLinus Torvalds 	if (!hlist_empty(&pp->owner)) {
83221da177e4SLinus Torvalds 		/* We had a port hash table hit - there is an
83231da177e4SLinus Torvalds 		 * available port (pp != NULL) and it is being
83241da177e4SLinus Torvalds 		 * used by other socket (pp->owner not empty); that other
83251da177e4SLinus Torvalds 		 * socket is going to be sk2.
83261da177e4SLinus Torvalds 		 */
83271da177e4SLinus Torvalds 		struct sock *sk2;
83281da177e4SLinus Torvalds 
8329bb33381dSDaniel Borkmann 		pr_debug("%s: found a possible match\n", __func__);
8330bb33381dSDaniel Borkmann 
83316ba84574SXin Long 		if ((pp->fastreuse && reuse &&
83326ba84574SXin Long 		     sk->sk_state != SCTP_SS_LISTENING) ||
83336ba84574SXin Long 		    (pp->fastreuseport && sk->sk_reuseport &&
83346ba84574SXin Long 		     uid_eq(pp->fastuid, uid)))
83351da177e4SLinus Torvalds 			goto success;
83361da177e4SLinus Torvalds 
83371da177e4SLinus Torvalds 		/* Run through the list of sockets bound to the port
83381da177e4SLinus Torvalds 		 * (pp->port) [via the pointers bind_next and
83391da177e4SLinus Torvalds 		 * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one,
83401da177e4SLinus Torvalds 		 * we get the endpoint they describe and run through
83411da177e4SLinus Torvalds 		 * the endpoint's list of IP (v4 or v6) addresses,
83421da177e4SLinus Torvalds 		 * comparing each of the addresses with the address of
83431da177e4SLinus Torvalds 		 * the socket sk. If we find a match, then that means
83441da177e4SLinus Torvalds 		 * that this port/socket (sk) combination are already
83451da177e4SLinus Torvalds 		 * in an endpoint.
83461da177e4SLinus Torvalds 		 */
8347b67bfe0dSSasha Levin 		sk_for_each_bound(sk2, &pp->owner) {
83486ba84574SXin Long 			struct sctp_sock *sp2 = sctp_sk(sk2);
83496ba84574SXin Long 			struct sctp_endpoint *ep2 = sp2->ep;
83501da177e4SLinus Torvalds 
83514e54064eSVlad Yasevich 			if (sk == sk2 ||
83526ba84574SXin Long 			    (reuse && (sk2->sk_reuse || sp2->reuse) &&
83536ba84574SXin Long 			     sk2->sk_state != SCTP_SS_LISTENING) ||
83546ba84574SXin Long 			    (sk->sk_reuseport && sk2->sk_reuseport &&
83556ba84574SXin Long 			     uid_eq(uid, sock_i_uid(sk2))))
83561da177e4SLinus Torvalds 				continue;
83571da177e4SLinus Torvalds 
83586ba84574SXin Long 			if (sctp_bind_addr_conflict(&ep2->base.bind_addr,
83596ba84574SXin Long 						    addr, sp2, sp)) {
83608e2ef6abSMao Wenan 				ret = 1;
83611da177e4SLinus Torvalds 				goto fail_unlock;
83621da177e4SLinus Torvalds 			}
83631da177e4SLinus Torvalds 		}
8364bb33381dSDaniel Borkmann 
8365bb33381dSDaniel Borkmann 		pr_debug("%s: found a match\n", __func__);
83661da177e4SLinus Torvalds 	}
83671da177e4SLinus Torvalds pp_not_found:
83681da177e4SLinus Torvalds 	/* If there was a hash table miss, create a new port.  */
83691da177e4SLinus Torvalds 	ret = 1;
8370fb822388SMaciej Żenczykowski 	if (!pp && !(pp = sctp_bucket_create(head, net, snum)))
83711da177e4SLinus Torvalds 		goto fail_unlock;
83721da177e4SLinus Torvalds 
83731da177e4SLinus Torvalds 	/* In either case (hit or miss), make sure fastreuse is 1 only
83741da177e4SLinus Torvalds 	 * if sk->sk_reuse is too (that is, if the caller requested
83751da177e4SLinus Torvalds 	 * SO_REUSEADDR on this socket -sk-).
83761da177e4SLinus Torvalds 	 */
8377ce5325c1SVlad Yasevich 	if (hlist_empty(&pp->owner)) {
8378b0e9a2feSXin Long 		if (reuse && sk->sk_state != SCTP_SS_LISTENING)
8379ce5325c1SVlad Yasevich 			pp->fastreuse = 1;
8380ce5325c1SVlad Yasevich 		else
8381ce5325c1SVlad Yasevich 			pp->fastreuse = 0;
83826ba84574SXin Long 
83836ba84574SXin Long 		if (sk->sk_reuseport) {
83846ba84574SXin Long 			pp->fastreuseport = 1;
83856ba84574SXin Long 			pp->fastuid = uid;
83866ba84574SXin Long 		} else {
83876ba84574SXin Long 			pp->fastreuseport = 0;
83886ba84574SXin Long 		}
83896ba84574SXin Long 	} else {
83906ba84574SXin Long 		if (pp->fastreuse &&
8391b0e9a2feSXin Long 		    (!reuse || sk->sk_state == SCTP_SS_LISTENING))
83921da177e4SLinus Torvalds 			pp->fastreuse = 0;
83931da177e4SLinus Torvalds 
83946ba84574SXin Long 		if (pp->fastreuseport &&
83956ba84574SXin Long 		    (!sk->sk_reuseport || !uid_eq(pp->fastuid, uid)))
83966ba84574SXin Long 			pp->fastreuseport = 0;
83976ba84574SXin Long 	}
83986ba84574SXin Long 
83991da177e4SLinus Torvalds 	/* We are set, so fill up all the data in the hash table
84001da177e4SLinus Torvalds 	 * entry, tie the socket list information with the rest of the
84011da177e4SLinus Torvalds 	 * sockets FIXME: Blurry, NPI (ipg).
84021da177e4SLinus Torvalds 	 */
84031da177e4SLinus Torvalds success:
84046ba84574SXin Long 	if (!sp->bind_hash) {
8405c720c7e8SEric Dumazet 		inet_sk(sk)->inet_num = snum;
84061da177e4SLinus Torvalds 		sk_add_bind_node(sk, &pp->owner);
84076ba84574SXin Long 		sp->bind_hash = pp;
84081da177e4SLinus Torvalds 	}
84091da177e4SLinus Torvalds 	ret = 0;
84101da177e4SLinus Torvalds 
84111da177e4SLinus Torvalds fail_unlock:
84123c8e43baSwangweidong 	spin_unlock(&head->lock);
84131da177e4SLinus Torvalds 
84141da177e4SLinus Torvalds fail:
841579b91130Swangweidong 	local_bh_enable();
84161da177e4SLinus Torvalds 	return ret;
84171da177e4SLinus Torvalds }
84181da177e4SLinus Torvalds 
84191da177e4SLinus Torvalds /* Assign a 'snum' port to the socket.  If snum == 0, an ephemeral
84201da177e4SLinus Torvalds  * port is requested.
84211da177e4SLinus Torvalds  */
84221da177e4SLinus Torvalds static int sctp_get_port(struct sock *sk, unsigned short snum)
84231da177e4SLinus Torvalds {
84241da177e4SLinus Torvalds 	union sctp_addr addr;
84251da177e4SLinus Torvalds 	struct sctp_af *af = sctp_sk(sk)->pf->af;
84261da177e4SLinus Torvalds 
84271da177e4SLinus Torvalds 	/* Set up a dummy address struct from the sk. */
84281da177e4SLinus Torvalds 	af->from_sk(&addr, sk);
84291da177e4SLinus Torvalds 	addr.v4.sin_port = htons(snum);
84301da177e4SLinus Torvalds 
84311da177e4SLinus Torvalds 	/* Note: sk->sk_num gets filled in if ephemeral port request. */
84328e2ef6abSMao Wenan 	return sctp_get_port_local(sk, &addr);
84331da177e4SLinus Torvalds }
84341da177e4SLinus Torvalds 
84351da177e4SLinus Torvalds /*
84361da177e4SLinus Torvalds  *  Move a socket to LISTENING state.
84371da177e4SLinus Torvalds  */
8438dda91928SDaniel Borkmann static int sctp_listen_start(struct sock *sk, int backlog)
84391da177e4SLinus Torvalds {
84405e8f3f70SVlad Yasevich 	struct sctp_sock *sp = sctp_sk(sk);
84415e8f3f70SVlad Yasevich 	struct sctp_endpoint *ep = sp->ep;
84425821c769SHerbert Xu 	struct crypto_shash *tfm = NULL;
84433c68198eSNeil Horman 	char alg[32];
84441da177e4SLinus Torvalds 
84451da177e4SLinus Torvalds 	/* Allocate HMAC for generating cookie. */
84463c68198eSNeil Horman 	if (!sp->hmac && sp->sctp_hmac_alg) {
84473c68198eSNeil Horman 		sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg);
84485821c769SHerbert Xu 		tfm = crypto_alloc_shash(alg, 0, 0);
84498dc4984aSVlad Yasevich 		if (IS_ERR(tfm)) {
8450e87cc472SJoe Perches 			net_info_ratelimited("failed to load transform for %s: %ld\n",
84513c68198eSNeil Horman 					     sp->sctp_hmac_alg, PTR_ERR(tfm));
84525e8f3f70SVlad Yasevich 			return -ENOSYS;
84535e8f3f70SVlad Yasevich 		}
84545e8f3f70SVlad Yasevich 		sctp_sk(sk)->hmac = tfm;
84555e8f3f70SVlad Yasevich 	}
84565e8f3f70SVlad Yasevich 
84575e8f3f70SVlad Yasevich 	/*
84585e8f3f70SVlad Yasevich 	 * If a bind() or sctp_bindx() is not called prior to a listen()
84595e8f3f70SVlad Yasevich 	 * call that allows new associations to be accepted, the system
84605e8f3f70SVlad Yasevich 	 * picks an ephemeral port and will choose an address set equivalent
84615e8f3f70SVlad Yasevich 	 * to binding with a wildcard address.
84625e8f3f70SVlad Yasevich 	 *
84635e8f3f70SVlad Yasevich 	 * This is not currently spelled out in the SCTP sockets
84645e8f3f70SVlad Yasevich 	 * extensions draft, but follows the practice as seen in TCP
84655e8f3f70SVlad Yasevich 	 * sockets.
84665e8f3f70SVlad Yasevich 	 *
84675e8f3f70SVlad Yasevich 	 */
8468cbabf463SYafang Shao 	inet_sk_set_state(sk, SCTP_SS_LISTENING);
84695e8f3f70SVlad Yasevich 	if (!ep->base.bind_addr.port) {
84705e8f3f70SVlad Yasevich 		if (sctp_autobind(sk))
84715e8f3f70SVlad Yasevich 			return -EAGAIN;
84725e8f3f70SVlad Yasevich 	} else {
8473c720c7e8SEric Dumazet 		if (sctp_get_port(sk, inet_sk(sk)->inet_num)) {
8474cbabf463SYafang Shao 			inet_sk_set_state(sk, SCTP_SS_CLOSED);
84755e8f3f70SVlad Yasevich 			return -EADDRINUSE;
84765e8f3f70SVlad Yasevich 		}
84775e8f3f70SVlad Yasevich 	}
84785e8f3f70SVlad Yasevich 
8479099ecf59SEric Dumazet 	WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
848076c6d988SXin Long 	return sctp_hash_endpoint(ep);
84815e8f3f70SVlad Yasevich }
84825e8f3f70SVlad Yasevich 
84835e8f3f70SVlad Yasevich /*
84845e8f3f70SVlad Yasevich  * 4.1.3 / 5.1.3 listen()
84855e8f3f70SVlad Yasevich  *
84865e8f3f70SVlad Yasevich  *   By default, new associations are not accepted for UDP style sockets.
84875e8f3f70SVlad Yasevich  *   An application uses listen() to mark a socket as being able to
84885e8f3f70SVlad Yasevich  *   accept new associations.
84895e8f3f70SVlad Yasevich  *
84905e8f3f70SVlad Yasevich  *   On TCP style sockets, applications use listen() to ready the SCTP
84915e8f3f70SVlad Yasevich  *   endpoint for accepting inbound associations.
84925e8f3f70SVlad Yasevich  *
84935e8f3f70SVlad Yasevich  *   On both types of endpoints a backlog of '0' disables listening.
84945e8f3f70SVlad Yasevich  *
84955e8f3f70SVlad Yasevich  *  Move a socket to LISTENING state.
84965e8f3f70SVlad Yasevich  */
84975e8f3f70SVlad Yasevich int sctp_inet_listen(struct socket *sock, int backlog)
84985e8f3f70SVlad Yasevich {
84995e8f3f70SVlad Yasevich 	struct sock *sk = sock->sk;
85005e8f3f70SVlad Yasevich 	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
85015e8f3f70SVlad Yasevich 	int err = -EINVAL;
85025e8f3f70SVlad Yasevich 
85035e8f3f70SVlad Yasevich 	if (unlikely(backlog < 0))
85045e8f3f70SVlad Yasevich 		return err;
85055e8f3f70SVlad Yasevich 
8506048ed4b6Swangweidong 	lock_sock(sk);
85075e8f3f70SVlad Yasevich 
85085e8f3f70SVlad Yasevich 	/* Peeled-off sockets are not allowed to listen().  */
85095e8f3f70SVlad Yasevich 	if (sctp_style(sk, UDP_HIGH_BANDWIDTH))
85105e8f3f70SVlad Yasevich 		goto out;
85115e8f3f70SVlad Yasevich 
85125e8f3f70SVlad Yasevich 	if (sock->state != SS_UNCONNECTED)
85135e8f3f70SVlad Yasevich 		goto out;
85145e8f3f70SVlad Yasevich 
851534b2789fSXin Long 	if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED))
851634b2789fSXin Long 		goto out;
851734b2789fSXin Long 
85185e8f3f70SVlad Yasevich 	/* If backlog is zero, disable listening. */
85195e8f3f70SVlad Yasevich 	if (!backlog) {
85205e8f3f70SVlad Yasevich 		if (sctp_sstate(sk, CLOSED))
85215e8f3f70SVlad Yasevich 			goto out;
85225e8f3f70SVlad Yasevich 
85235e8f3f70SVlad Yasevich 		err = 0;
85245e8f3f70SVlad Yasevich 		sctp_unhash_endpoint(ep);
85255e8f3f70SVlad Yasevich 		sk->sk_state = SCTP_SS_CLOSED;
8526b0e9a2feSXin Long 		if (sk->sk_reuse || sctp_sk(sk)->reuse)
85275e8f3f70SVlad Yasevich 			sctp_sk(sk)->bind_hash->fastreuse = 1;
85281da177e4SLinus Torvalds 		goto out;
85291da177e4SLinus Torvalds 	}
85301da177e4SLinus Torvalds 
85315e8f3f70SVlad Yasevich 	/* If we are already listening, just update the backlog */
85325e8f3f70SVlad Yasevich 	if (sctp_sstate(sk, LISTENING))
8533099ecf59SEric Dumazet 		WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
85345e8f3f70SVlad Yasevich 	else {
85355e8f3f70SVlad Yasevich 		err = sctp_listen_start(sk, backlog);
85361da177e4SLinus Torvalds 		if (err)
85375e8f3f70SVlad Yasevich 			goto out;
85385e8f3f70SVlad Yasevich 	}
85391da177e4SLinus Torvalds 
85405e8f3f70SVlad Yasevich 	err = 0;
85411da177e4SLinus Torvalds out:
8542048ed4b6Swangweidong 	release_sock(sk);
85431da177e4SLinus Torvalds 	return err;
85441da177e4SLinus Torvalds }
85451da177e4SLinus Torvalds 
85461da177e4SLinus Torvalds /*
85471da177e4SLinus Torvalds  * This function is done by modeling the current datagram_poll() and the
85481da177e4SLinus Torvalds  * tcp_poll().  Note that, based on these implementations, we don't
85491da177e4SLinus Torvalds  * lock the socket in this function, even though it seems that,
85501da177e4SLinus Torvalds  * ideally, locking or some other mechanisms can be used to ensure
85519bffc4acSNeil Horman  * the integrity of the counters (sndbuf and wmem_alloc) used
85521da177e4SLinus Torvalds  * in this place.  We assume that we don't need locks either until proven
85531da177e4SLinus Torvalds  * otherwise.
85541da177e4SLinus Torvalds  *
85551da177e4SLinus Torvalds  * Another thing to note is that we include the Async I/O support
85561da177e4SLinus Torvalds  * here, again, by modeling the current TCP/UDP code.  We don't have
85571da177e4SLinus Torvalds  * a good way to test with it yet.
85581da177e4SLinus Torvalds  */
8559a11e1d43SLinus Torvalds __poll_t sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
85601da177e4SLinus Torvalds {
85611da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
85621da177e4SLinus Torvalds 	struct sctp_sock *sp = sctp_sk(sk);
8563ade994f4SAl Viro 	__poll_t mask;
85641da177e4SLinus Torvalds 
8565a11e1d43SLinus Torvalds 	poll_wait(file, sk_sleep(sk), wait);
8566a11e1d43SLinus Torvalds 
8567486bdee0SMarcelo Ricardo Leitner 	sock_rps_record_flow(sk);
8568486bdee0SMarcelo Ricardo Leitner 
85691da177e4SLinus Torvalds 	/* A TCP-style listening socket becomes readable when the accept queue
85701da177e4SLinus Torvalds 	 * is not empty.
85711da177e4SLinus Torvalds 	 */
85721da177e4SLinus Torvalds 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
85731da177e4SLinus Torvalds 		return (!list_empty(&sp->ep->asocs)) ?
8574a9a08845SLinus Torvalds 			(EPOLLIN | EPOLLRDNORM) : 0;
85751da177e4SLinus Torvalds 
85761da177e4SLinus Torvalds 	mask = 0;
85771da177e4SLinus Torvalds 
85781da177e4SLinus Torvalds 	/* Is there any exceptional events?  */
85793ef7cf57SEric Dumazet 	if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
8580a9a08845SLinus Torvalds 		mask |= EPOLLERR |
8581a9a08845SLinus Torvalds 			(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0);
8582f348d70aSDavide Libenzi 	if (sk->sk_shutdown & RCV_SHUTDOWN)
8583a9a08845SLinus Torvalds 		mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM;
85841da177e4SLinus Torvalds 	if (sk->sk_shutdown == SHUTDOWN_MASK)
8585a9a08845SLinus Torvalds 		mask |= EPOLLHUP;
85861da177e4SLinus Torvalds 
85871da177e4SLinus Torvalds 	/* Is it readable?  Reconsider this code with TCP-style support.  */
85883ef7cf57SEric Dumazet 	if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
8589a9a08845SLinus Torvalds 		mask |= EPOLLIN | EPOLLRDNORM;
85901da177e4SLinus Torvalds 
85911da177e4SLinus Torvalds 	/* The association is either gone or not ready.  */
85921da177e4SLinus Torvalds 	if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED))
85931da177e4SLinus Torvalds 		return mask;
85941da177e4SLinus Torvalds 
85951da177e4SLinus Torvalds 	/* Is it writable?  */
85961da177e4SLinus Torvalds 	if (sctp_writeable(sk)) {
8597a9a08845SLinus Torvalds 		mask |= EPOLLOUT | EPOLLWRNORM;
85981da177e4SLinus Torvalds 	} else {
85999cd3e072SEric Dumazet 		sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
86001da177e4SLinus Torvalds 		/*
86011da177e4SLinus Torvalds 		 * Since the socket is not locked, the buffer
86021da177e4SLinus Torvalds 		 * might be made available after the writeable check and
86031da177e4SLinus Torvalds 		 * before the bit is set.  This could cause a lost I/O
86041da177e4SLinus Torvalds 		 * signal.  tcp_poll() has a race breaker for this race
86051da177e4SLinus Torvalds 		 * condition.  Based on their implementation, we put
86061da177e4SLinus Torvalds 		 * in the following code to cover it as well.
86071da177e4SLinus Torvalds 		 */
86081da177e4SLinus Torvalds 		if (sctp_writeable(sk))
8609a9a08845SLinus Torvalds 			mask |= EPOLLOUT | EPOLLWRNORM;
86101da177e4SLinus Torvalds 	}
86111da177e4SLinus Torvalds 	return mask;
86121da177e4SLinus Torvalds }
86131da177e4SLinus Torvalds 
86141da177e4SLinus Torvalds /********************************************************************
86151da177e4SLinus Torvalds  * 2nd Level Abstractions
86161da177e4SLinus Torvalds  ********************************************************************/
86171da177e4SLinus Torvalds 
86181da177e4SLinus Torvalds static struct sctp_bind_bucket *sctp_bucket_create(
8619f1f43763SEric W. Biederman 	struct sctp_bind_hashbucket *head, struct net *net, unsigned short snum)
86201da177e4SLinus Torvalds {
86211da177e4SLinus Torvalds 	struct sctp_bind_bucket *pp;
86221da177e4SLinus Torvalds 
862354e6ecb2SChristoph Lameter 	pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC);
86241da177e4SLinus Torvalds 	if (pp) {
8625935a7f6eSLi Zefan 		SCTP_DBG_OBJCNT_INC(bind_bucket);
86261da177e4SLinus Torvalds 		pp->port = snum;
86271da177e4SLinus Torvalds 		pp->fastreuse = 0;
86281da177e4SLinus Torvalds 		INIT_HLIST_HEAD(&pp->owner);
8629f1f43763SEric W. Biederman 		pp->net = net;
8630d970dbf8SVlad Yasevich 		hlist_add_head(&pp->node, &head->chain);
86311da177e4SLinus Torvalds 	}
86321da177e4SLinus Torvalds 	return pp;
86331da177e4SLinus Torvalds }
86341da177e4SLinus Torvalds 
86351da177e4SLinus Torvalds /* Caller must hold hashbucket lock for this tb with local BH disabled */
86361da177e4SLinus Torvalds static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
86371da177e4SLinus Torvalds {
863837fa6878SSridhar Samudrala 	if (pp && hlist_empty(&pp->owner)) {
8639d970dbf8SVlad Yasevich 		__hlist_del(&pp->node);
86401da177e4SLinus Torvalds 		kmem_cache_free(sctp_bucket_cachep, pp);
86411da177e4SLinus Torvalds 		SCTP_DBG_OBJCNT_DEC(bind_bucket);
86421da177e4SLinus Torvalds 	}
86431da177e4SLinus Torvalds }
86441da177e4SLinus Torvalds 
86451da177e4SLinus Torvalds /* Release this socket's reference to a local port.  */
86461da177e4SLinus Torvalds static inline void __sctp_put_port(struct sock *sk)
86471da177e4SLinus Torvalds {
86481da177e4SLinus Torvalds 	struct sctp_bind_hashbucket *head =
8649f1f43763SEric W. Biederman 		&sctp_port_hashtable[sctp_phashfn(sock_net(sk),
8650f1f43763SEric W. Biederman 						  inet_sk(sk)->inet_num)];
86511da177e4SLinus Torvalds 	struct sctp_bind_bucket *pp;
86521da177e4SLinus Torvalds 
86533c8e43baSwangweidong 	spin_lock(&head->lock);
86541da177e4SLinus Torvalds 	pp = sctp_sk(sk)->bind_hash;
86551da177e4SLinus Torvalds 	__sk_del_bind_node(sk);
86561da177e4SLinus Torvalds 	sctp_sk(sk)->bind_hash = NULL;
8657c720c7e8SEric Dumazet 	inet_sk(sk)->inet_num = 0;
86581da177e4SLinus Torvalds 	sctp_bucket_destroy(pp);
86593c8e43baSwangweidong 	spin_unlock(&head->lock);
86601da177e4SLinus Torvalds }
86611da177e4SLinus Torvalds 
86621da177e4SLinus Torvalds void sctp_put_port(struct sock *sk)
86631da177e4SLinus Torvalds {
866479b91130Swangweidong 	local_bh_disable();
86651da177e4SLinus Torvalds 	__sctp_put_port(sk);
866679b91130Swangweidong 	local_bh_enable();
86671da177e4SLinus Torvalds }
86681da177e4SLinus Torvalds 
86691da177e4SLinus Torvalds /*
86701da177e4SLinus Torvalds  * The system picks an ephemeral port and choose an address set equivalent
86711da177e4SLinus Torvalds  * to binding with a wildcard address.
86721da177e4SLinus Torvalds  * One of those addresses will be the primary address for the association.
86731da177e4SLinus Torvalds  * This automatically enables the multihoming capability of SCTP.
86741da177e4SLinus Torvalds  */
86751da177e4SLinus Torvalds static int sctp_autobind(struct sock *sk)
86761da177e4SLinus Torvalds {
86771da177e4SLinus Torvalds 	union sctp_addr autoaddr;
86781da177e4SLinus Torvalds 	struct sctp_af *af;
86796fbfa9f9SAl Viro 	__be16 port;
86801da177e4SLinus Torvalds 
86811da177e4SLinus Torvalds 	/* Initialize a local sockaddr structure to INADDR_ANY. */
86821da177e4SLinus Torvalds 	af = sctp_sk(sk)->pf->af;
86831da177e4SLinus Torvalds 
8684c720c7e8SEric Dumazet 	port = htons(inet_sk(sk)->inet_num);
86851da177e4SLinus Torvalds 	af->inaddr_any(&autoaddr, port);
86861da177e4SLinus Torvalds 
86871da177e4SLinus Torvalds 	return sctp_do_bind(sk, &autoaddr, af->sockaddr_len);
86881da177e4SLinus Torvalds }
86891da177e4SLinus Torvalds 
86901da177e4SLinus Torvalds /* Parse out IPPROTO_SCTP CMSG headers.  Perform only minimal validation.
86911da177e4SLinus Torvalds  *
86921da177e4SLinus Torvalds  * From RFC 2292
86931da177e4SLinus Torvalds  * 4.2 The cmsghdr Structure *
86941da177e4SLinus Torvalds  *
86951da177e4SLinus Torvalds  * When ancillary data is sent or received, any number of ancillary data
86961da177e4SLinus Torvalds  * objects can be specified by the msg_control and msg_controllen members of
86971da177e4SLinus Torvalds  * the msghdr structure, because each object is preceded by
86981da177e4SLinus Torvalds  * a cmsghdr structure defining the object's length (the cmsg_len member).
86991da177e4SLinus Torvalds  * Historically Berkeley-derived implementations have passed only one object
87001da177e4SLinus Torvalds  * at a time, but this API allows multiple objects to be
87011da177e4SLinus Torvalds  * passed in a single call to sendmsg() or recvmsg(). The following example
87021da177e4SLinus Torvalds  * shows two ancillary data objects in a control buffer.
87031da177e4SLinus Torvalds  *
87041da177e4SLinus Torvalds  *   |<--------------------------- msg_controllen -------------------------->|
87051da177e4SLinus Torvalds  *   |                                                                       |
87061da177e4SLinus Torvalds  *
87071da177e4SLinus Torvalds  *   |<----- ancillary data object ----->|<----- ancillary data object ----->|
87081da177e4SLinus Torvalds  *
87091da177e4SLinus Torvalds  *   |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->|
87101da177e4SLinus Torvalds  *   |                                   |                                   |
87111da177e4SLinus Torvalds  *
87121da177e4SLinus Torvalds  *   |<---------- cmsg_len ---------->|  |<--------- cmsg_len ----------->|  |
87131da177e4SLinus Torvalds  *
87141da177e4SLinus Torvalds  *   |<--------- CMSG_LEN() --------->|  |<-------- CMSG_LEN() ---------->|  |
87151da177e4SLinus Torvalds  *   |                                |  |                                |  |
87161da177e4SLinus Torvalds  *
87171da177e4SLinus Torvalds  *   +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+
87181da177e4SLinus Torvalds  *   |cmsg_|cmsg_|cmsg_|XX|           |XX|cmsg_|cmsg_|cmsg_|XX|           |XX|
87191da177e4SLinus Torvalds  *
87201da177e4SLinus Torvalds  *   |len  |level|type |XX|cmsg_data[]|XX|len  |level|type |XX|cmsg_data[]|XX|
87211da177e4SLinus Torvalds  *
87221da177e4SLinus Torvalds  *   +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+
87231da177e4SLinus Torvalds  *    ^
87241da177e4SLinus Torvalds  *    |
87251da177e4SLinus Torvalds  *
87261da177e4SLinus Torvalds  * msg_control
87271da177e4SLinus Torvalds  * points here
87281da177e4SLinus Torvalds  */
8729a05437acSXin Long static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
87301da177e4SLinus Torvalds {
8731ab38fb04SVlad Yasevich 	struct msghdr *my_msg = (struct msghdr *)msg;
8732a05437acSXin Long 	struct cmsghdr *cmsg;
87331da177e4SLinus Torvalds 
8734f95b414eSGu Zheng 	for_each_cmsghdr(cmsg, my_msg) {
8735ab38fb04SVlad Yasevich 		if (!CMSG_OK(my_msg, cmsg))
87361da177e4SLinus Torvalds 			return -EINVAL;
87371da177e4SLinus Torvalds 
87381da177e4SLinus Torvalds 		/* Should we parse this header or ignore?  */
87391da177e4SLinus Torvalds 		if (cmsg->cmsg_level != IPPROTO_SCTP)
87401da177e4SLinus Torvalds 			continue;
87411da177e4SLinus Torvalds 
87421da177e4SLinus Torvalds 		/* Strictly check lengths following example in SCM code.  */
87431da177e4SLinus Torvalds 		switch (cmsg->cmsg_type) {
87441da177e4SLinus Torvalds 		case SCTP_INIT:
87451da177e4SLinus Torvalds 			/* SCTP Socket API Extension
874663b94938SGeir Ola Vaagland 			 * 5.3.1 SCTP Initiation Structure (SCTP_INIT)
87471da177e4SLinus Torvalds 			 *
87481da177e4SLinus Torvalds 			 * This cmsghdr structure provides information for
87491da177e4SLinus Torvalds 			 * initializing new SCTP associations with sendmsg().
87501da177e4SLinus Torvalds 			 * The SCTP_INITMSG socket option uses this same data
87511da177e4SLinus Torvalds 			 * structure.  This structure is not used for
87521da177e4SLinus Torvalds 			 * recvmsg().
87531da177e4SLinus Torvalds 			 *
87541da177e4SLinus Torvalds 			 * cmsg_level    cmsg_type      cmsg_data[]
87551da177e4SLinus Torvalds 			 * ------------  ------------   ----------------------
87561da177e4SLinus Torvalds 			 * IPPROTO_SCTP  SCTP_INIT      struct sctp_initmsg
87571da177e4SLinus Torvalds 			 */
875863b94938SGeir Ola Vaagland 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg)))
87591da177e4SLinus Torvalds 				return -EINVAL;
876063b94938SGeir Ola Vaagland 
876163b94938SGeir Ola Vaagland 			cmsgs->init = CMSG_DATA(cmsg);
87621da177e4SLinus Torvalds 			break;
87631da177e4SLinus Torvalds 
87641da177e4SLinus Torvalds 		case SCTP_SNDRCV:
87651da177e4SLinus Torvalds 			/* SCTP Socket API Extension
876663b94938SGeir Ola Vaagland 			 * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV)
87671da177e4SLinus Torvalds 			 *
87681da177e4SLinus Torvalds 			 * This cmsghdr structure specifies SCTP options for
87691da177e4SLinus Torvalds 			 * sendmsg() and describes SCTP header information
87701da177e4SLinus Torvalds 			 * about a received message through recvmsg().
87711da177e4SLinus Torvalds 			 *
87721da177e4SLinus Torvalds 			 * cmsg_level    cmsg_type      cmsg_data[]
87731da177e4SLinus Torvalds 			 * ------------  ------------   ----------------------
87741da177e4SLinus Torvalds 			 * IPPROTO_SCTP  SCTP_SNDRCV    struct sctp_sndrcvinfo
87751da177e4SLinus Torvalds 			 */
877663b94938SGeir Ola Vaagland 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
87771da177e4SLinus Torvalds 				return -EINVAL;
87781da177e4SLinus Torvalds 
877963b94938SGeir Ola Vaagland 			cmsgs->srinfo = CMSG_DATA(cmsg);
87801da177e4SLinus Torvalds 
878163b94938SGeir Ola Vaagland 			if (cmsgs->srinfo->sinfo_flags &
8782eaa5c54dSIvan Skytte Jorgensen 			    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
878349102805SXin Long 			      SCTP_SACK_IMMEDIATELY | SCTP_SENDALL |
878449102805SXin Long 			      SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF))
87851da177e4SLinus Torvalds 				return -EINVAL;
87861da177e4SLinus Torvalds 			break;
87871da177e4SLinus Torvalds 
878863b94938SGeir Ola Vaagland 		case SCTP_SNDINFO:
878963b94938SGeir Ola Vaagland 			/* SCTP Socket API Extension
879063b94938SGeir Ola Vaagland 			 * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO)
879163b94938SGeir Ola Vaagland 			 *
879263b94938SGeir Ola Vaagland 			 * This cmsghdr structure specifies SCTP options for
879363b94938SGeir Ola Vaagland 			 * sendmsg(). This structure and SCTP_RCVINFO replaces
879463b94938SGeir Ola Vaagland 			 * SCTP_SNDRCV which has been deprecated.
879563b94938SGeir Ola Vaagland 			 *
879663b94938SGeir Ola Vaagland 			 * cmsg_level    cmsg_type      cmsg_data[]
879763b94938SGeir Ola Vaagland 			 * ------------  ------------   ---------------------
879863b94938SGeir Ola Vaagland 			 * IPPROTO_SCTP  SCTP_SNDINFO    struct sctp_sndinfo
879963b94938SGeir Ola Vaagland 			 */
880063b94938SGeir Ola Vaagland 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo)))
880163b94938SGeir Ola Vaagland 				return -EINVAL;
880263b94938SGeir Ola Vaagland 
880363b94938SGeir Ola Vaagland 			cmsgs->sinfo = CMSG_DATA(cmsg);
880463b94938SGeir Ola Vaagland 
880563b94938SGeir Ola Vaagland 			if (cmsgs->sinfo->snd_flags &
880663b94938SGeir Ola Vaagland 			    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
880749102805SXin Long 			      SCTP_SACK_IMMEDIATELY | SCTP_SENDALL |
880849102805SXin Long 			      SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF))
880963b94938SGeir Ola Vaagland 				return -EINVAL;
881063b94938SGeir Ola Vaagland 			break;
8811ed63afb8SXin Long 		case SCTP_PRINFO:
8812ed63afb8SXin Long 			/* SCTP Socket API Extension
8813ed63afb8SXin Long 			 * 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO)
8814ed63afb8SXin Long 			 *
8815ed63afb8SXin Long 			 * This cmsghdr structure specifies SCTP options for sendmsg().
8816ed63afb8SXin Long 			 *
8817ed63afb8SXin Long 			 * cmsg_level    cmsg_type      cmsg_data[]
8818ed63afb8SXin Long 			 * ------------  ------------   ---------------------
8819ed63afb8SXin Long 			 * IPPROTO_SCTP  SCTP_PRINFO    struct sctp_prinfo
8820ed63afb8SXin Long 			 */
8821ed63afb8SXin Long 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_prinfo)))
8822ed63afb8SXin Long 				return -EINVAL;
8823ed63afb8SXin Long 
8824ed63afb8SXin Long 			cmsgs->prinfo = CMSG_DATA(cmsg);
8825ed63afb8SXin Long 			if (cmsgs->prinfo->pr_policy & ~SCTP_PR_SCTP_MASK)
8826ed63afb8SXin Long 				return -EINVAL;
8827ed63afb8SXin Long 
8828ed63afb8SXin Long 			if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
8829ed63afb8SXin Long 				cmsgs->prinfo->pr_value = 0;
8830ed63afb8SXin Long 			break;
88313ff547c0SXin Long 		case SCTP_AUTHINFO:
88323ff547c0SXin Long 			/* SCTP Socket API Extension
88333ff547c0SXin Long 			 * 5.3.8 SCTP AUTH Information Structure (SCTP_AUTHINFO)
88343ff547c0SXin Long 			 *
88353ff547c0SXin Long 			 * This cmsghdr structure specifies SCTP options for sendmsg().
88363ff547c0SXin Long 			 *
88373ff547c0SXin Long 			 * cmsg_level    cmsg_type      cmsg_data[]
88383ff547c0SXin Long 			 * ------------  ------------   ---------------------
88393ff547c0SXin Long 			 * IPPROTO_SCTP  SCTP_AUTHINFO  struct sctp_authinfo
88403ff547c0SXin Long 			 */
88413ff547c0SXin Long 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_authinfo)))
88423ff547c0SXin Long 				return -EINVAL;
88433ff547c0SXin Long 
88443ff547c0SXin Long 			cmsgs->authinfo = CMSG_DATA(cmsg);
88453ff547c0SXin Long 			break;
88462c0dbaa0SXin Long 		case SCTP_DSTADDRV4:
88472c0dbaa0SXin Long 		case SCTP_DSTADDRV6:
88482c0dbaa0SXin Long 			/* SCTP Socket API Extension
88492c0dbaa0SXin Long 			 * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6)
88502c0dbaa0SXin Long 			 *
88512c0dbaa0SXin Long 			 * This cmsghdr structure specifies SCTP options for sendmsg().
88522c0dbaa0SXin Long 			 *
88532c0dbaa0SXin Long 			 * cmsg_level    cmsg_type         cmsg_data[]
88542c0dbaa0SXin Long 			 * ------------  ------------   ---------------------
88552c0dbaa0SXin Long 			 * IPPROTO_SCTP  SCTP_DSTADDRV4 struct in_addr
88562c0dbaa0SXin Long 			 * ------------  ------------   ---------------------
88572c0dbaa0SXin Long 			 * IPPROTO_SCTP  SCTP_DSTADDRV6 struct in6_addr
88582c0dbaa0SXin Long 			 */
88592c0dbaa0SXin Long 			cmsgs->addrs_msg = my_msg;
88602c0dbaa0SXin Long 			break;
88611da177e4SLinus Torvalds 		default:
88621da177e4SLinus Torvalds 			return -EINVAL;
88633ff50b79SStephen Hemminger 		}
88641da177e4SLinus Torvalds 	}
886563b94938SGeir Ola Vaagland 
88661da177e4SLinus Torvalds 	return 0;
88671da177e4SLinus Torvalds }
88681da177e4SLinus Torvalds 
88691da177e4SLinus Torvalds /*
88701da177e4SLinus Torvalds  * Wait for a packet..
88711da177e4SLinus Torvalds  * Note: This function is the same function as in core/datagram.c
88721da177e4SLinus Torvalds  * with a few modifications to make lksctp work.
88731da177e4SLinus Torvalds  */
88741da177e4SLinus Torvalds static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p)
88751da177e4SLinus Torvalds {
88761da177e4SLinus Torvalds 	int error;
88771da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
88781da177e4SLinus Torvalds 
8879aa395145SEric Dumazet 	prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
88801da177e4SLinus Torvalds 
88811da177e4SLinus Torvalds 	/* Socket errors? */
88821da177e4SLinus Torvalds 	error = sock_error(sk);
88831da177e4SLinus Torvalds 	if (error)
88841da177e4SLinus Torvalds 		goto out;
88851da177e4SLinus Torvalds 
88861da177e4SLinus Torvalds 	if (!skb_queue_empty(&sk->sk_receive_queue))
88871da177e4SLinus Torvalds 		goto ready;
88881da177e4SLinus Torvalds 
88891da177e4SLinus Torvalds 	/* Socket shut down?  */
88901da177e4SLinus Torvalds 	if (sk->sk_shutdown & RCV_SHUTDOWN)
88911da177e4SLinus Torvalds 		goto out;
88921da177e4SLinus Torvalds 
88931da177e4SLinus Torvalds 	/* Sequenced packets can come disconnected.  If so we report the
88941da177e4SLinus Torvalds 	 * problem.
88951da177e4SLinus Torvalds 	 */
88961da177e4SLinus Torvalds 	error = -ENOTCONN;
88971da177e4SLinus Torvalds 
88981da177e4SLinus Torvalds 	/* Is there a good reason to think that we may receive some data?  */
88991da177e4SLinus Torvalds 	if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING))
89001da177e4SLinus Torvalds 		goto out;
89011da177e4SLinus Torvalds 
89021da177e4SLinus Torvalds 	/* Handle signals.  */
89031da177e4SLinus Torvalds 	if (signal_pending(current))
89041da177e4SLinus Torvalds 		goto interrupted;
89051da177e4SLinus Torvalds 
89061da177e4SLinus Torvalds 	/* Let another process have a go.  Since we are going to sleep
89071da177e4SLinus Torvalds 	 * anyway.  Note: This may cause odd behaviors if the message
89081da177e4SLinus Torvalds 	 * does not fit in the user's buffer, but this seems to be the
89091da177e4SLinus Torvalds 	 * only way to honor MSG_DONTWAIT realistically.
89101da177e4SLinus Torvalds 	 */
8911048ed4b6Swangweidong 	release_sock(sk);
89121da177e4SLinus Torvalds 	*timeo_p = schedule_timeout(*timeo_p);
8913048ed4b6Swangweidong 	lock_sock(sk);
89141da177e4SLinus Torvalds 
89151da177e4SLinus Torvalds ready:
8916aa395145SEric Dumazet 	finish_wait(sk_sleep(sk), &wait);
89171da177e4SLinus Torvalds 	return 0;
89181da177e4SLinus Torvalds 
89191da177e4SLinus Torvalds interrupted:
89201da177e4SLinus Torvalds 	error = sock_intr_errno(*timeo_p);
89211da177e4SLinus Torvalds 
89221da177e4SLinus Torvalds out:
8923aa395145SEric Dumazet 	finish_wait(sk_sleep(sk), &wait);
89241da177e4SLinus Torvalds 	*err = error;
89251da177e4SLinus Torvalds 	return error;
89261da177e4SLinus Torvalds }
89271da177e4SLinus Torvalds 
89281da177e4SLinus Torvalds /* Receive a datagram.
89291da177e4SLinus Torvalds  * Note: This is pretty much the same routine as in core/datagram.c
89301da177e4SLinus Torvalds  * with a few changes to make lksctp work.
89311da177e4SLinus Torvalds  */
89322347c80fSGeir Ola Vaagland struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
89331da177e4SLinus Torvalds 				       int noblock, int *err)
89341da177e4SLinus Torvalds {
89351da177e4SLinus Torvalds 	int error;
89361da177e4SLinus Torvalds 	struct sk_buff *skb;
89371da177e4SLinus Torvalds 	long timeo;
89381da177e4SLinus Torvalds 
89391da177e4SLinus Torvalds 	timeo = sock_rcvtimeo(sk, noblock);
89401da177e4SLinus Torvalds 
8941bb33381dSDaniel Borkmann 	pr_debug("%s: timeo:%ld, max:%ld\n", __func__, timeo,
8942bb33381dSDaniel Borkmann 		 MAX_SCHEDULE_TIMEOUT);
89431da177e4SLinus Torvalds 
89441da177e4SLinus Torvalds 	do {
89451da177e4SLinus Torvalds 		/* Again only user level code calls this function,
89461da177e4SLinus Torvalds 		 * so nothing interrupt level
89471da177e4SLinus Torvalds 		 * will suddenly eat the receive_queue.
89481da177e4SLinus Torvalds 		 *
89491da177e4SLinus Torvalds 		 *  Look at current nfs client by the way...
89508917a3c0SDavid Shwatrz 		 *  However, this function was correct in any case. 8)
89511da177e4SLinus Torvalds 		 */
89521da177e4SLinus Torvalds 		if (flags & MSG_PEEK) {
89531da177e4SLinus Torvalds 			skb = skb_peek(&sk->sk_receive_queue);
89541da177e4SLinus Torvalds 			if (skb)
895563354797SReshetova, Elena 				refcount_inc(&skb->users);
89561da177e4SLinus Torvalds 		} else {
8957311b2177SMarcelo Ricardo Leitner 			skb = __skb_dequeue(&sk->sk_receive_queue);
89581da177e4SLinus Torvalds 		}
89591da177e4SLinus Torvalds 
89601da177e4SLinus Torvalds 		if (skb)
89611da177e4SLinus Torvalds 			return skb;
89621da177e4SLinus Torvalds 
89636736dc35SNeil Horman 		/* Caller is allowed not to check sk->sk_err before calling. */
89646736dc35SNeil Horman 		error = sock_error(sk);
89656736dc35SNeil Horman 		if (error)
89666736dc35SNeil Horman 			goto no_packet;
89676736dc35SNeil Horman 
89681da177e4SLinus Torvalds 		if (sk->sk_shutdown & RCV_SHUTDOWN)
89691da177e4SLinus Torvalds 			break;
89701da177e4SLinus Torvalds 
89712b5cd0dfSAlexander Duyck 		if (sk_can_busy_loop(sk)) {
89722b5cd0dfSAlexander Duyck 			sk_busy_loop(sk, noblock);
89732b5cd0dfSAlexander Duyck 
89743f926af3SEric Dumazet 			if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
89758465a5fcSNeil Horman 				continue;
89762b5cd0dfSAlexander Duyck 		}
89778465a5fcSNeil Horman 
89781da177e4SLinus Torvalds 		/* User doesn't want to wait.  */
89791da177e4SLinus Torvalds 		error = -EAGAIN;
89801da177e4SLinus Torvalds 		if (!timeo)
89811da177e4SLinus Torvalds 			goto no_packet;
89821da177e4SLinus Torvalds 	} while (sctp_wait_for_packet(sk, err, &timeo) == 0);
89831da177e4SLinus Torvalds 
89841da177e4SLinus Torvalds 	return NULL;
89851da177e4SLinus Torvalds 
89861da177e4SLinus Torvalds no_packet:
89871da177e4SLinus Torvalds 	*err = error;
89881da177e4SLinus Torvalds 	return NULL;
89891da177e4SLinus Torvalds }
89901da177e4SLinus Torvalds 
89911da177e4SLinus Torvalds /* If sndbuf has changed, wake up per association sndbuf waiters.  */
89921da177e4SLinus Torvalds static void __sctp_write_space(struct sctp_association *asoc)
89931da177e4SLinus Torvalds {
89941da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
89951da177e4SLinus Torvalds 
8996ceb5d58bSEric Dumazet 	if (sctp_wspace(asoc) <= 0)
8997ceb5d58bSEric Dumazet 		return;
8998ceb5d58bSEric Dumazet 
89991da177e4SLinus Torvalds 	if (waitqueue_active(&asoc->wait))
90001da177e4SLinus Torvalds 		wake_up_interruptible(&asoc->wait);
90011da177e4SLinus Torvalds 
90021da177e4SLinus Torvalds 	if (sctp_writeable(sk)) {
9003ceb5d58bSEric Dumazet 		struct socket_wq *wq;
9004eaefd110SEric Dumazet 
9005ceb5d58bSEric Dumazet 		rcu_read_lock();
9006ceb5d58bSEric Dumazet 		wq = rcu_dereference(sk->sk_wq);
9007ceb5d58bSEric Dumazet 		if (wq) {
9008ceb5d58bSEric Dumazet 			if (waitqueue_active(&wq->wait))
9009ceb5d58bSEric Dumazet 				wake_up_interruptible(&wq->wait);
90101da177e4SLinus Torvalds 
90111da177e4SLinus Torvalds 			/* Note that we try to include the Async I/O support
90121da177e4SLinus Torvalds 			 * here by modeling from the current TCP/UDP code.
90131da177e4SLinus Torvalds 			 * We have not tested with it yet.
90141da177e4SLinus Torvalds 			 */
9015eaefd110SEric Dumazet 			if (!(sk->sk_shutdown & SEND_SHUTDOWN))
9016ceb5d58bSEric Dumazet 				sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT);
90171da177e4SLinus Torvalds 		}
9018ceb5d58bSEric Dumazet 		rcu_read_unlock();
90191da177e4SLinus Torvalds 	}
90201da177e4SLinus Torvalds }
90211da177e4SLinus Torvalds 
902252c35befSDaniel Borkmann static void sctp_wake_up_waiters(struct sock *sk,
902352c35befSDaniel Borkmann 				 struct sctp_association *asoc)
902452c35befSDaniel Borkmann {
902552c35befSDaniel Borkmann 	struct sctp_association *tmp = asoc;
902652c35befSDaniel Borkmann 
902752c35befSDaniel Borkmann 	/* We do accounting for the sndbuf space per association,
902852c35befSDaniel Borkmann 	 * so we only need to wake our own association.
902952c35befSDaniel Borkmann 	 */
903052c35befSDaniel Borkmann 	if (asoc->ep->sndbuf_policy)
903152c35befSDaniel Borkmann 		return __sctp_write_space(asoc);
903252c35befSDaniel Borkmann 
90331e1cdf8aSDaniel Borkmann 	/* If association goes down and is just flushing its
90341e1cdf8aSDaniel Borkmann 	 * outq, then just normally notify others.
90351e1cdf8aSDaniel Borkmann 	 */
90361e1cdf8aSDaniel Borkmann 	if (asoc->base.dead)
90371e1cdf8aSDaniel Borkmann 		return sctp_write_space(sk);
90381e1cdf8aSDaniel Borkmann 
903952c35befSDaniel Borkmann 	/* Accounting for the sndbuf space is per socket, so we
904052c35befSDaniel Borkmann 	 * need to wake up others, try to be fair and in case of
904152c35befSDaniel Borkmann 	 * other associations, let them have a go first instead
904252c35befSDaniel Borkmann 	 * of just doing a sctp_write_space() call.
904352c35befSDaniel Borkmann 	 *
904452c35befSDaniel Borkmann 	 * Note that we reach sctp_wake_up_waiters() only when
904552c35befSDaniel Borkmann 	 * associations free up queued chunks, thus we are under
904652c35befSDaniel Borkmann 	 * lock and the list of associations on a socket is
904752c35befSDaniel Borkmann 	 * guaranteed not to change.
904852c35befSDaniel Borkmann 	 */
904952c35befSDaniel Borkmann 	for (tmp = list_next_entry(tmp, asocs); 1;
905052c35befSDaniel Borkmann 	     tmp = list_next_entry(tmp, asocs)) {
905152c35befSDaniel Borkmann 		/* Manually skip the head element. */
905252c35befSDaniel Borkmann 		if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs))
905352c35befSDaniel Borkmann 			continue;
905452c35befSDaniel Borkmann 		/* Wake up association. */
905552c35befSDaniel Borkmann 		__sctp_write_space(tmp);
905652c35befSDaniel Borkmann 		/* We've reached the end. */
905752c35befSDaniel Borkmann 		if (tmp == asoc)
905852c35befSDaniel Borkmann 			break;
905952c35befSDaniel Borkmann 	}
906052c35befSDaniel Borkmann }
906152c35befSDaniel Borkmann 
90621da177e4SLinus Torvalds /* Do accounting for the sndbuf space.
90631da177e4SLinus Torvalds  * Decrement the used sndbuf space of the corresponding association by the
90641da177e4SLinus Torvalds  * data size which was just transmitted(freed).
90651da177e4SLinus Torvalds  */
90661da177e4SLinus Torvalds static void sctp_wfree(struct sk_buff *skb)
90671da177e4SLinus Torvalds {
9068f869c912SDaniel Borkmann 	struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg;
9069f869c912SDaniel Borkmann 	struct sctp_association *asoc = chunk->asoc;
9070f869c912SDaniel Borkmann 	struct sock *sk = asoc->base.sk;
90711da177e4SLinus Torvalds 
90723ab224beSHideo Aoki 	sk_mem_uncharge(sk, skb->truesize);
9073605c0ac1SXin Long 	sk->sk_wmem_queued -= skb->truesize + sizeof(struct sctp_chunk);
9074605c0ac1SXin Long 	asoc->sndbuf_used -= skb->truesize + sizeof(struct sctp_chunk);
9075605c0ac1SXin Long 	WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk),
9076605c0ac1SXin Long 				      &sk->sk_wmem_alloc));
90774d93df0aSNeil Horman 
9078ec2e506cSXin Long 	if (chunk->shkey) {
9079ec2e506cSXin Long 		struct sctp_shared_key *shkey = chunk->shkey;
9080ec2e506cSXin Long 
9081ec2e506cSXin Long 		/* refcnt == 2 and !list_empty mean after this release, it's
9082ec2e506cSXin Long 		 * not being used anywhere, and it's time to notify userland
9083ec2e506cSXin Long 		 * that this shkey can be freed if it's been deactivated.
9084ec2e506cSXin Long 		 */
9085ec2e506cSXin Long 		if (shkey->deactivated && !list_empty(&shkey->key_list) &&
9086ec2e506cSXin Long 		    refcount_read(&shkey->refcnt) == 2) {
9087ec2e506cSXin Long 			struct sctp_ulpevent *ev;
9088ec2e506cSXin Long 
9089ec2e506cSXin Long 			ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id,
9090ec2e506cSXin Long 							SCTP_AUTH_FREE_KEY,
9091ec2e506cSXin Long 							GFP_KERNEL);
9092ec2e506cSXin Long 			if (ev)
9093ec2e506cSXin Long 				asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
9094ec2e506cSXin Long 		}
90951b1e0bc9SXin Long 		sctp_auth_shkey_release(chunk->shkey);
9096ec2e506cSXin Long 	}
90971b1e0bc9SXin Long 
90984eb701dfSNeil Horman 	sock_wfree(skb);
909952c35befSDaniel Borkmann 	sctp_wake_up_waiters(sk, asoc);
91001da177e4SLinus Torvalds 
91011da177e4SLinus Torvalds 	sctp_association_put(asoc);
91021da177e4SLinus Torvalds }
91031da177e4SLinus Torvalds 
9104331c4ee7SVlad Yasevich /* Do accounting for the receive space on the socket.
9105331c4ee7SVlad Yasevich  * Accounting for the association is done in ulpevent.c
9106331c4ee7SVlad Yasevich  * We set this as a destructor for the cloned data skbs so that
9107331c4ee7SVlad Yasevich  * accounting is done at the correct time.
9108331c4ee7SVlad Yasevich  */
9109331c4ee7SVlad Yasevich void sctp_sock_rfree(struct sk_buff *skb)
9110331c4ee7SVlad Yasevich {
9111331c4ee7SVlad Yasevich 	struct sock *sk = skb->sk;
9112331c4ee7SVlad Yasevich 	struct sctp_ulpevent *event = sctp_skb2event(skb);
9113331c4ee7SVlad Yasevich 
9114331c4ee7SVlad Yasevich 	atomic_sub(event->rmem_len, &sk->sk_rmem_alloc);
91154d93df0aSNeil Horman 
91164d93df0aSNeil Horman 	/*
91173ab224beSHideo Aoki 	 * Mimic the behavior of sock_rfree
91184d93df0aSNeil Horman 	 */
91193ab224beSHideo Aoki 	sk_mem_uncharge(sk, event->rmem_len);
9120331c4ee7SVlad Yasevich }
9121331c4ee7SVlad Yasevich 
9122331c4ee7SVlad Yasevich 
91231da177e4SLinus Torvalds /* Helper function to wait for space in the sndbuf.  */
91241da177e4SLinus Torvalds static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
9125a0ff6600SXin Long 				size_t msg_len)
91261da177e4SLinus Torvalds {
91271da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
91281da177e4SLinus Torvalds 	long current_timeo = *timeo_p;
91291da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
9130a0ff6600SXin Long 	int err = 0;
91311da177e4SLinus Torvalds 
9132bb33381dSDaniel Borkmann 	pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc,
9133bb33381dSDaniel Borkmann 		 *timeo_p, msg_len);
91341da177e4SLinus Torvalds 
91351da177e4SLinus Torvalds 	/* Increment the association's refcnt.  */
91361da177e4SLinus Torvalds 	sctp_association_hold(asoc);
91371da177e4SLinus Torvalds 
91381da177e4SLinus Torvalds 	/* Wait on the association specific sndbuf space. */
91391da177e4SLinus Torvalds 	for (;;) {
91401da177e4SLinus Torvalds 		prepare_to_wait_exclusive(&asoc->wait, &wait,
91411da177e4SLinus Torvalds 					  TASK_INTERRUPTIBLE);
9142ca3af4ddSXin Long 		if (asoc->base.dead)
9143ca3af4ddSXin Long 			goto do_dead;
91441da177e4SLinus Torvalds 		if (!*timeo_p)
91451da177e4SLinus Torvalds 			goto do_nonblock;
9146ca3af4ddSXin Long 		if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING)
91471da177e4SLinus Torvalds 			goto do_error;
91481da177e4SLinus Torvalds 		if (signal_pending(current))
91491da177e4SLinus Torvalds 			goto do_interrupted;
91501033990aSXin Long 		if (sk_under_memory_pressure(sk))
91511033990aSXin Long 			sk_mem_reclaim(sk);
91521033990aSXin Long 		if ((int)msg_len <= sctp_wspace(asoc) &&
91531033990aSXin Long 		    sk_wmem_schedule(sk, msg_len))
91541da177e4SLinus Torvalds 			break;
91551da177e4SLinus Torvalds 
91561da177e4SLinus Torvalds 		/* Let another process have a go.  Since we are going
91571da177e4SLinus Torvalds 		 * to sleep anyway.
91581da177e4SLinus Torvalds 		 */
9159048ed4b6Swangweidong 		release_sock(sk);
91601da177e4SLinus Torvalds 		current_timeo = schedule_timeout(current_timeo);
9161048ed4b6Swangweidong 		lock_sock(sk);
9162a0ff6600SXin Long 		if (sk != asoc->base.sk)
9163a0ff6600SXin Long 			goto do_error;
91641da177e4SLinus Torvalds 
91651da177e4SLinus Torvalds 		*timeo_p = current_timeo;
91661da177e4SLinus Torvalds 	}
91671da177e4SLinus Torvalds 
91681da177e4SLinus Torvalds out:
91691da177e4SLinus Torvalds 	finish_wait(&asoc->wait, &wait);
91701da177e4SLinus Torvalds 
91711da177e4SLinus Torvalds 	/* Release the association's refcnt.  */
91721da177e4SLinus Torvalds 	sctp_association_put(asoc);
91731da177e4SLinus Torvalds 
91741da177e4SLinus Torvalds 	return err;
91751da177e4SLinus Torvalds 
9176ca3af4ddSXin Long do_dead:
9177ca3af4ddSXin Long 	err = -ESRCH;
9178ca3af4ddSXin Long 	goto out;
9179ca3af4ddSXin Long 
91801da177e4SLinus Torvalds do_error:
91811da177e4SLinus Torvalds 	err = -EPIPE;
91821da177e4SLinus Torvalds 	goto out;
91831da177e4SLinus Torvalds 
91841da177e4SLinus Torvalds do_interrupted:
91851da177e4SLinus Torvalds 	err = sock_intr_errno(*timeo_p);
91861da177e4SLinus Torvalds 	goto out;
91871da177e4SLinus Torvalds 
91881da177e4SLinus Torvalds do_nonblock:
91891da177e4SLinus Torvalds 	err = -EAGAIN;
91901da177e4SLinus Torvalds 	goto out;
91911da177e4SLinus Torvalds }
91921da177e4SLinus Torvalds 
9193676d2369SDavid S. Miller void sctp_data_ready(struct sock *sk)
9194561b1733SWei Yongjun {
91957ef52737SDavid S. Miller 	struct socket_wq *wq;
91967ef52737SDavid S. Miller 
91977ef52737SDavid S. Miller 	rcu_read_lock();
91987ef52737SDavid S. Miller 	wq = rcu_dereference(sk->sk_wq);
91991ce0bf50SHerbert Xu 	if (skwq_has_sleeper(wq))
9200a9a08845SLinus Torvalds 		wake_up_interruptible_sync_poll(&wq->wait, EPOLLIN |
9201a9a08845SLinus Torvalds 						EPOLLRDNORM | EPOLLRDBAND);
9202561b1733SWei Yongjun 	sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
92037ef52737SDavid S. Miller 	rcu_read_unlock();
9204561b1733SWei Yongjun }
9205561b1733SWei Yongjun 
92061da177e4SLinus Torvalds /* If socket sndbuf has changed, wake up all per association waiters.  */
92071da177e4SLinus Torvalds void sctp_write_space(struct sock *sk)
92081da177e4SLinus Torvalds {
92091da177e4SLinus Torvalds 	struct sctp_association *asoc;
92101da177e4SLinus Torvalds 
92111da177e4SLinus Torvalds 	/* Wake up the tasks in each wait queue.  */
92129dbc15f0SRobert P. J. Day 	list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) {
92131da177e4SLinus Torvalds 		__sctp_write_space(asoc);
92141da177e4SLinus Torvalds 	}
92151da177e4SLinus Torvalds }
92161da177e4SLinus Torvalds 
92171da177e4SLinus Torvalds /* Is there any sndbuf space available on the socket?
92181da177e4SLinus Torvalds  *
92199bffc4acSNeil Horman  * Note that sk_wmem_alloc is the sum of the send buffers on all of the
92201da177e4SLinus Torvalds  * associations on the same socket.  For a UDP-style socket with
92211da177e4SLinus Torvalds  * multiple associations, it is possible for it to be "unwriteable"
92221da177e4SLinus Torvalds  * prematurely.  I assume that this is acceptable because
92231da177e4SLinus Torvalds  * a premature "unwriteable" is better than an accidental "writeable" which
92241da177e4SLinus Torvalds  * would cause an unwanted block under certain circumstances.  For the 1-1
92251da177e4SLinus Torvalds  * UDP-style sockets or TCP-style sockets, this code should work.
92261da177e4SLinus Torvalds  *  - Daisy
92271da177e4SLinus Torvalds  */
9228cd305c74SXin Long static bool sctp_writeable(struct sock *sk)
92291da177e4SLinus Torvalds {
9230cd305c74SXin Long 	return sk->sk_sndbuf > sk->sk_wmem_queued;
92311da177e4SLinus Torvalds }
92321da177e4SLinus Torvalds 
92331da177e4SLinus Torvalds /* Wait for an association to go into ESTABLISHED state. If timeout is 0,
92341da177e4SLinus Torvalds  * returns immediately with EINPROGRESS.
92351da177e4SLinus Torvalds  */
92361da177e4SLinus Torvalds static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)
92371da177e4SLinus Torvalds {
92381da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
92391da177e4SLinus Torvalds 	int err = 0;
92401da177e4SLinus Torvalds 	long current_timeo = *timeo_p;
92411da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
92421da177e4SLinus Torvalds 
9243bb33381dSDaniel Borkmann 	pr_debug("%s: asoc:%p, timeo:%ld\n", __func__, asoc, *timeo_p);
92441da177e4SLinus Torvalds 
92451da177e4SLinus Torvalds 	/* Increment the association's refcnt.  */
92461da177e4SLinus Torvalds 	sctp_association_hold(asoc);
92471da177e4SLinus Torvalds 
92481da177e4SLinus Torvalds 	for (;;) {
92491da177e4SLinus Torvalds 		prepare_to_wait_exclusive(&asoc->wait, &wait,
92501da177e4SLinus Torvalds 					  TASK_INTERRUPTIBLE);
92511da177e4SLinus Torvalds 		if (!*timeo_p)
92521da177e4SLinus Torvalds 			goto do_nonblock;
92531da177e4SLinus Torvalds 		if (sk->sk_shutdown & RCV_SHUTDOWN)
92541da177e4SLinus Torvalds 			break;
92551da177e4SLinus Torvalds 		if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
92561da177e4SLinus Torvalds 		    asoc->base.dead)
92571da177e4SLinus Torvalds 			goto do_error;
92581da177e4SLinus Torvalds 		if (signal_pending(current))
92591da177e4SLinus Torvalds 			goto do_interrupted;
92601da177e4SLinus Torvalds 
92611da177e4SLinus Torvalds 		if (sctp_state(asoc, ESTABLISHED))
92621da177e4SLinus Torvalds 			break;
92631da177e4SLinus Torvalds 
92641da177e4SLinus Torvalds 		/* Let another process have a go.  Since we are going
92651da177e4SLinus Torvalds 		 * to sleep anyway.
92661da177e4SLinus Torvalds 		 */
9267048ed4b6Swangweidong 		release_sock(sk);
92681da177e4SLinus Torvalds 		current_timeo = schedule_timeout(current_timeo);
9269048ed4b6Swangweidong 		lock_sock(sk);
92701da177e4SLinus Torvalds 
92711da177e4SLinus Torvalds 		*timeo_p = current_timeo;
92721da177e4SLinus Torvalds 	}
92731da177e4SLinus Torvalds 
92741da177e4SLinus Torvalds out:
92751da177e4SLinus Torvalds 	finish_wait(&asoc->wait, &wait);
92761da177e4SLinus Torvalds 
92771da177e4SLinus Torvalds 	/* Release the association's refcnt.  */
92781da177e4SLinus Torvalds 	sctp_association_put(asoc);
92791da177e4SLinus Torvalds 
92801da177e4SLinus Torvalds 	return err;
92811da177e4SLinus Torvalds 
92821da177e4SLinus Torvalds do_error:
928381845c21SVlad Yasevich 	if (asoc->init_err_counter + 1 > asoc->max_init_attempts)
92841da177e4SLinus Torvalds 		err = -ETIMEDOUT;
92851da177e4SLinus Torvalds 	else
92861da177e4SLinus Torvalds 		err = -ECONNREFUSED;
92871da177e4SLinus Torvalds 	goto out;
92881da177e4SLinus Torvalds 
92891da177e4SLinus Torvalds do_interrupted:
92901da177e4SLinus Torvalds 	err = sock_intr_errno(*timeo_p);
92911da177e4SLinus Torvalds 	goto out;
92921da177e4SLinus Torvalds 
92931da177e4SLinus Torvalds do_nonblock:
92941da177e4SLinus Torvalds 	err = -EINPROGRESS;
92951da177e4SLinus Torvalds 	goto out;
92961da177e4SLinus Torvalds }
92971da177e4SLinus Torvalds 
92981da177e4SLinus Torvalds static int sctp_wait_for_accept(struct sock *sk, long timeo)
92991da177e4SLinus Torvalds {
93001da177e4SLinus Torvalds 	struct sctp_endpoint *ep;
93011da177e4SLinus Torvalds 	int err = 0;
93021da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
93031da177e4SLinus Torvalds 
93041da177e4SLinus Torvalds 	ep = sctp_sk(sk)->ep;
93051da177e4SLinus Torvalds 
93061da177e4SLinus Torvalds 
93071da177e4SLinus Torvalds 	for (;;) {
9308aa395145SEric Dumazet 		prepare_to_wait_exclusive(sk_sleep(sk), &wait,
93091da177e4SLinus Torvalds 					  TASK_INTERRUPTIBLE);
93101da177e4SLinus Torvalds 
93111da177e4SLinus Torvalds 		if (list_empty(&ep->asocs)) {
9312048ed4b6Swangweidong 			release_sock(sk);
93131da177e4SLinus Torvalds 			timeo = schedule_timeout(timeo);
9314048ed4b6Swangweidong 			lock_sock(sk);
93151da177e4SLinus Torvalds 		}
93161da177e4SLinus Torvalds 
93171da177e4SLinus Torvalds 		err = -EINVAL;
93181da177e4SLinus Torvalds 		if (!sctp_sstate(sk, LISTENING))
93191da177e4SLinus Torvalds 			break;
93201da177e4SLinus Torvalds 
93211da177e4SLinus Torvalds 		err = 0;
93221da177e4SLinus Torvalds 		if (!list_empty(&ep->asocs))
93231da177e4SLinus Torvalds 			break;
93241da177e4SLinus Torvalds 
93251da177e4SLinus Torvalds 		err = sock_intr_errno(timeo);
93261da177e4SLinus Torvalds 		if (signal_pending(current))
93271da177e4SLinus Torvalds 			break;
93281da177e4SLinus Torvalds 
93291da177e4SLinus Torvalds 		err = -EAGAIN;
93301da177e4SLinus Torvalds 		if (!timeo)
93311da177e4SLinus Torvalds 			break;
93321da177e4SLinus Torvalds 	}
93331da177e4SLinus Torvalds 
9334aa395145SEric Dumazet 	finish_wait(sk_sleep(sk), &wait);
93351da177e4SLinus Torvalds 
93361da177e4SLinus Torvalds 	return err;
93371da177e4SLinus Torvalds }
93381da177e4SLinus Torvalds 
933904675210Ssebastian@breakpoint.cc static void sctp_wait_for_close(struct sock *sk, long timeout)
93401da177e4SLinus Torvalds {
93411da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
93421da177e4SLinus Torvalds 
93431da177e4SLinus Torvalds 	do {
9344aa395145SEric Dumazet 		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
93451da177e4SLinus Torvalds 		if (list_empty(&sctp_sk(sk)->ep->asocs))
93461da177e4SLinus Torvalds 			break;
9347048ed4b6Swangweidong 		release_sock(sk);
93481da177e4SLinus Torvalds 		timeout = schedule_timeout(timeout);
9349048ed4b6Swangweidong 		lock_sock(sk);
93501da177e4SLinus Torvalds 	} while (!signal_pending(current) && timeout);
93511da177e4SLinus Torvalds 
9352aa395145SEric Dumazet 	finish_wait(sk_sleep(sk), &wait);
93531da177e4SLinus Torvalds }
93541da177e4SLinus Torvalds 
9355ea2bc483STsutomu Fujii static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
9356ea2bc483STsutomu Fujii {
9357ea2bc483STsutomu Fujii 	struct sk_buff *frag;
9358ea2bc483STsutomu Fujii 
9359ea2bc483STsutomu Fujii 	if (!skb->data_len)
9360ea2bc483STsutomu Fujii 		goto done;
9361ea2bc483STsutomu Fujii 
9362ea2bc483STsutomu Fujii 	/* Don't forget the fragments. */
93631b003be3SDavid S. Miller 	skb_walk_frags(skb, frag)
9364ea2bc483STsutomu Fujii 		sctp_skb_set_owner_r_frag(frag, sk);
9365ea2bc483STsutomu Fujii 
9366ea2bc483STsutomu Fujii done:
9367ea2bc483STsutomu Fujii 	sctp_skb_set_owner_r(skb, sk);
9368ea2bc483STsutomu Fujii }
9369ea2bc483STsutomu Fujii 
9370914e1c8bSVlad Yasevich void sctp_copy_sock(struct sock *newsk, struct sock *sk,
9371914e1c8bSVlad Yasevich 		    struct sctp_association *asoc)
9372914e1c8bSVlad Yasevich {
9373914e1c8bSVlad Yasevich 	struct inet_sock *inet = inet_sk(sk);
937409cb47a2SJulia Lawall 	struct inet_sock *newinet;
93752277c7cdSRichard Haines 	struct sctp_sock *sp = sctp_sk(sk);
93762277c7cdSRichard Haines 	struct sctp_endpoint *ep = sp->ep;
9377914e1c8bSVlad Yasevich 
9378914e1c8bSVlad Yasevich 	newsk->sk_type = sk->sk_type;
9379914e1c8bSVlad Yasevich 	newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
9380914e1c8bSVlad Yasevich 	newsk->sk_flags = sk->sk_flags;
938150a5ffb1SMarcelo Ricardo Leitner 	newsk->sk_tsflags = sk->sk_tsflags;
938228448b80STom Herbert 	newsk->sk_no_check_tx = sk->sk_no_check_tx;
938328448b80STom Herbert 	newsk->sk_no_check_rx = sk->sk_no_check_rx;
9384914e1c8bSVlad Yasevich 	newsk->sk_reuse = sk->sk_reuse;
9385b0e9a2feSXin Long 	sctp_sk(newsk)->reuse = sp->reuse;
9386914e1c8bSVlad Yasevich 
9387914e1c8bSVlad Yasevich 	newsk->sk_shutdown = sk->sk_shutdown;
93880a2fbac1SDaniel Borkmann 	newsk->sk_destruct = sctp_destruct_sock;
9389914e1c8bSVlad Yasevich 	newsk->sk_family = sk->sk_family;
9390914e1c8bSVlad Yasevich 	newsk->sk_protocol = IPPROTO_SCTP;
9391914e1c8bSVlad Yasevich 	newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
9392914e1c8bSVlad Yasevich 	newsk->sk_sndbuf = sk->sk_sndbuf;
9393914e1c8bSVlad Yasevich 	newsk->sk_rcvbuf = sk->sk_rcvbuf;
9394914e1c8bSVlad Yasevich 	newsk->sk_lingertime = sk->sk_lingertime;
9395914e1c8bSVlad Yasevich 	newsk->sk_rcvtimeo = sk->sk_rcvtimeo;
9396914e1c8bSVlad Yasevich 	newsk->sk_sndtimeo = sk->sk_sndtimeo;
9397486bdee0SMarcelo Ricardo Leitner 	newsk->sk_rxhash = sk->sk_rxhash;
9398914e1c8bSVlad Yasevich 
9399914e1c8bSVlad Yasevich 	newinet = inet_sk(newsk);
9400914e1c8bSVlad Yasevich 
9401914e1c8bSVlad Yasevich 	/* Initialize sk's sport, dport, rcv_saddr and daddr for
9402914e1c8bSVlad Yasevich 	 * getsockname() and getpeername()
9403914e1c8bSVlad Yasevich 	 */
9404c720c7e8SEric Dumazet 	newinet->inet_sport = inet->inet_sport;
9405c720c7e8SEric Dumazet 	newinet->inet_saddr = inet->inet_saddr;
9406c720c7e8SEric Dumazet 	newinet->inet_rcv_saddr = inet->inet_rcv_saddr;
9407c720c7e8SEric Dumazet 	newinet->inet_dport = htons(asoc->peer.port);
9408914e1c8bSVlad Yasevich 	newinet->pmtudisc = inet->pmtudisc;
9409a904a069SEric Dumazet 	newinet->inet_id = prandom_u32();
9410914e1c8bSVlad Yasevich 
9411914e1c8bSVlad Yasevich 	newinet->uc_ttl = inet->uc_ttl;
9412914e1c8bSVlad Yasevich 	newinet->mc_loop = 1;
9413914e1c8bSVlad Yasevich 	newinet->mc_ttl = 1;
9414914e1c8bSVlad Yasevich 	newinet->mc_index = 0;
9415914e1c8bSVlad Yasevich 	newinet->mc_list = NULL;
941601ce63c9SMarcelo Ricardo Leitner 
941701ce63c9SMarcelo Ricardo Leitner 	if (newsk->sk_flags & SK_FLAGS_TIMESTAMP)
941801ce63c9SMarcelo Ricardo Leitner 		net_enable_timestamp();
94193538a5c8SMarcelo Ricardo Leitner 
94202277c7cdSRichard Haines 	/* Set newsk security attributes from orginal sk and connection
94212277c7cdSRichard Haines 	 * security attribute from ep.
94222277c7cdSRichard Haines 	 */
94232277c7cdSRichard Haines 	security_sctp_sk_clone(ep, sk, newsk);
9424914e1c8bSVlad Yasevich }
9425914e1c8bSVlad Yasevich 
94262d45a02dSMarcelo Ricardo Leitner static inline void sctp_copy_descendant(struct sock *sk_to,
94272d45a02dSMarcelo Ricardo Leitner 					const struct sock *sk_from)
94282d45a02dSMarcelo Ricardo Leitner {
94292d45a02dSMarcelo Ricardo Leitner 	int ancestor_size = sizeof(struct inet_sock) +
94302d45a02dSMarcelo Ricardo Leitner 			    sizeof(struct sctp_sock) -
9431636d25d5SXin Long 			    offsetof(struct sctp_sock, pd_lobby);
94322d45a02dSMarcelo Ricardo Leitner 
94332d45a02dSMarcelo Ricardo Leitner 	if (sk_from->sk_family == PF_INET6)
94342d45a02dSMarcelo Ricardo Leitner 		ancestor_size += sizeof(struct ipv6_pinfo);
94352d45a02dSMarcelo Ricardo Leitner 
94362d45a02dSMarcelo Ricardo Leitner 	__inet_sk_copy_descendant(sk_to, sk_from, ancestor_size);
94372d45a02dSMarcelo Ricardo Leitner }
94382d45a02dSMarcelo Ricardo Leitner 
94391da177e4SLinus Torvalds /* Populate the fields of the newsk from the oldsk and migrate the assoc
94401da177e4SLinus Torvalds  * and its messages to the newsk.
94411da177e4SLinus Torvalds  */
944289664c62SXin Long static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
94431da177e4SLinus Torvalds 			     struct sctp_association *assoc,
9444b7ef2618SXin Long 			     enum sctp_socket_type type)
94451da177e4SLinus Torvalds {
94461da177e4SLinus Torvalds 	struct sctp_sock *oldsp = sctp_sk(oldsk);
94471da177e4SLinus Torvalds 	struct sctp_sock *newsp = sctp_sk(newsk);
94481da177e4SLinus Torvalds 	struct sctp_bind_bucket *pp; /* hash list port iterator */
94491da177e4SLinus Torvalds 	struct sctp_endpoint *newep = newsp->ep;
94501da177e4SLinus Torvalds 	struct sk_buff *skb, *tmp;
94511da177e4SLinus Torvalds 	struct sctp_ulpevent *event;
9452f26f7c48SVlad Yasevich 	struct sctp_bind_hashbucket *head;
945389664c62SXin Long 	int err;
94541da177e4SLinus Torvalds 
94551da177e4SLinus Torvalds 	/* Migrate socket buffer sizes and all the socket level options to the
94561da177e4SLinus Torvalds 	 * new socket.
94571da177e4SLinus Torvalds 	 */
94581da177e4SLinus Torvalds 	newsk->sk_sndbuf = oldsk->sk_sndbuf;
94591da177e4SLinus Torvalds 	newsk->sk_rcvbuf = oldsk->sk_rcvbuf;
94601da177e4SLinus Torvalds 	/* Brute force copy old sctp opt. */
94612d45a02dSMarcelo Ricardo Leitner 	sctp_copy_descendant(newsk, oldsk);
94621da177e4SLinus Torvalds 
94631da177e4SLinus Torvalds 	/* Restore the ep value that was overwritten with the above structure
94641da177e4SLinus Torvalds 	 * copy.
94651da177e4SLinus Torvalds 	 */
94661da177e4SLinus Torvalds 	newsp->ep = newep;
94671da177e4SLinus Torvalds 	newsp->hmac = NULL;
94681da177e4SLinus Torvalds 
94691da177e4SLinus Torvalds 	/* Hook this new socket in to the bind_hash list. */
9470f1f43763SEric W. Biederman 	head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk),
9471f1f43763SEric W. Biederman 						 inet_sk(oldsk)->inet_num)];
9472489ce5f4SNicholas Mc Guire 	spin_lock_bh(&head->lock);
94731da177e4SLinus Torvalds 	pp = sctp_sk(oldsk)->bind_hash;
94741da177e4SLinus Torvalds 	sk_add_bind_node(newsk, &pp->owner);
94751da177e4SLinus Torvalds 	sctp_sk(newsk)->bind_hash = pp;
9476c720c7e8SEric Dumazet 	inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num;
9477489ce5f4SNicholas Mc Guire 	spin_unlock_bh(&head->lock);
94781da177e4SLinus Torvalds 
94794243cac1SVladislav Yasevich 	/* Copy the bind_addr list from the original endpoint to the new
94804243cac1SVladislav Yasevich 	 * endpoint so that we can handle restarts properly
94814243cac1SVladislav Yasevich 	 */
948289664c62SXin Long 	err = sctp_bind_addr_dup(&newsp->ep->base.bind_addr,
94838e71a11cSVlad Yasevich 				 &oldsp->ep->base.bind_addr, GFP_KERNEL);
948489664c62SXin Long 	if (err)
948589664c62SXin Long 		return err;
94864243cac1SVladislav Yasevich 
9487c6f33e05SXin Long 	/* New ep's auth_hmacs should be set if old ep's is set, in case
9488c6f33e05SXin Long 	 * that net->sctp.auth_enable has been changed to 0 by users and
9489c6f33e05SXin Long 	 * new ep's auth_hmacs couldn't be set in sctp_endpoint_init().
9490c6f33e05SXin Long 	 */
9491c6f33e05SXin Long 	if (oldsp->ep->auth_hmacs) {
9492c6f33e05SXin Long 		err = sctp_auth_init_hmacs(newsp->ep, GFP_KERNEL);
9493c6f33e05SXin Long 		if (err)
9494c6f33e05SXin Long 			return err;
9495c6f33e05SXin Long 	}
9496c6f33e05SXin Long 
94971da177e4SLinus Torvalds 	/* Move any messages in the old socket's receive queue that are for the
94981da177e4SLinus Torvalds 	 * peeled off association to the new socket's receive queue.
94991da177e4SLinus Torvalds 	 */
95001da177e4SLinus Torvalds 	sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
95011da177e4SLinus Torvalds 		event = sctp_skb2event(skb);
95021da177e4SLinus Torvalds 		if (event->asoc == assoc) {
95038728b834SDavid S. Miller 			__skb_unlink(skb, &oldsk->sk_receive_queue);
95041da177e4SLinus Torvalds 			__skb_queue_tail(&newsk->sk_receive_queue, skb);
9505ea2bc483STsutomu Fujii 			sctp_skb_set_owner_r_frag(skb, newsk);
95061da177e4SLinus Torvalds 		}
95071da177e4SLinus Torvalds 	}
95081da177e4SLinus Torvalds 
95091da177e4SLinus Torvalds 	/* Clean up any messages pending delivery due to partial
95101da177e4SLinus Torvalds 	 * delivery.   Three cases:
95111da177e4SLinus Torvalds 	 * 1) No partial deliver;  no work.
95121da177e4SLinus Torvalds 	 * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
95131da177e4SLinus Torvalds 	 * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue.
95141da177e4SLinus Torvalds 	 */
9515b6e1331fSVlad Yasevich 	atomic_set(&sctp_sk(newsk)->pd_mode, assoc->ulpq.pd_mode);
95161da177e4SLinus Torvalds 
9517b6e1331fSVlad Yasevich 	if (atomic_read(&sctp_sk(oldsk)->pd_mode)) {
95181da177e4SLinus Torvalds 		struct sk_buff_head *queue;
95191da177e4SLinus Torvalds 
95201da177e4SLinus Torvalds 		/* Decide which queue to move pd_lobby skbs to. */
95211da177e4SLinus Torvalds 		if (assoc->ulpq.pd_mode) {
95221da177e4SLinus Torvalds 			queue = &newsp->pd_lobby;
95231da177e4SLinus Torvalds 		} else
95241da177e4SLinus Torvalds 			queue = &newsk->sk_receive_queue;
95251da177e4SLinus Torvalds 
95261da177e4SLinus Torvalds 		/* Walk through the pd_lobby, looking for skbs that
95271da177e4SLinus Torvalds 		 * need moved to the new socket.
95281da177e4SLinus Torvalds 		 */
95291da177e4SLinus Torvalds 		sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
95301da177e4SLinus Torvalds 			event = sctp_skb2event(skb);
95311da177e4SLinus Torvalds 			if (event->asoc == assoc) {
95328728b834SDavid S. Miller 				__skb_unlink(skb, &oldsp->pd_lobby);
95331da177e4SLinus Torvalds 				__skb_queue_tail(queue, skb);
9534ea2bc483STsutomu Fujii 				sctp_skb_set_owner_r_frag(skb, newsk);
95351da177e4SLinus Torvalds 			}
95361da177e4SLinus Torvalds 		}
95371da177e4SLinus Torvalds 
95381da177e4SLinus Torvalds 		/* Clear up any skbs waiting for the partial
95391da177e4SLinus Torvalds 		 * delivery to finish.
95401da177e4SLinus Torvalds 		 */
95411da177e4SLinus Torvalds 		if (assoc->ulpq.pd_mode)
9542b6e1331fSVlad Yasevich 			sctp_clear_pd(oldsk, NULL);
95431da177e4SLinus Torvalds 
95441da177e4SLinus Torvalds 	}
95451da177e4SLinus Torvalds 
954613228238SXin Long 	sctp_for_each_rx_skb(assoc, newsk, sctp_skb_set_owner_r_frag);
9547ea2bc483STsutomu Fujii 
95481da177e4SLinus Torvalds 	/* Set the type of socket to indicate that it is peeled off from the
95491da177e4SLinus Torvalds 	 * original UDP-style socket or created with the accept() call on a
95501da177e4SLinus Torvalds 	 * TCP-style socket..
95511da177e4SLinus Torvalds 	 */
95521da177e4SLinus Torvalds 	newsp->type = type;
95531da177e4SLinus Torvalds 
955461c9fed4SVladislav Yasevich 	/* Mark the new socket "in-use" by the user so that any packets
955561c9fed4SVladislav Yasevich 	 * that may arrive on the association after we've moved it are
955661c9fed4SVladislav Yasevich 	 * queued to the backlog.  This prevents a potential race between
955761c9fed4SVladislav Yasevich 	 * backlog processing on the old socket and new-packet processing
955861c9fed4SVladislav Yasevich 	 * on the new socket.
95595131a184SZach Brown 	 *
95605131a184SZach Brown 	 * The caller has just allocated newsk so we can guarantee that other
95615131a184SZach Brown 	 * paths won't try to lock it and then oldsk.
956261c9fed4SVladislav Yasevich 	 */
95635131a184SZach Brown 	lock_sock_nested(newsk, SINGLE_DEPTH_NESTING);
95645c3e82feSQiujun Huang 	sctp_for_each_tx_datachunk(assoc, true, sctp_clear_owner_w);
95651da177e4SLinus Torvalds 	sctp_assoc_migrate(assoc, newsk);
95665c3e82feSQiujun Huang 	sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w);
95671da177e4SLinus Torvalds 
95681da177e4SLinus Torvalds 	/* If the association on the newsk is already closed before accept()
95691da177e4SLinus Torvalds 	 * is called, set RCV_SHUTDOWN flag.
95701da177e4SLinus Torvalds 	 */
9571d46e416cSXin Long 	if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) {
9572cbabf463SYafang Shao 		inet_sk_set_state(newsk, SCTP_SS_CLOSED);
95731da177e4SLinus Torvalds 		newsk->sk_shutdown |= RCV_SHUTDOWN;
9574d46e416cSXin Long 	} else {
9575cbabf463SYafang Shao 		inet_sk_set_state(newsk, SCTP_SS_ESTABLISHED);
9576d46e416cSXin Long 	}
9577d46e416cSXin Long 
9578048ed4b6Swangweidong 	release_sock(newsk);
957989664c62SXin Long 
958089664c62SXin Long 	return 0;
95811da177e4SLinus Torvalds }
95821da177e4SLinus Torvalds 
95834d93df0aSNeil Horman 
95841da177e4SLinus Torvalds /* This proto struct describes the ULP interface for SCTP.  */
95851da177e4SLinus Torvalds struct proto sctp_prot = {
95861da177e4SLinus Torvalds 	.name        =	"SCTP",
95871da177e4SLinus Torvalds 	.owner       =	THIS_MODULE,
95881da177e4SLinus Torvalds 	.close       =	sctp_close,
95891da177e4SLinus Torvalds 	.disconnect  =	sctp_disconnect,
95901da177e4SLinus Torvalds 	.accept      =	sctp_accept,
95911da177e4SLinus Torvalds 	.ioctl       =	sctp_ioctl,
95921da177e4SLinus Torvalds 	.init        =	sctp_init_sock,
95931da177e4SLinus Torvalds 	.destroy     =	sctp_destroy_sock,
95941da177e4SLinus Torvalds 	.shutdown    =	sctp_shutdown,
95951da177e4SLinus Torvalds 	.setsockopt  =	sctp_setsockopt,
95961da177e4SLinus Torvalds 	.getsockopt  =	sctp_getsockopt,
95971da177e4SLinus Torvalds 	.sendmsg     =	sctp_sendmsg,
95981da177e4SLinus Torvalds 	.recvmsg     =	sctp_recvmsg,
95991da177e4SLinus Torvalds 	.bind        =	sctp_bind,
9600c0425a42SChristoph Hellwig 	.bind_add    =  sctp_bind_add,
96011da177e4SLinus Torvalds 	.backlog_rcv =	sctp_backlog_rcv,
96021da177e4SLinus Torvalds 	.hash        =	sctp_hash,
96031da177e4SLinus Torvalds 	.unhash      =	sctp_unhash,
960463dfb793SXin Long 	.no_autobind =	true,
96051da177e4SLinus Torvalds 	.obj_size    =  sizeof(struct sctp_sock),
9606ab9ee8e3SDavid Windsor 	.useroffset  =  offsetof(struct sctp_sock, subscribe),
9607ab9ee8e3SDavid Windsor 	.usersize    =  offsetof(struct sctp_sock, initmsg) -
9608ab9ee8e3SDavid Windsor 				offsetof(struct sctp_sock, subscribe) +
9609ab9ee8e3SDavid Windsor 				sizeof_field(struct sctp_sock, initmsg),
96104d93df0aSNeil Horman 	.sysctl_mem  =  sysctl_sctp_mem,
96114d93df0aSNeil Horman 	.sysctl_rmem =  sysctl_sctp_rmem,
96124d93df0aSNeil Horman 	.sysctl_wmem =  sysctl_sctp_wmem,
96134d93df0aSNeil Horman 	.memory_pressure = &sctp_memory_pressure,
96144d93df0aSNeil Horman 	.enter_memory_pressure = sctp_enter_memory_pressure,
96154d93df0aSNeil Horman 	.memory_allocated = &sctp_memory_allocated,
96165f31886fSPavel Emelyanov 	.sockets_allocated = &sctp_sockets_allocated,
96171da177e4SLinus Torvalds };
96181da177e4SLinus Torvalds 
9619dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
96208295b6d9SEric Dumazet 
9621602dd62dSEric Dumazet #include <net/transp_v6.h>
9622602dd62dSEric Dumazet static void sctp_v6_destroy_sock(struct sock *sk)
9623602dd62dSEric Dumazet {
9624602dd62dSEric Dumazet 	sctp_destroy_sock(sk);
9625602dd62dSEric Dumazet 	inet6_destroy_sock(sk);
9626602dd62dSEric Dumazet }
9627602dd62dSEric Dumazet 
96281da177e4SLinus Torvalds struct proto sctpv6_prot = {
96291da177e4SLinus Torvalds 	.name		= "SCTPv6",
96301da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
96311da177e4SLinus Torvalds 	.close		= sctp_close,
96321da177e4SLinus Torvalds 	.disconnect	= sctp_disconnect,
96331da177e4SLinus Torvalds 	.accept		= sctp_accept,
96341da177e4SLinus Torvalds 	.ioctl		= sctp_ioctl,
96351da177e4SLinus Torvalds 	.init		= sctp_init_sock,
9636602dd62dSEric Dumazet 	.destroy	= sctp_v6_destroy_sock,
96371da177e4SLinus Torvalds 	.shutdown	= sctp_shutdown,
96381da177e4SLinus Torvalds 	.setsockopt	= sctp_setsockopt,
96391da177e4SLinus Torvalds 	.getsockopt	= sctp_getsockopt,
96401da177e4SLinus Torvalds 	.sendmsg	= sctp_sendmsg,
96411da177e4SLinus Torvalds 	.recvmsg	= sctp_recvmsg,
96421da177e4SLinus Torvalds 	.bind		= sctp_bind,
9643c0425a42SChristoph Hellwig 	.bind_add	= sctp_bind_add,
96441da177e4SLinus Torvalds 	.backlog_rcv	= sctp_backlog_rcv,
96451da177e4SLinus Torvalds 	.hash		= sctp_hash,
96461da177e4SLinus Torvalds 	.unhash		= sctp_unhash,
964763dfb793SXin Long 	.no_autobind	= true,
96481da177e4SLinus Torvalds 	.obj_size	= sizeof(struct sctp6_sock),
9649ab9ee8e3SDavid Windsor 	.useroffset	= offsetof(struct sctp6_sock, sctp.subscribe),
9650ab9ee8e3SDavid Windsor 	.usersize	= offsetof(struct sctp6_sock, sctp.initmsg) -
9651ab9ee8e3SDavid Windsor 				offsetof(struct sctp6_sock, sctp.subscribe) +
9652ab9ee8e3SDavid Windsor 				sizeof_field(struct sctp6_sock, sctp.initmsg),
96534d93df0aSNeil Horman 	.sysctl_mem	= sysctl_sctp_mem,
96544d93df0aSNeil Horman 	.sysctl_rmem	= sysctl_sctp_rmem,
96554d93df0aSNeil Horman 	.sysctl_wmem	= sysctl_sctp_wmem,
96564d93df0aSNeil Horman 	.memory_pressure = &sctp_memory_pressure,
96574d93df0aSNeil Horman 	.enter_memory_pressure = sctp_enter_memory_pressure,
96584d93df0aSNeil Horman 	.memory_allocated = &sctp_memory_allocated,
96595f31886fSPavel Emelyanov 	.sockets_allocated = &sctp_sockets_allocated,
96601da177e4SLinus Torvalds };
9661dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */
9662