summaryrefslogtreecommitdiff
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-08-06 06:13:21 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2020-08-06 06:13:21 +0300
commit47ec5303d73ea344e84f46660fff693c57641386 (patch)
treea2252debab749de29620c43285295d60c4741119 /net/sctp/socket.c
parent8186749621ed6b8fc42644c399e8c755a2b6f630 (diff)
parentc1055b76ad00aed0e8b79417080f212d736246b6 (diff)
downloadlinux-47ec5303d73ea344e84f46660fff693c57641386.tar.xz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from David Miller: 1) Support 6Ghz band in ath11k driver, from Rajkumar Manoharan. 2) Support UDP segmentation in code TSO code, from Eric Dumazet. 3) Allow flashing different flash images in cxgb4 driver, from Vishal Kulkarni. 4) Add drop frames counter and flow status to tc flower offloading, from Po Liu. 5) Support n-tuple filters in cxgb4, from Vishal Kulkarni. 6) Various new indirect call avoidance, from Eric Dumazet and Brian Vazquez. 7) Fix BPF verifier failures on 32-bit pointer arithmetic, from Yonghong Song. 8) Support querying and setting hardware address of a port function via devlink, use this in mlx5, from Parav Pandit. 9) Support hw ipsec offload on bonding slaves, from Jarod Wilson. 10) Switch qca8k driver over to phylink, from Jonathan McDowell. 11) In bpftool, show list of processes holding BPF FD references to maps, programs, links, and btf objects. From Andrii Nakryiko. 12) Several conversions over to generic power management, from Vaibhav Gupta. 13) Add support for SO_KEEPALIVE et al. to bpf_setsockopt(), from Dmitry Yakunin. 14) Various https url conversions, from Alexander A. Klimov. 15) Timestamping and PHC support for mscc PHY driver, from Antoine Tenart. 16) Support bpf iterating over tcp and udp sockets, from Yonghong Song. 17) Support 5GBASE-T i40e NICs, from Aleksandr Loktionov. 18) Add kTLS RX HW offload support to mlx5e, from Tariq Toukan. 19) Fix the ->ndo_start_xmit() return type to be netdev_tx_t in several drivers. From Luc Van Oostenryck. 20) XDP support for xen-netfront, from Denis Kirjanov. 21) Support receive buffer autotuning in MPTCP, from Florian Westphal. 22) Support EF100 chip in sfc driver, from Edward Cree. 23) Add XDP support to mvpp2 driver, from Matteo Croce. 24) Support MPTCP in sock_diag, from Paolo Abeni. 25) Commonize UDP tunnel offloading code by creating udp_tunnel_nic infrastructure, from Jakub Kicinski. 26) Several pci_ --> dma_ API conversions, from Christophe JAILLET. 27) Add FLOW_ACTION_POLICE support to mlxsw, from Ido Schimmel. 28) Add SK_LOOKUP bpf program type, from Jakub Sitnicki. 29) Refactor a lot of networking socket option handling code in order to avoid set_fs() calls, from Christoph Hellwig. 30) Add rfc4884 support to icmp code, from Willem de Bruijn. 31) Support TBF offload in dpaa2-eth driver, from Ioana Ciornei. 32) Support XDP_REDIRECT in qede driver, from Alexander Lobakin. 33) Support PCI relaxed ordering in mlx5 driver, from Aya Levin. 34) Support TCP syncookies in MPTCP, from Flowian Westphal. 35) Fix several tricky cases of PMTU handling wrt. briding, from Stefano Brivio. * git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (2056 commits) net: thunderx: initialize VF's mailbox mutex before first usage usb: hso: remove bogus check for EINPROGRESS usb: hso: no complaint about kmalloc failure hso: fix bailout in error case of probe ip_tunnel_core: Fix build for archs without _HAVE_ARCH_IPV6_CSUM selftests/net: relax cpu affinity requirement in msg_zerocopy test mptcp: be careful on subflow creation selftests: rtnetlink: make kci_test_encap() return sub-test result selftests: rtnetlink: correct the final return value for the test net: dsa: sja1105: use detected device id instead of DT one on mismatch tipc: set ub->ifindex for local ipv6 address ipv6: add ipv6_dev_find() net: openvswitch: silence suspicious RCU usage warning Revert "vxlan: fix tos value before xmit" ptp: only allow phase values lower than 1 period farsync: switch from 'pci_' to 'dma_' API wan: wanxl: switch from 'pci_' to 'dma_' API hv_netvsc: do not use VF device if link is down dpaa2-eth: Fix passing zero to 'PTR_ERR' warning net: macb: Properly handle phylink on at91sam9x ...
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r--net/sctp/socket.c1239
1 files changed, 501 insertions, 738 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index d57e1a002ffc..ec1fba1fbe71 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -979,9 +979,8 @@ int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw)
*
* Returns 0 if ok, <0 errno code on error.
*/
-static int sctp_setsockopt_bindx_kernel(struct sock *sk,
- struct sockaddr *addrs, int addrs_size,
- int op)
+static int sctp_setsockopt_bindx(struct sock *sk, struct sockaddr *addrs,
+ int addrs_size, int op)
{
int err;
int addrcnt = 0;
@@ -991,7 +990,7 @@ static int sctp_setsockopt_bindx_kernel(struct sock *sk,
struct sctp_af *af;
pr_debug("%s: sk:%p addrs:%p addrs_size:%d opt:%d\n",
- __func__, sk, addrs, addrs_size, op);
+ __func__, sk, addr_buf, addrs_size, op);
if (unlikely(addrs_size <= 0))
return -EINVAL;
@@ -1037,29 +1036,13 @@ static int sctp_setsockopt_bindx_kernel(struct sock *sk,
}
}
-static int sctp_setsockopt_bindx(struct sock *sk,
- struct sockaddr __user *addrs,
- int addrs_size, int op)
-{
- struct sockaddr *kaddrs;
- int err;
-
- kaddrs = memdup_user(addrs, addrs_size);
- if (IS_ERR(kaddrs))
- return PTR_ERR(kaddrs);
- err = sctp_setsockopt_bindx_kernel(sk, kaddrs, addrs_size, op);
- kfree(kaddrs);
- return err;
-}
-
static int sctp_bind_add(struct sock *sk, struct sockaddr *addrs,
int addrlen)
{
int err;
lock_sock(sk);
- err = sctp_setsockopt_bindx_kernel(sk, addrs, addrlen,
- SCTP_BINDX_ADD_ADDR);
+ err = sctp_setsockopt_bindx(sk, addrs, addrlen, SCTP_BINDX_ADD_ADDR);
release_sock(sk);
return err;
}
@@ -1303,36 +1286,29 @@ out_free:
* it.
*
* sk The sk of the socket
- * addrs The pointer to the addresses in user land
+ * addrs The pointer to the addresses
* addrssize Size of the addrs buffer
*
* Returns >=0 if ok, <0 errno code on error.
*/
-static int __sctp_setsockopt_connectx(struct sock *sk,
- struct sockaddr __user *addrs,
- int addrs_size,
- sctp_assoc_t *assoc_id)
+static int __sctp_setsockopt_connectx(struct sock *sk, struct sockaddr *kaddrs,
+ int addrs_size, sctp_assoc_t *assoc_id)
{
- struct sockaddr *kaddrs;
int err = 0, flags = 0;
pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
- __func__, sk, addrs, addrs_size);
+ __func__, sk, kaddrs, addrs_size);
/* make sure the 1st addr's sa_family is accessible later */
if (unlikely(addrs_size < sizeof(sa_family_t)))
return -EINVAL;
- kaddrs = memdup_user(addrs, addrs_size);
- if (IS_ERR(kaddrs))
- return PTR_ERR(kaddrs);
-
/* Allow security module to validate connectx addresses. */
err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX,
(struct sockaddr *)kaddrs,
addrs_size);
if (err)
- goto out_free;
+ return err;
/* in-kernel sockets don't generally have a file allocated to them
* if all they do is call sock_create_kern().
@@ -1340,12 +1316,7 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
if (sk->sk_socket->file)
flags = sk->sk_socket->file->f_flags;
- err = __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
-
-out_free:
- kfree(kaddrs);
-
- return err;
+ return __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
}
/*
@@ -1353,10 +1324,10 @@ out_free:
* to the option that doesn't provide association id.
*/
static int sctp_setsockopt_connectx_old(struct sock *sk,
- struct sockaddr __user *addrs,
+ struct sockaddr *kaddrs,
int addrs_size)
{
- return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL);
+ return __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, NULL);
}
/*
@@ -1366,13 +1337,13 @@ static int sctp_setsockopt_connectx_old(struct sock *sk,
* always positive.
*/
static int sctp_setsockopt_connectx(struct sock *sk,
- struct sockaddr __user *addrs,
+ struct sockaddr *kaddrs,
int addrs_size)
{
sctp_assoc_t assoc_id = 0;
int err = 0;
- err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id);
+ err = __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, &assoc_id);
if (err)
return err;
@@ -1402,6 +1373,7 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len,
{
struct sctp_getaddrs_old param;
sctp_assoc_t assoc_id = 0;
+ struct sockaddr *kaddrs;
int err = 0;
#ifdef CONFIG_COMPAT
@@ -1425,9 +1397,12 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len,
return -EFAULT;
}
- err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *)
- param.addrs, param.addr_num,
- &assoc_id);
+ kaddrs = memdup_user(param.addrs, param.addr_num);
+ if (IS_ERR(kaddrs))
+ return PTR_ERR(kaddrs);
+
+ err = __sctp_setsockopt_connectx(sk, kaddrs, param.addr_num, &assoc_id);
+ kfree(kaddrs);
if (err == 0 || err == -EINPROGRESS) {
if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
return -EFAULT;
@@ -2209,28 +2184,18 @@ out:
* exceeds the current PMTU size, the message will NOT be sent and
* instead a error will be indicated to the user.
*/
-static int sctp_setsockopt_disable_fragments(struct sock *sk,
- char __user *optval,
+static int sctp_setsockopt_disable_fragments(struct sock *sk, int *val,
unsigned int optlen)
{
- int val;
-
if (optlen < sizeof(int))
return -EINVAL;
-
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
-
- sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1;
-
+ sctp_sk(sk)->disable_fragments = (*val == 0) ? 0 : 1;
return 0;
}
-static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_events(struct sock *sk, __u8 *sn_type,
unsigned int optlen)
{
- struct sctp_event_subscribe subscribe;
- __u8 *sn_type = (__u8 *)&subscribe;
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
int i;
@@ -2238,9 +2203,6 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
if (optlen > sizeof(struct sctp_event_subscribe))
return -EINVAL;
- if (copy_from_user(&subscribe, optval, optlen))
- return -EFAULT;
-
for (i = 0; i < optlen; i++)
sctp_ulpevent_type_set(&sp->subscribe, SCTP_SN_TYPE_BASE + i,
sn_type[i]);
@@ -2280,7 +2242,7 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
* integer defining the number of seconds of idle time before an
* association is closed.
*/
-static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_autoclose(struct sock *sk, u32 *optval,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
@@ -2291,9 +2253,8 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
return -EOPNOTSUPP;
if (optlen != sizeof(int))
return -EINVAL;
- if (copy_from_user(&sp->autoclose, optval, optlen))
- return -EFAULT;
+ sp->autoclose = *optval;
if (sp->autoclose > net->sctp.max_autoclose)
sp->autoclose = net->sctp.max_autoclose;
@@ -2628,48 +2589,42 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
}
static int sctp_setsockopt_peer_addr_params(struct sock *sk,
- char __user *optval,
+ struct sctp_paddrparams *params,
unsigned int optlen)
{
- struct sctp_paddrparams params;
struct sctp_transport *trans = NULL;
struct sctp_association *asoc = NULL;
struct sctp_sock *sp = sctp_sk(sk);
int error;
int hb_change, pmtud_change, sackdelay_change;
- if (optlen == sizeof(params)) {
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
- } else if (optlen == ALIGN(offsetof(struct sctp_paddrparams,
+ if (optlen == ALIGN(offsetof(struct sctp_paddrparams,
spp_ipv6_flowlabel), 4)) {
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
- if (params.spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL))
+ if (params->spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL))
return -EINVAL;
- } else {
+ } else if (optlen != sizeof(*params)) {
return -EINVAL;
}
/* Validate flags and value parameters. */
- hb_change = params.spp_flags & SPP_HB;
- pmtud_change = params.spp_flags & SPP_PMTUD;
- sackdelay_change = params.spp_flags & SPP_SACKDELAY;
+ hb_change = params->spp_flags & SPP_HB;
+ pmtud_change = params->spp_flags & SPP_PMTUD;
+ sackdelay_change = params->spp_flags & SPP_SACKDELAY;
if (hb_change == SPP_HB ||
pmtud_change == SPP_PMTUD ||
sackdelay_change == SPP_SACKDELAY ||
- params.spp_sackdelay > 500 ||
- (params.spp_pathmtu &&
- params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
+ params->spp_sackdelay > 500 ||
+ (params->spp_pathmtu &&
+ params->spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
return -EINVAL;
/* If an address other than INADDR_ANY is specified, and
* no transport is found, then the request is invalid.
*/
- if (!sctp_is_any(sk, (union sctp_addr *)&params.spp_address)) {
- trans = sctp_addr_id2transport(sk, &params.spp_address,
- params.spp_assoc_id);
+ if (!sctp_is_any(sk, (union sctp_addr *)&params->spp_address)) {
+ trans = sctp_addr_id2transport(sk, &params->spp_address,
+ params->spp_assoc_id);
if (!trans)
return -EINVAL;
}
@@ -2678,19 +2633,19 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
* socket is a one to many style socket, and an association
* was not found, then the id was invalid.
*/
- asoc = sctp_id2assoc(sk, params.spp_assoc_id);
- if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->spp_assoc_id);
+ if (!asoc && params->spp_assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
/* Heartbeat demand can only be sent on a transport or
* association, but not a socket.
*/
- if (params.spp_flags & SPP_HB_DEMAND && !trans && !asoc)
+ if (params->spp_flags & SPP_HB_DEMAND && !trans && !asoc)
return -EINVAL;
/* Process parameters. */
- error = sctp_apply_peer_addr_params(&params, trans, asoc, sp,
+ error = sctp_apply_peer_addr_params(params, trans, asoc, sp,
hb_change, pmtud_change,
sackdelay_change);
@@ -2703,7 +2658,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
if (!trans && asoc) {
list_for_each_entry(trans, &asoc->peer.transport_addr_list,
transports) {
- sctp_apply_peer_addr_params(&params, trans, asoc, sp,
+ sctp_apply_peer_addr_params(params, trans, asoc, sp,
hb_change, pmtud_change,
sackdelay_change);
}
@@ -2794,83 +2749,86 @@ static void sctp_apply_asoc_delayed_ack(struct sctp_sack_info *params,
* timer to expire. The default value for this is 2, setting this
* value to 1 will disable the delayed sack algorithm.
*/
-
-static int sctp_setsockopt_delayed_ack(struct sock *sk,
- char __user *optval, unsigned int optlen)
+static int __sctp_setsockopt_delayed_ack(struct sock *sk,
+ struct sctp_sack_info *params)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
- struct sctp_sack_info params;
-
- if (optlen == sizeof(struct sctp_sack_info)) {
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
-
- if (params.sack_delay == 0 && params.sack_freq == 0)
- return 0;
- } else if (optlen == sizeof(struct sctp_assoc_value)) {
- pr_warn_ratelimited(DEPRECATED
- "%s (pid %d) "
- "Use of struct sctp_assoc_value in delayed_ack socket option.\n"
- "Use struct sctp_sack_info instead\n",
- current->comm, task_pid_nr(current));
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
-
- if (params.sack_delay == 0)
- params.sack_freq = 1;
- else
- params.sack_freq = 0;
- } else
- return -EINVAL;
/* Validate value parameter. */
- if (params.sack_delay > 500)
+ if (params->sack_delay > 500)
return -EINVAL;
/* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the
* socket is a one to many style socket, and an association
* was not found, then the id was invalid.
*/
- asoc = sctp_id2assoc(sk, params.sack_assoc_id);
- if (!asoc && params.sack_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->sack_assoc_id);
+ if (!asoc && params->sack_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
- sctp_apply_asoc_delayed_ack(&params, asoc);
+ sctp_apply_asoc_delayed_ack(params, asoc);
return 0;
}
if (sctp_style(sk, TCP))
- params.sack_assoc_id = SCTP_FUTURE_ASSOC;
+ params->sack_assoc_id = SCTP_FUTURE_ASSOC;
- if (params.sack_assoc_id == SCTP_FUTURE_ASSOC ||
- params.sack_assoc_id == SCTP_ALL_ASSOC) {
- if (params.sack_delay) {
- sp->sackdelay = params.sack_delay;
+ if (params->sack_assoc_id == SCTP_FUTURE_ASSOC ||
+ params->sack_assoc_id == SCTP_ALL_ASSOC) {
+ if (params->sack_delay) {
+ sp->sackdelay = params->sack_delay;
sp->param_flags =
sctp_spp_sackdelay_enable(sp->param_flags);
}
- if (params.sack_freq == 1) {
+ if (params->sack_freq == 1) {
sp->param_flags =
sctp_spp_sackdelay_disable(sp->param_flags);
- } else if (params.sack_freq > 1) {
- sp->sackfreq = params.sack_freq;
+ } else if (params->sack_freq > 1) {
+ sp->sackfreq = params->sack_freq;
sp->param_flags =
sctp_spp_sackdelay_enable(sp->param_flags);
}
}
- if (params.sack_assoc_id == SCTP_CURRENT_ASSOC ||
- params.sack_assoc_id == SCTP_ALL_ASSOC)
+ if (params->sack_assoc_id == SCTP_CURRENT_ASSOC ||
+ params->sack_assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &sp->ep->asocs, asocs)
- sctp_apply_asoc_delayed_ack(&params, asoc);
+ sctp_apply_asoc_delayed_ack(params, asoc);
return 0;
}
+static int sctp_setsockopt_delayed_ack(struct sock *sk,
+ struct sctp_sack_info *params,
+ unsigned int optlen)
+{
+ if (optlen == sizeof(struct sctp_assoc_value)) {
+ struct sctp_assoc_value *v = (struct sctp_assoc_value *)params;
+ struct sctp_sack_info p;
+
+ pr_warn_ratelimited(DEPRECATED
+ "%s (pid %d) "
+ "Use of struct sctp_assoc_value in delayed_ack socket option.\n"
+ "Use struct sctp_sack_info instead\n",
+ current->comm, task_pid_nr(current));
+
+ p.sack_assoc_id = v->assoc_id;
+ p.sack_delay = v->assoc_value;
+ p.sack_freq = v->assoc_value ? 0 : 1;
+ return __sctp_setsockopt_delayed_ack(sk, &p);
+ }
+
+ if (optlen != sizeof(struct sctp_sack_info))
+ return -EINVAL;
+ if (params->sack_delay == 0 && params->sack_freq == 0)
+ return 0;
+ return __sctp_setsockopt_delayed_ack(sk, params);
+}
+
/* 7.1.3 Initialization Parameters (SCTP_INITMSG)
*
* Applications can specify protocol parameters for the default association
@@ -2882,24 +2840,22 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
* by the change). With TCP-style sockets, this option is inherited by
* sockets derived from a listener socket.
*/
-static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_initmsg(struct sock *sk, struct sctp_initmsg *sinit,
+ unsigned int optlen)
{
- struct sctp_initmsg sinit;
struct sctp_sock *sp = sctp_sk(sk);
if (optlen != sizeof(struct sctp_initmsg))
return -EINVAL;
- if (copy_from_user(&sinit, optval, optlen))
- return -EFAULT;
- if (sinit.sinit_num_ostreams)
- sp->initmsg.sinit_num_ostreams = sinit.sinit_num_ostreams;
- if (sinit.sinit_max_instreams)
- sp->initmsg.sinit_max_instreams = sinit.sinit_max_instreams;
- if (sinit.sinit_max_attempts)
- sp->initmsg.sinit_max_attempts = sinit.sinit_max_attempts;
- if (sinit.sinit_max_init_timeo)
- sp->initmsg.sinit_max_init_timeo = sinit.sinit_max_init_timeo;
+ if (sinit->sinit_num_ostreams)
+ sp->initmsg.sinit_num_ostreams = sinit->sinit_num_ostreams;
+ if (sinit->sinit_max_instreams)
+ sp->initmsg.sinit_max_instreams = sinit->sinit_max_instreams;
+ if (sinit->sinit_max_attempts)
+ sp->initmsg.sinit_max_attempts = sinit->sinit_max_attempts;
+ if (sinit->sinit_max_init_timeo)
+ sp->initmsg.sinit_max_init_timeo = sinit->sinit_max_init_timeo;
return 0;
}
@@ -2919,57 +2875,54 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigne
* to this call if the caller is using the UDP model.
*/
static int sctp_setsockopt_default_send_param(struct sock *sk,
- char __user *optval,
+ struct sctp_sndrcvinfo *info,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
- struct sctp_sndrcvinfo info;
- if (optlen != sizeof(info))
+ if (optlen != sizeof(*info))
return -EINVAL;
- if (copy_from_user(&info, optval, optlen))
- return -EFAULT;
- if (info.sinfo_flags &
+ if (info->sinfo_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF))
return -EINVAL;
- asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
- if (!asoc && info.sinfo_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, info->sinfo_assoc_id);
+ if (!asoc && info->sinfo_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
- asoc->default_stream = info.sinfo_stream;
- asoc->default_flags = info.sinfo_flags;
- asoc->default_ppid = info.sinfo_ppid;
- asoc->default_context = info.sinfo_context;
- asoc->default_timetolive = info.sinfo_timetolive;
+ asoc->default_stream = info->sinfo_stream;
+ asoc->default_flags = info->sinfo_flags;
+ asoc->default_ppid = info->sinfo_ppid;
+ asoc->default_context = info->sinfo_context;
+ asoc->default_timetolive = info->sinfo_timetolive;
return 0;
}
if (sctp_style(sk, TCP))
- info.sinfo_assoc_id = SCTP_FUTURE_ASSOC;
+ info->sinfo_assoc_id = SCTP_FUTURE_ASSOC;
- if (info.sinfo_assoc_id == SCTP_FUTURE_ASSOC ||
- info.sinfo_assoc_id == SCTP_ALL_ASSOC) {
- sp->default_stream = info.sinfo_stream;
- sp->default_flags = info.sinfo_flags;
- sp->default_ppid = info.sinfo_ppid;
- sp->default_context = info.sinfo_context;
- sp->default_timetolive = info.sinfo_timetolive;
+ if (info->sinfo_assoc_id == SCTP_FUTURE_ASSOC ||
+ info->sinfo_assoc_id == SCTP_ALL_ASSOC) {
+ sp->default_stream = info->sinfo_stream;
+ sp->default_flags = info->sinfo_flags;
+ sp->default_ppid = info->sinfo_ppid;
+ sp->default_context = info->sinfo_context;
+ sp->default_timetolive = info->sinfo_timetolive;
}
- if (info.sinfo_assoc_id == SCTP_CURRENT_ASSOC ||
- info.sinfo_assoc_id == SCTP_ALL_ASSOC) {
+ if (info->sinfo_assoc_id == SCTP_CURRENT_ASSOC ||
+ info->sinfo_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
- asoc->default_stream = info.sinfo_stream;
- asoc->default_flags = info.sinfo_flags;
- asoc->default_ppid = info.sinfo_ppid;
- asoc->default_context = info.sinfo_context;
- asoc->default_timetolive = info.sinfo_timetolive;
+ asoc->default_stream = info->sinfo_stream;
+ asoc->default_flags = info->sinfo_flags;
+ asoc->default_ppid = info->sinfo_ppid;
+ asoc->default_context = info->sinfo_context;
+ asoc->default_timetolive = info->sinfo_timetolive;
}
}
@@ -2980,54 +2933,51 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
* (SCTP_DEFAULT_SNDINFO)
*/
static int sctp_setsockopt_default_sndinfo(struct sock *sk,
- char __user *optval,
+ struct sctp_sndinfo *info,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
- struct sctp_sndinfo info;
- if (optlen != sizeof(info))
+ if (optlen != sizeof(*info))
return -EINVAL;
- if (copy_from_user(&info, optval, optlen))
- return -EFAULT;
- if (info.snd_flags &
+ if (info->snd_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF))
return -EINVAL;
- asoc = sctp_id2assoc(sk, info.snd_assoc_id);
- if (!asoc && info.snd_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, info->snd_assoc_id);
+ if (!asoc && info->snd_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
- asoc->default_stream = info.snd_sid;
- asoc->default_flags = info.snd_flags;
- asoc->default_ppid = info.snd_ppid;
- asoc->default_context = info.snd_context;
+ asoc->default_stream = info->snd_sid;
+ asoc->default_flags = info->snd_flags;
+ asoc->default_ppid = info->snd_ppid;
+ asoc->default_context = info->snd_context;
return 0;
}
if (sctp_style(sk, TCP))
- info.snd_assoc_id = SCTP_FUTURE_ASSOC;
+ info->snd_assoc_id = SCTP_FUTURE_ASSOC;
- if (info.snd_assoc_id == SCTP_FUTURE_ASSOC ||
- info.snd_assoc_id == SCTP_ALL_ASSOC) {
- sp->default_stream = info.snd_sid;
- sp->default_flags = info.snd_flags;
- sp->default_ppid = info.snd_ppid;
- sp->default_context = info.snd_context;
+ if (info->snd_assoc_id == SCTP_FUTURE_ASSOC ||
+ info->snd_assoc_id == SCTP_ALL_ASSOC) {
+ sp->default_stream = info->snd_sid;
+ sp->default_flags = info->snd_flags;
+ sp->default_ppid = info->snd_ppid;
+ sp->default_context = info->snd_context;
}
- if (info.snd_assoc_id == SCTP_CURRENT_ASSOC ||
- info.snd_assoc_id == SCTP_ALL_ASSOC) {
+ if (info->snd_assoc_id == SCTP_CURRENT_ASSOC ||
+ info->snd_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
- asoc->default_stream = info.snd_sid;
- asoc->default_flags = info.snd_flags;
- asoc->default_ppid = info.snd_ppid;
- asoc->default_context = info.snd_context;
+ asoc->default_stream = info->snd_sid;
+ asoc->default_flags = info->snd_flags;
+ asoc->default_ppid = info->snd_ppid;
+ asoc->default_context = info->snd_context;
}
}
@@ -3040,10 +2990,9 @@ static int sctp_setsockopt_default_sndinfo(struct sock *sk,
* the association primary. The enclosed address must be one of the
* association peer's addresses.
*/
-static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_primary_addr(struct sock *sk, struct sctp_prim *prim,
unsigned int optlen)
{
- struct sctp_prim prim;
struct sctp_transport *trans;
struct sctp_af *af;
int err;
@@ -3051,21 +3000,18 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
if (optlen != sizeof(struct sctp_prim))
return -EINVAL;
- if (copy_from_user(&prim, optval, sizeof(struct sctp_prim)))
- return -EFAULT;
-
/* Allow security module to validate address but need address len. */
- af = sctp_get_af_specific(prim.ssp_addr.ss_family);
+ af = sctp_get_af_specific(prim->ssp_addr.ss_family);
if (!af)
return -EINVAL;
err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR,
- (struct sockaddr *)&prim.ssp_addr,
+ (struct sockaddr *)&prim->ssp_addr,
af->sockaddr_len);
if (err)
return err;
- trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id);
+ trans = sctp_addr_id2transport(sk, &prim->ssp_addr, prim->ssp_assoc_id);
if (!trans)
return -EINVAL;
@@ -3082,17 +3028,12 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
* introduced, at the cost of more packets in the network. Expects an
* integer boolean flag.
*/
-static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_nodelay(struct sock *sk, int *val,
unsigned int optlen)
{
- int val;
-
if (optlen < sizeof(int))
return -EINVAL;
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
-
- sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1;
+ sctp_sk(sk)->nodelay = (*val == 0) ? 0 : 1;
return 0;
}
@@ -3108,9 +3049,10 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
* be changed.
*
*/
-static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_rtoinfo(struct sock *sk,
+ struct sctp_rtoinfo *rtoinfo,
+ unsigned int optlen)
{
- struct sctp_rtoinfo rtoinfo;
struct sctp_association *asoc;
unsigned long rto_min, rto_max;
struct sctp_sock *sp = sctp_sk(sk);
@@ -3118,18 +3060,15 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne
if (optlen != sizeof (struct sctp_rtoinfo))
return -EINVAL;
- if (copy_from_user(&rtoinfo, optval, optlen))
- return -EFAULT;
-
- asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id);
+ asoc = sctp_id2assoc(sk, rtoinfo->srto_assoc_id);
/* Set the values to the specific association */
- if (!asoc && rtoinfo.srto_assoc_id != SCTP_FUTURE_ASSOC &&
+ if (!asoc && rtoinfo->srto_assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
- rto_max = rtoinfo.srto_max;
- rto_min = rtoinfo.srto_min;
+ rto_max = rtoinfo->srto_max;
+ rto_min = rtoinfo->srto_min;
if (rto_max)
rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max;
@@ -3145,17 +3084,17 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne
return -EINVAL;
if (asoc) {
- if (rtoinfo.srto_initial != 0)
+ if (rtoinfo->srto_initial != 0)
asoc->rto_initial =
- msecs_to_jiffies(rtoinfo.srto_initial);
+ msecs_to_jiffies(rtoinfo->srto_initial);
asoc->rto_max = rto_max;
asoc->rto_min = rto_min;
} else {
/* If there is no association or the association-id = 0
* set the values to the endpoint.
*/
- if (rtoinfo.srto_initial != 0)
- sp->rtoinfo.srto_initial = rtoinfo.srto_initial;
+ if (rtoinfo->srto_initial != 0)
+ sp->rtoinfo.srto_initial = rtoinfo->srto_initial;
sp->rtoinfo.srto_max = rto_max;
sp->rtoinfo.srto_min = rto_min;
}
@@ -3174,26 +3113,25 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne
* See [SCTP] for more information.
*
*/
-static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_associnfo(struct sock *sk,
+ struct sctp_assocparams *assocparams,
+ unsigned int optlen)
{
- struct sctp_assocparams assocparams;
struct sctp_association *asoc;
if (optlen != sizeof(struct sctp_assocparams))
return -EINVAL;
- if (copy_from_user(&assocparams, optval, optlen))
- return -EFAULT;
- asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id);
+ asoc = sctp_id2assoc(sk, assocparams->sasoc_assoc_id);
- if (!asoc && assocparams.sasoc_assoc_id != SCTP_FUTURE_ASSOC &&
+ if (!asoc && assocparams->sasoc_assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
/* Set the values to the specific association */
if (asoc) {
- if (assocparams.sasoc_asocmaxrxt != 0) {
+ if (assocparams->sasoc_asocmaxrxt != 0) {
__u32 path_sum = 0;
int paths = 0;
struct sctp_transport *peer_addr;
@@ -3210,24 +3148,25 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsig
* then one path.
*/
if (paths > 1 &&
- assocparams.sasoc_asocmaxrxt > path_sum)
+ assocparams->sasoc_asocmaxrxt > path_sum)
return -EINVAL;
- asoc->max_retrans = assocparams.sasoc_asocmaxrxt;
+ asoc->max_retrans = assocparams->sasoc_asocmaxrxt;
}
- if (assocparams.sasoc_cookie_life != 0)
- asoc->cookie_life = ms_to_ktime(assocparams.sasoc_cookie_life);
+ if (assocparams->sasoc_cookie_life != 0)
+ asoc->cookie_life =
+ ms_to_ktime(assocparams->sasoc_cookie_life);
} else {
/* Set the values to the endpoint */
struct sctp_sock *sp = sctp_sk(sk);
- if (assocparams.sasoc_asocmaxrxt != 0)
+ if (assocparams->sasoc_asocmaxrxt != 0)
sp->assocparams.sasoc_asocmaxrxt =
- assocparams.sasoc_asocmaxrxt;
- if (assocparams.sasoc_cookie_life != 0)
+ assocparams->sasoc_asocmaxrxt;
+ if (assocparams->sasoc_cookie_life != 0)
sp->assocparams.sasoc_cookie_life =
- assocparams.sasoc_cookie_life;
+ assocparams->sasoc_cookie_life;
}
return 0;
}
@@ -3242,16 +3181,14 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsig
* addresses and a user will receive both PF_INET6 and PF_INET type
* addresses on the socket.
*/
-static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_mappedv4(struct sock *sk, int *val,
+ unsigned int optlen)
{
- int val;
struct sctp_sock *sp = sctp_sk(sk);
if (optlen < sizeof(int))
return -EINVAL;
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
- if (val)
+ if (*val)
sp->v4mapped = 1;
else
sp->v4mapped = 0;
@@ -3286,11 +3223,13 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign
* changed (effecting future associations only).
* assoc_value: This parameter specifies the maximum size in bytes.
*/
-static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_maxseg(struct sock *sk,
+ struct sctp_assoc_value *params,
+ unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
- struct sctp_assoc_value params;
struct sctp_association *asoc;
+ sctp_assoc_t assoc_id;
int val;
if (optlen == sizeof(int)) {
@@ -3299,19 +3238,17 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
"Use of int in maxseg socket option.\n"
"Use struct sctp_assoc_value instead\n",
current->comm, task_pid_nr(current));
- if (copy_from_user(&val, optval, optlen))
- return -EFAULT;
- params.assoc_id = SCTP_FUTURE_ASSOC;
+ assoc_id = SCTP_FUTURE_ASSOC;
+ val = *(int *)params;
} else if (optlen == sizeof(struct sctp_assoc_value)) {
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
- val = params.assoc_value;
+ assoc_id = params->assoc_id;
+ val = params->assoc_value;
} else {
return -EINVAL;
}
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, assoc_id);
+ if (!asoc && assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
@@ -3346,12 +3283,12 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
* locally bound addresses. The following structure is used to make a
* set primary request:
*/
-static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_peer_primary_addr(struct sock *sk,
+ struct sctp_setpeerprim *prim,
unsigned int optlen)
{
struct sctp_sock *sp;
struct sctp_association *asoc = NULL;
- struct sctp_setpeerprim prim;
struct sctp_chunk *chunk;
struct sctp_af *af;
int err;
@@ -3364,10 +3301,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
if (optlen != sizeof(struct sctp_setpeerprim))
return -EINVAL;
- if (copy_from_user(&prim, optval, optlen))
- return -EFAULT;
-
- asoc = sctp_id2assoc(sk, prim.sspp_assoc_id);
+ asoc = sctp_id2assoc(sk, prim->sspp_assoc_id);
if (!asoc)
return -EINVAL;
@@ -3380,26 +3314,26 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
if (!sctp_state(asoc, ESTABLISHED))
return -ENOTCONN;
- af = sctp_get_af_specific(prim.sspp_addr.ss_family);
+ af = sctp_get_af_specific(prim->sspp_addr.ss_family);
if (!af)
return -EINVAL;
- if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL))
+ if (!af->addr_valid((union sctp_addr *)&prim->sspp_addr, sp, NULL))
return -EADDRNOTAVAIL;
- if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))
+ if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim->sspp_addr))
return -EADDRNOTAVAIL;
/* Allow security module to validate address. */
err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR,
- (struct sockaddr *)&prim.sspp_addr,
+ (struct sockaddr *)&prim->sspp_addr,
af->sockaddr_len);
if (err)
return err;
/* Create an ASCONF chunk with SET_PRIMARY parameter */
chunk = sctp_make_asconf_set_prim(asoc,
- (union sctp_addr *)&prim.sspp_addr);
+ (union sctp_addr *)&prim->sspp_addr);
if (!chunk)
return -ENOMEM;
@@ -3410,17 +3344,14 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
return err;
}
-static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_adaptation_layer(struct sock *sk,
+ struct sctp_setadaptation *adapt,
unsigned int optlen)
{
- struct sctp_setadaptation adaptation;
-
if (optlen != sizeof(struct sctp_setadaptation))
return -EINVAL;
- if (copy_from_user(&adaptation, optval, optlen))
- return -EFAULT;
- sctp_sk(sk)->adaptation_ind = adaptation.ssb_adaptation_ind;
+ sctp_sk(sk)->adaptation_ind = adapt->ssb_adaptation_ind;
return 0;
}
@@ -3439,40 +3370,38 @@ static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval
* received messages from the peer and does not effect the value that is
* saved with outbound messages.
*/
-static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_context(struct sock *sk,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
- struct sctp_assoc_value params;
struct sctp_association *asoc;
if (optlen != sizeof(struct sctp_assoc_value))
return -EINVAL;
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
- asoc->default_rcv_context = params.assoc_value;
+ asoc->default_rcv_context = params->assoc_value;
return 0;
}
if (sctp_style(sk, TCP))
- params.assoc_id = SCTP_FUTURE_ASSOC;
+ params->assoc_id = SCTP_FUTURE_ASSOC;
- if (params.assoc_id == SCTP_FUTURE_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC)
- sp->default_rcv_context = params.assoc_value;
+ if (params->assoc_id == SCTP_FUTURE_ASSOC ||
+ params->assoc_id == SCTP_ALL_ASSOC)
+ sp->default_rcv_context = params->assoc_value;
- if (params.assoc_id == SCTP_CURRENT_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC)
+ if (params->assoc_id == SCTP_CURRENT_ASSOC ||
+ params->assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &sp->ep->asocs, asocs)
- asoc->default_rcv_context = params.assoc_value;
+ asoc->default_rcv_context = params->assoc_value;
return 0;
}
@@ -3501,18 +3430,13 @@ static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
* application using the one to many model may become confused and act
* incorrectly.
*/
-static int sctp_setsockopt_fragment_interleave(struct sock *sk,
- char __user *optval,
+static int sctp_setsockopt_fragment_interleave(struct sock *sk, int *val,
unsigned int optlen)
{
- int val;
-
if (optlen != sizeof(int))
return -EINVAL;
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
- sctp_sk(sk)->frag_interleave = !!val;
+ sctp_sk(sk)->frag_interleave = !!*val;
if (!sctp_sk(sk)->frag_interleave)
sctp_sk(sk)->ep->intl_enable = 0;
@@ -3537,24 +3461,19 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk,
* call as long as the user provided buffer is large enough to hold the
* message.
*/
-static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
- char __user *optval,
+static int sctp_setsockopt_partial_delivery_point(struct sock *sk, u32 *val,
unsigned int optlen)
{
- u32 val;
-
if (optlen != sizeof(u32))
return -EINVAL;
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
/* Note: We double the receive buffer from what the user sets
* it to be, also initial rwnd is based on rcvbuf/2.
*/
- if (val > (sk->sk_rcvbuf >> 1))
+ if (*val > (sk->sk_rcvbuf >> 1))
return -EINVAL;
- sctp_sk(sk)->pd_point = val;
+ sctp_sk(sk)->pd_point = *val;
return 0; /* is this the right error code? */
}
@@ -3571,12 +3490,13 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
* future associations inheriting the socket value.
*/
static int sctp_setsockopt_maxburst(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
- struct sctp_assoc_value params;
struct sctp_association *asoc;
+ sctp_assoc_t assoc_id;
+ u32 assoc_value;
if (optlen == sizeof(int)) {
pr_warn_ratelimited(DEPRECATED
@@ -3584,37 +3504,33 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
"Use of int in max_burst socket option deprecated.\n"
"Use struct sctp_assoc_value instead\n",
current->comm, task_pid_nr(current));
- if (copy_from_user(&params.assoc_value, optval, optlen))
- return -EFAULT;
- params.assoc_id = SCTP_FUTURE_ASSOC;
+ assoc_id = SCTP_FUTURE_ASSOC;
+ assoc_value = *((int *)params);
} else if (optlen == sizeof(struct sctp_assoc_value)) {
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
+ assoc_id = params->assoc_id;
+ assoc_value = params->assoc_value;
} else
return -EINVAL;
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id > SCTP_ALL_ASSOC &&
- sctp_style(sk, UDP))
+ asoc = sctp_id2assoc(sk, assoc_id);
+ if (!asoc && assoc_id > SCTP_ALL_ASSOC && sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
- asoc->max_burst = params.assoc_value;
+ asoc->max_burst = assoc_value;
return 0;
}
if (sctp_style(sk, TCP))
- params.assoc_id = SCTP_FUTURE_ASSOC;
+ assoc_id = SCTP_FUTURE_ASSOC;
- if (params.assoc_id == SCTP_FUTURE_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC)
- sp->max_burst = params.assoc_value;
+ if (assoc_id == SCTP_FUTURE_ASSOC || assoc_id == SCTP_ALL_ASSOC)
+ sp->max_burst = assoc_value;
- if (params.assoc_id == SCTP_CURRENT_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC)
+ if (assoc_id == SCTP_CURRENT_ASSOC || assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &sp->ep->asocs, asocs)
- asoc->max_burst = params.assoc_value;
+ asoc->max_burst = assoc_value;
return 0;
}
@@ -3627,21 +3543,18 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
* will only effect future associations on the socket.
*/
static int sctp_setsockopt_auth_chunk(struct sock *sk,
- char __user *optval,
+ struct sctp_authchunk *val,
unsigned int optlen)
{
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
- struct sctp_authchunk val;
if (!ep->auth_enable)
return -EACCES;
if (optlen != sizeof(struct sctp_authchunk))
return -EINVAL;
- if (copy_from_user(&val, optval, optlen))
- return -EFAULT;
- switch (val.sauth_chunk) {
+ switch (val->sauth_chunk) {
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
case SCTP_CID_SHUTDOWN_COMPLETE:
@@ -3650,7 +3563,7 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,
}
/* add this chunk id to the endpoint */
- return sctp_auth_ep_add_chunkid(ep, val.sauth_chunk);
+ return sctp_auth_ep_add_chunkid(ep, val->sauth_chunk);
}
/*
@@ -3660,13 +3573,11 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,
* endpoint requires the peer to use.
*/
static int sctp_setsockopt_hmac_ident(struct sock *sk,
- char __user *optval,
+ struct sctp_hmacalgo *hmacs,
unsigned int optlen)
{
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
- struct sctp_hmacalgo *hmacs;
u32 idents;
- int err;
if (!ep->auth_enable)
return -EACCES;
@@ -3676,21 +3587,12 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) +
SCTP_AUTH_NUM_HMACS * sizeof(u16));
- hmacs = memdup_user(optval, optlen);
- if (IS_ERR(hmacs))
- return PTR_ERR(hmacs);
-
idents = hmacs->shmac_num_idents;
if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS ||
- (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) {
- err = -EINVAL;
- goto out;
- }
+ (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo)))
+ return -EINVAL;
- err = sctp_auth_ep_set_hmacs(ep, hmacs);
-out:
- kfree(hmacs);
- return err;
+ return sctp_auth_ep_set_hmacs(ep, hmacs);
}
/*
@@ -3700,11 +3602,10 @@ out:
* association shared key.
*/
static int sctp_setsockopt_auth_key(struct sock *sk,
- char __user *optval,
+ struct sctp_authkey *authkey,
unsigned int optlen)
{
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
- struct sctp_authkey *authkey;
struct sctp_association *asoc;
int ret = -EINVAL;
@@ -3715,10 +3616,6 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
*/
optlen = min_t(unsigned int, optlen, USHRT_MAX + sizeof(*authkey));
- authkey = memdup_user(optval, optlen);
- if (IS_ERR(authkey))
- return PTR_ERR(authkey);
-
if (authkey->sca_keylength > optlen - sizeof(*authkey))
goto out;
@@ -3755,7 +3652,7 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
}
out:
- kzfree(authkey);
+ memzero_explicit(authkey, optlen);
return ret;
}
@@ -3766,42 +3663,39 @@ out:
* the association shared key.
*/
static int sctp_setsockopt_active_key(struct sock *sk,
- char __user *optval,
+ struct sctp_authkeyid *val,
unsigned int optlen)
{
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_association *asoc;
- struct sctp_authkeyid val;
int ret = 0;
if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL;
- if (copy_from_user(&val, optval, optlen))
- return -EFAULT;
- asoc = sctp_id2assoc(sk, val.scact_assoc_id);
- if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, val->scact_assoc_id);
+ if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc)
- return sctp_auth_set_active_key(ep, asoc, val.scact_keynumber);
+ return sctp_auth_set_active_key(ep, asoc, val->scact_keynumber);
if (sctp_style(sk, TCP))
- val.scact_assoc_id = SCTP_FUTURE_ASSOC;
+ val->scact_assoc_id = SCTP_FUTURE_ASSOC;
- if (val.scact_assoc_id == SCTP_FUTURE_ASSOC ||
- val.scact_assoc_id == SCTP_ALL_ASSOC) {
- ret = sctp_auth_set_active_key(ep, asoc, val.scact_keynumber);
+ if (val->scact_assoc_id == SCTP_FUTURE_ASSOC ||
+ val->scact_assoc_id == SCTP_ALL_ASSOC) {
+ ret = sctp_auth_set_active_key(ep, asoc, val->scact_keynumber);
if (ret)
return ret;
}
- if (val.scact_assoc_id == SCTP_CURRENT_ASSOC ||
- val.scact_assoc_id == SCTP_ALL_ASSOC) {
+ if (val->scact_assoc_id == SCTP_CURRENT_ASSOC ||
+ val->scact_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &ep->asocs, asocs) {
int res = sctp_auth_set_active_key(ep, asoc,
- val.scact_keynumber);
+ val->scact_keynumber);
if (res && !ret)
ret = res;
@@ -3817,42 +3711,39 @@ static int sctp_setsockopt_active_key(struct sock *sk,
* This set option will delete a shared secret key from use.
*/
static int sctp_setsockopt_del_key(struct sock *sk,
- char __user *optval,
+ struct sctp_authkeyid *val,
unsigned int optlen)
{
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_association *asoc;
- struct sctp_authkeyid val;
int ret = 0;
if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL;
- if (copy_from_user(&val, optval, optlen))
- return -EFAULT;
- asoc = sctp_id2assoc(sk, val.scact_assoc_id);
- if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, val->scact_assoc_id);
+ if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc)
- return sctp_auth_del_key_id(ep, asoc, val.scact_keynumber);
+ return sctp_auth_del_key_id(ep, asoc, val->scact_keynumber);
if (sctp_style(sk, TCP))
- val.scact_assoc_id = SCTP_FUTURE_ASSOC;
+ val->scact_assoc_id = SCTP_FUTURE_ASSOC;
- if (val.scact_assoc_id == SCTP_FUTURE_ASSOC ||
- val.scact_assoc_id == SCTP_ALL_ASSOC) {
- ret = sctp_auth_del_key_id(ep, asoc, val.scact_keynumber);
+ if (val->scact_assoc_id == SCTP_FUTURE_ASSOC ||
+ val->scact_assoc_id == SCTP_ALL_ASSOC) {
+ ret = sctp_auth_del_key_id(ep, asoc, val->scact_keynumber);
if (ret)
return ret;
}
- if (val.scact_assoc_id == SCTP_CURRENT_ASSOC ||
- val.scact_assoc_id == SCTP_ALL_ASSOC) {
+ if (val->scact_assoc_id == SCTP_CURRENT_ASSOC ||
+ val->scact_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &ep->asocs, asocs) {
int res = sctp_auth_del_key_id(ep, asoc,
- val.scact_keynumber);
+ val->scact_keynumber);
if (res && !ret)
ret = res;
@@ -3867,42 +3758,40 @@ static int sctp_setsockopt_del_key(struct sock *sk,
*
* This set option will deactivate a shared secret key.
*/
-static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_deactivate_key(struct sock *sk,
+ struct sctp_authkeyid *val,
unsigned int optlen)
{
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_association *asoc;
- struct sctp_authkeyid val;
int ret = 0;
if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL;
- if (copy_from_user(&val, optval, optlen))
- return -EFAULT;
- asoc = sctp_id2assoc(sk, val.scact_assoc_id);
- if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, val->scact_assoc_id);
+ if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc)
- return sctp_auth_deact_key_id(ep, asoc, val.scact_keynumber);
+ return sctp_auth_deact_key_id(ep, asoc, val->scact_keynumber);
if (sctp_style(sk, TCP))
- val.scact_assoc_id = SCTP_FUTURE_ASSOC;
+ val->scact_assoc_id = SCTP_FUTURE_ASSOC;
- if (val.scact_assoc_id == SCTP_FUTURE_ASSOC ||
- val.scact_assoc_id == SCTP_ALL_ASSOC) {
- ret = sctp_auth_deact_key_id(ep, asoc, val.scact_keynumber);
+ if (val->scact_assoc_id == SCTP_FUTURE_ASSOC ||
+ val->scact_assoc_id == SCTP_ALL_ASSOC) {
+ ret = sctp_auth_deact_key_id(ep, asoc, val->scact_keynumber);
if (ret)
return ret;
}
- if (val.scact_assoc_id == SCTP_CURRENT_ASSOC ||
- val.scact_assoc_id == SCTP_ALL_ASSOC) {
+ if (val->scact_assoc_id == SCTP_CURRENT_ASSOC ||
+ val->scact_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &ep->asocs, asocs) {
int res = sctp_auth_deact_key_id(ep, asoc,
- val.scact_keynumber);
+ val->scact_keynumber);
if (res && !ret)
ret = res;
@@ -3926,26 +3815,23 @@ static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval,
* Note. In this implementation, socket operation overrides default parameter
* being set by sysctl as well as FreeBSD implementation
*/
-static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_auto_asconf(struct sock *sk, int *val,
unsigned int optlen)
{
- int val;
struct sctp_sock *sp = sctp_sk(sk);
if (optlen < sizeof(int))
return -EINVAL;
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
- if (!sctp_is_ep_boundall(sk) && val)
+ if (!sctp_is_ep_boundall(sk) && *val)
return -EINVAL;
- if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf))
+ if ((*val && sp->do_auto_asconf) || (!*val && !sp->do_auto_asconf))
return 0;
spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock);
- if (val == 0 && sp->do_auto_asconf) {
+ if (*val == 0 && sp->do_auto_asconf) {
list_del(&sp->auto_asconf_list);
sp->do_auto_asconf = 0;
- } else if (val && !sp->do_auto_asconf) {
+ } else if (*val && !sp->do_auto_asconf) {
list_add_tail(&sp->auto_asconf_list,
&sock_net(sk)->sctp.auto_asconf_splist);
sp->do_auto_asconf = 1;
@@ -3962,176 +3848,154 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
* http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt
*/
static int sctp_setsockopt_paddr_thresholds(struct sock *sk,
- char __user *optval,
+ struct sctp_paddrthlds_v2 *val,
unsigned int optlen, bool v2)
{
- struct sctp_paddrthlds_v2 val;
struct sctp_transport *trans;
struct sctp_association *asoc;
int len;
- len = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds);
+ len = v2 ? sizeof(*val) : sizeof(struct sctp_paddrthlds);
if (optlen < len)
return -EINVAL;
- if (copy_from_user(&val, optval, len))
- return -EFAULT;
- if (v2 && val.spt_pathpfthld > val.spt_pathcpthld)
+ if (v2 && val->spt_pathpfthld > val->spt_pathcpthld)
return -EINVAL;
- if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) {
- trans = sctp_addr_id2transport(sk, &val.spt_address,
- val.spt_assoc_id);
+ if (!sctp_is_any(sk, (const union sctp_addr *)&val->spt_address)) {
+ trans = sctp_addr_id2transport(sk, &val->spt_address,
+ val->spt_assoc_id);
if (!trans)
return -ENOENT;
- if (val.spt_pathmaxrxt)
- trans->pathmaxrxt = val.spt_pathmaxrxt;
+ if (val->spt_pathmaxrxt)
+ trans->pathmaxrxt = val->spt_pathmaxrxt;
if (v2)
- trans->ps_retrans = val.spt_pathcpthld;
- trans->pf_retrans = val.spt_pathpfthld;
+ trans->ps_retrans = val->spt_pathcpthld;
+ trans->pf_retrans = val->spt_pathpfthld;
return 0;
}
- asoc = sctp_id2assoc(sk, val.spt_assoc_id);
- if (!asoc && val.spt_assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, val->spt_assoc_id);
+ if (!asoc && val->spt_assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
list_for_each_entry(trans, &asoc->peer.transport_addr_list,
transports) {
- if (val.spt_pathmaxrxt)
- trans->pathmaxrxt = val.spt_pathmaxrxt;
+ if (val->spt_pathmaxrxt)
+ trans->pathmaxrxt = val->spt_pathmaxrxt;
if (v2)
- trans->ps_retrans = val.spt_pathcpthld;
- trans->pf_retrans = val.spt_pathpfthld;
+ trans->ps_retrans = val->spt_pathcpthld;
+ trans->pf_retrans = val->spt_pathpfthld;
}
- if (val.spt_pathmaxrxt)
- asoc->pathmaxrxt = val.spt_pathmaxrxt;
+ if (val->spt_pathmaxrxt)
+ asoc->pathmaxrxt = val->spt_pathmaxrxt;
if (v2)
- asoc->ps_retrans = val.spt_pathcpthld;
- asoc->pf_retrans = val.spt_pathpfthld;
+ asoc->ps_retrans = val->spt_pathcpthld;
+ asoc->pf_retrans = val->spt_pathpfthld;
} else {
struct sctp_sock *sp = sctp_sk(sk);
- if (val.spt_pathmaxrxt)
- sp->pathmaxrxt = val.spt_pathmaxrxt;
+ if (val->spt_pathmaxrxt)
+ sp->pathmaxrxt = val->spt_pathmaxrxt;
if (v2)
- sp->ps_retrans = val.spt_pathcpthld;
- sp->pf_retrans = val.spt_pathpfthld;
+ sp->ps_retrans = val->spt_pathcpthld;
+ sp->pf_retrans = val->spt_pathpfthld;
}
return 0;
}
-static int sctp_setsockopt_recvrcvinfo(struct sock *sk,
- char __user *optval,
+static int sctp_setsockopt_recvrcvinfo(struct sock *sk, int *val,
unsigned int optlen)
{
- int val;
-
if (optlen < sizeof(int))
return -EINVAL;
- if (get_user(val, (int __user *) optval))
- return -EFAULT;
- sctp_sk(sk)->recvrcvinfo = (val == 0) ? 0 : 1;
+ sctp_sk(sk)->recvrcvinfo = (*val == 0) ? 0 : 1;
return 0;
}
-static int sctp_setsockopt_recvnxtinfo(struct sock *sk,
- char __user *optval,
+static int sctp_setsockopt_recvnxtinfo(struct sock *sk, int *val,
unsigned int optlen)
{
- int val;
-
if (optlen < sizeof(int))
return -EINVAL;
- if (get_user(val, (int __user *) optval))
- return -EFAULT;
- sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1;
+ sctp_sk(sk)->recvnxtinfo = (*val == 0) ? 0 : 1;
return 0;
}
static int sctp_setsockopt_pr_supported(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
- struct sctp_assoc_value params;
struct sctp_association *asoc;
- if (optlen != sizeof(params))
+ if (optlen != sizeof(*params))
return -EINVAL;
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
-
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
- sctp_sk(sk)->ep->prsctp_enable = !!params.assoc_value;
+ sctp_sk(sk)->ep->prsctp_enable = !!params->assoc_value;
return 0;
}
static int sctp_setsockopt_default_prinfo(struct sock *sk,
- char __user *optval,
+ struct sctp_default_prinfo *info,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
- struct sctp_default_prinfo info;
struct sctp_association *asoc;
int retval = -EINVAL;
- if (optlen != sizeof(info))
+ if (optlen != sizeof(*info))
goto out;
- if (copy_from_user(&info, optval, sizeof(info))) {
- retval = -EFAULT;
+ if (info->pr_policy & ~SCTP_PR_SCTP_MASK)
goto out;
- }
- if (info.pr_policy & ~SCTP_PR_SCTP_MASK)
- goto out;
+ if (info->pr_policy == SCTP_PR_SCTP_NONE)
+ info->pr_value = 0;
- if (info.pr_policy == SCTP_PR_SCTP_NONE)
- info.pr_value = 0;
-
- asoc = sctp_id2assoc(sk, info.pr_assoc_id);
- if (!asoc && info.pr_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, info->pr_assoc_id);
+ if (!asoc && info->pr_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
goto out;
retval = 0;
if (asoc) {
- SCTP_PR_SET_POLICY(asoc->default_flags, info.pr_policy);
- asoc->default_timetolive = info.pr_value;
+ SCTP_PR_SET_POLICY(asoc->default_flags, info->pr_policy);
+ asoc->default_timetolive = info->pr_value;
goto out;
}
if (sctp_style(sk, TCP))
- info.pr_assoc_id = SCTP_FUTURE_ASSOC;
+ info->pr_assoc_id = SCTP_FUTURE_ASSOC;
- if (info.pr_assoc_id == SCTP_FUTURE_ASSOC ||
- info.pr_assoc_id == SCTP_ALL_ASSOC) {
- SCTP_PR_SET_POLICY(sp->default_flags, info.pr_policy);
- sp->default_timetolive = info.pr_value;
+ if (info->pr_assoc_id == SCTP_FUTURE_ASSOC ||
+ info->pr_assoc_id == SCTP_ALL_ASSOC) {
+ SCTP_PR_SET_POLICY(sp->default_flags, info->pr_policy);
+ sp->default_timetolive = info->pr_value;
}
- if (info.pr_assoc_id == SCTP_CURRENT_ASSOC ||
- info.pr_assoc_id == SCTP_ALL_ASSOC) {
+ if (info->pr_assoc_id == SCTP_CURRENT_ASSOC ||
+ info->pr_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
- SCTP_PR_SET_POLICY(asoc->default_flags, info.pr_policy);
- asoc->default_timetolive = info.pr_value;
+ SCTP_PR_SET_POLICY(asoc->default_flags,
+ info->pr_policy);
+ asoc->default_timetolive = info->pr_value;
}
}
@@ -4140,27 +4004,21 @@ out:
}
static int sctp_setsockopt_reconfig_supported(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
- struct sctp_assoc_value params;
struct sctp_association *asoc;
int retval = -EINVAL;
- if (optlen != sizeof(params))
- goto out;
-
- if (copy_from_user(&params, optval, optlen)) {
- retval = -EFAULT;
+ if (optlen != sizeof(*params))
goto out;
- }
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
goto out;
- sctp_sk(sk)->ep->reconf_enable = !!params.assoc_value;
+ sctp_sk(sk)->ep->reconf_enable = !!params->assoc_value;
retval = 0;
@@ -4169,60 +4027,52 @@ out:
}
static int sctp_setsockopt_enable_strreset(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
- struct sctp_assoc_value params;
struct sctp_association *asoc;
int retval = -EINVAL;
- if (optlen != sizeof(params))
+ if (optlen != sizeof(*params))
goto out;
- if (copy_from_user(&params, optval, optlen)) {
- retval = -EFAULT;
- goto out;
- }
-
- if (params.assoc_value & (~SCTP_ENABLE_STRRESET_MASK))
+ if (params->assoc_value & (~SCTP_ENABLE_STRRESET_MASK))
goto out;
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
goto out;
retval = 0;
if (asoc) {
- asoc->strreset_enable = params.assoc_value;
+ asoc->strreset_enable = params->assoc_value;
goto out;
}
if (sctp_style(sk, TCP))
- params.assoc_id = SCTP_FUTURE_ASSOC;
+ params->assoc_id = SCTP_FUTURE_ASSOC;
- if (params.assoc_id == SCTP_FUTURE_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC)
- ep->strreset_enable = params.assoc_value;
+ if (params->assoc_id == SCTP_FUTURE_ASSOC ||
+ params->assoc_id == SCTP_ALL_ASSOC)
+ ep->strreset_enable = params->assoc_value;
- if (params.assoc_id == SCTP_CURRENT_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC)
+ if (params->assoc_id == SCTP_CURRENT_ASSOC ||
+ params->assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &ep->asocs, asocs)
- asoc->strreset_enable = params.assoc_value;
+ asoc->strreset_enable = params->assoc_value;
out:
return retval;
}
static int sctp_setsockopt_reset_streams(struct sock *sk,
- char __user *optval,
+ struct sctp_reset_streams *params,
unsigned int optlen)
{
- struct sctp_reset_streams *params;
struct sctp_association *asoc;
- int retval = -EINVAL;
if (optlen < sizeof(*params))
return -EINVAL;
@@ -4230,116 +4080,82 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,
optlen = min_t(unsigned int, optlen, USHRT_MAX +
sizeof(__u16) * sizeof(*params));
- params = memdup_user(optval, optlen);
- if (IS_ERR(params))
- return PTR_ERR(params);
-
if (params->srs_number_streams * sizeof(__u16) >
optlen - sizeof(*params))
- goto out;
+ return -EINVAL;
asoc = sctp_id2assoc(sk, params->srs_assoc_id);
if (!asoc)
- goto out;
-
- retval = sctp_send_reset_streams(asoc, params);
+ return -EINVAL;
-out:
- kfree(params);
- return retval;
+ return sctp_send_reset_streams(asoc, params);
}
-static int sctp_setsockopt_reset_assoc(struct sock *sk,
- char __user *optval,
+static int sctp_setsockopt_reset_assoc(struct sock *sk, sctp_assoc_t *associd,
unsigned int optlen)
{
struct sctp_association *asoc;
- sctp_assoc_t associd;
- int retval = -EINVAL;
- if (optlen != sizeof(associd))
- goto out;
-
- if (copy_from_user(&associd, optval, optlen)) {
- retval = -EFAULT;
- goto out;
- }
+ if (optlen != sizeof(*associd))
+ return -EINVAL;
- asoc = sctp_id2assoc(sk, associd);
+ asoc = sctp_id2assoc(sk, *associd);
if (!asoc)
- goto out;
-
- retval = sctp_send_reset_assoc(asoc);
+ return -EINVAL;
-out:
- return retval;
+ return sctp_send_reset_assoc(asoc);
}
static int sctp_setsockopt_add_streams(struct sock *sk,
- char __user *optval,
+ struct sctp_add_streams *params,
unsigned int optlen)
{
struct sctp_association *asoc;
- struct sctp_add_streams params;
- int retval = -EINVAL;
- if (optlen != sizeof(params))
- goto out;
-
- if (copy_from_user(&params, optval, optlen)) {
- retval = -EFAULT;
- goto out;
- }
+ if (optlen != sizeof(*params))
+ return -EINVAL;
- asoc = sctp_id2assoc(sk, params.sas_assoc_id);
+ asoc = sctp_id2assoc(sk, params->sas_assoc_id);
if (!asoc)
- goto out;
-
- retval = sctp_send_add_streams(asoc, &params);
+ return -EINVAL;
-out:
- return retval;
+ return sctp_send_add_streams(asoc, params);
}
static int sctp_setsockopt_scheduler(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
- struct sctp_assoc_value params;
int retval = 0;
- if (optlen < sizeof(params))
+ if (optlen < sizeof(*params))
return -EINVAL;
- optlen = sizeof(params);
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
-
- if (params.assoc_value > SCTP_SS_MAX)
+ if (params->assoc_value > SCTP_SS_MAX)
return -EINVAL;
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc)
- return sctp_sched_set_sched(asoc, params.assoc_value);
+ return sctp_sched_set_sched(asoc, params->assoc_value);
if (sctp_style(sk, TCP))
- params.assoc_id = SCTP_FUTURE_ASSOC;
+ params->assoc_id = SCTP_FUTURE_ASSOC;
- if (params.assoc_id == SCTP_FUTURE_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC)
- sp->default_ss = params.assoc_value;
+ if (params->assoc_id == SCTP_FUTURE_ASSOC ||
+ params->assoc_id == SCTP_ALL_ASSOC)
+ sp->default_ss = params->assoc_value;
- if (params.assoc_id == SCTP_CURRENT_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC) {
+ if (params->assoc_id == SCTP_CURRENT_ASSOC ||
+ params->assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
int ret = sctp_sched_set_sched(asoc,
- params.assoc_value);
+ params->assoc_value);
if (ret && !retval)
retval = ret;
@@ -4350,38 +4166,32 @@ static int sctp_setsockopt_scheduler(struct sock *sk,
}
static int sctp_setsockopt_scheduler_value(struct sock *sk,
- char __user *optval,
+ struct sctp_stream_value *params,
unsigned int optlen)
{
- struct sctp_stream_value params;
struct sctp_association *asoc;
int retval = -EINVAL;
- if (optlen < sizeof(params))
- goto out;
-
- optlen = sizeof(params);
- if (copy_from_user(&params, optval, optlen)) {
- retval = -EFAULT;
+ if (optlen < sizeof(*params))
goto out;
- }
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_CURRENT_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id != SCTP_CURRENT_ASSOC &&
sctp_style(sk, UDP))
goto out;
if (asoc) {
- retval = sctp_sched_set_value(asoc, params.stream_id,
- params.stream_value, GFP_KERNEL);
+ retval = sctp_sched_set_value(asoc, params->stream_id,
+ params->stream_value, GFP_KERNEL);
goto out;
}
retval = 0;
list_for_each_entry(asoc, &sctp_sk(sk)->ep->asocs, asocs) {
- int ret = sctp_sched_set_value(asoc, params.stream_id,
- params.stream_value, GFP_KERNEL);
+ int ret = sctp_sched_set_value(asoc, params->stream_id,
+ params->stream_value,
+ GFP_KERNEL);
if (ret && !retval) /* try to return the 1st error. */
retval = ret;
}
@@ -4391,46 +4201,30 @@ out:
}
static int sctp_setsockopt_interleaving_supported(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *p,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
- struct sctp_assoc_value params;
struct sctp_association *asoc;
- int retval = -EINVAL;
- if (optlen < sizeof(params))
- goto out;
-
- optlen = sizeof(params);
- if (copy_from_user(&params, optval, optlen)) {
- retval = -EFAULT;
- goto out;
- }
+ if (optlen < sizeof(*p))
+ return -EINVAL;
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
- sctp_style(sk, UDP))
- goto out;
+ asoc = sctp_id2assoc(sk, p->assoc_id);
+ if (!asoc && p->assoc_id != SCTP_FUTURE_ASSOC && sctp_style(sk, UDP))
+ return -EINVAL;
if (!sock_net(sk)->sctp.intl_enable || !sp->frag_interleave) {
- retval = -EPERM;
- goto out;
+ return -EPERM;
}
- sp->ep->intl_enable = !!params.assoc_value;
-
- retval = 0;
-
-out:
- return retval;
+ sp->ep->intl_enable = !!p->assoc_value;
+ return 0;
}
-static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_reuse_port(struct sock *sk, int *val,
unsigned int optlen)
{
- int val;
-
if (!sctp_style(sk, TCP))
return -EOPNOTSUPP;
@@ -4440,10 +4234,7 @@ static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval,
if (optlen < sizeof(int))
return -EINVAL;
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
-
- sctp_sk(sk)->reuse = !!val;
+ sctp_sk(sk)->reuse = !!*val;
return 0;
}
@@ -4469,45 +4260,40 @@ static int sctp_assoc_ulpevent_type_set(struct sctp_event *param,
return 0;
}
-static int sctp_setsockopt_event(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_event(struct sock *sk, struct sctp_event *param,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
- struct sctp_event param;
int retval = 0;
- if (optlen < sizeof(param))
+ if (optlen < sizeof(*param))
return -EINVAL;
- optlen = sizeof(param);
- if (copy_from_user(&param, optval, optlen))
- return -EFAULT;
-
- if (param.se_type < SCTP_SN_TYPE_BASE ||
- param.se_type > SCTP_SN_TYPE_MAX)
+ if (param->se_type < SCTP_SN_TYPE_BASE ||
+ param->se_type > SCTP_SN_TYPE_MAX)
return -EINVAL;
- asoc = sctp_id2assoc(sk, param.se_assoc_id);
- if (!asoc && param.se_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, param->se_assoc_id);
+ if (!asoc && param->se_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc)
- return sctp_assoc_ulpevent_type_set(&param, asoc);
+ return sctp_assoc_ulpevent_type_set(param, asoc);
if (sctp_style(sk, TCP))
- param.se_assoc_id = SCTP_FUTURE_ASSOC;
+ param->se_assoc_id = SCTP_FUTURE_ASSOC;
- if (param.se_assoc_id == SCTP_FUTURE_ASSOC ||
- param.se_assoc_id == SCTP_ALL_ASSOC)
+ if (param->se_assoc_id == SCTP_FUTURE_ASSOC ||
+ param->se_assoc_id == SCTP_ALL_ASSOC)
sctp_ulpevent_type_set(&sp->subscribe,
- param.se_type, param.se_on);
+ param->se_type, param->se_on);
- if (param.se_assoc_id == SCTP_CURRENT_ASSOC ||
- param.se_assoc_id == SCTP_ALL_ASSOC) {
+ if (param->se_assoc_id == SCTP_CURRENT_ASSOC ||
+ param->se_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
- int ret = sctp_assoc_ulpevent_type_set(&param, asoc);
+ int ret = sctp_assoc_ulpevent_type_set(param, asoc);
if (ret && !retval)
retval = ret;
@@ -4518,29 +4304,23 @@ static int sctp_setsockopt_event(struct sock *sk, char __user *optval,
}
static int sctp_setsockopt_asconf_supported(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
- struct sctp_assoc_value params;
struct sctp_association *asoc;
struct sctp_endpoint *ep;
int retval = -EINVAL;
- if (optlen != sizeof(params))
+ if (optlen != sizeof(*params))
goto out;
- if (copy_from_user(&params, optval, optlen)) {
- retval = -EFAULT;
- goto out;
- }
-
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
goto out;
ep = sctp_sk(sk)->ep;
- ep->asconf_enable = !!params.assoc_value;
+ ep->asconf_enable = !!params->assoc_value;
if (ep->asconf_enable && ep->auth_enable) {
sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
@@ -4554,29 +4334,23 @@ out:
}
static int sctp_setsockopt_auth_supported(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
- struct sctp_assoc_value params;
struct sctp_association *asoc;
struct sctp_endpoint *ep;
int retval = -EINVAL;
- if (optlen != sizeof(params))
- goto out;
-
- if (copy_from_user(&params, optval, optlen)) {
- retval = -EFAULT;
+ if (optlen != sizeof(*params))
goto out;
- }
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
goto out;
ep = sctp_sk(sk)->ep;
- if (params.assoc_value) {
+ if (params->assoc_value) {
retval = sctp_auth_init(ep, GFP_KERNEL);
if (retval)
goto out;
@@ -4586,7 +4360,7 @@ static int sctp_setsockopt_auth_supported(struct sock *sk,
}
}
- ep->auth_enable = !!params.assoc_value;
+ ep->auth_enable = !!params->assoc_value;
retval = 0;
out:
@@ -4594,27 +4368,21 @@ out:
}
static int sctp_setsockopt_ecn_supported(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
- struct sctp_assoc_value params;
struct sctp_association *asoc;
int retval = -EINVAL;
- if (optlen != sizeof(params))
- goto out;
-
- if (copy_from_user(&params, optval, optlen)) {
- retval = -EFAULT;
+ if (optlen != sizeof(*params))
goto out;
- }
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
goto out;
- sctp_sk(sk)->ep->ecn_enable = !!params.assoc_value;
+ sctp_sk(sk)->ep->ecn_enable = !!params->assoc_value;
retval = 0;
out:
@@ -4622,33 +4390,27 @@ out:
}
static int sctp_setsockopt_pf_expose(struct sock *sk,
- char __user *optval,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
- struct sctp_assoc_value params;
struct sctp_association *asoc;
int retval = -EINVAL;
- if (optlen != sizeof(params))
+ if (optlen != sizeof(*params))
goto out;
- if (copy_from_user(&params, optval, optlen)) {
- retval = -EFAULT;
- goto out;
- }
-
- if (params.assoc_value > SCTP_PF_EXPOSE_MAX)
+ if (params->assoc_value > SCTP_PF_EXPOSE_MAX)
goto out;
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
goto out;
if (asoc)
- asoc->pf_expose = params.assoc_value;
+ asoc->pf_expose = params->assoc_value;
else
- sctp_sk(sk)->pf_expose = params.assoc_value;
+ sctp_sk(sk)->pf_expose = params->assoc_value;
retval = 0;
out:
@@ -4675,8 +4437,9 @@ out:
* optlen - the size of the buffer.
*/
static int sctp_setsockopt(struct sock *sk, int level, int optname,
- char __user *optval, unsigned int optlen)
+ sockptr_t optval, unsigned int optlen)
{
+ void *kopt = NULL;
int retval = 0;
pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname);
@@ -4689,8 +4452,14 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
*/
if (level != SOL_SCTP) {
struct sctp_af *af = sctp_sk(sk)->pf->af;
- retval = af->setsockopt(sk, level, optname, optval, optlen);
- goto out_nounlock;
+
+ return af->setsockopt(sk, level, optname, optval, optlen);
+ }
+
+ if (optlen > 0) {
+ kopt = memdup_sockptr(optval, optlen);
+ if (IS_ERR(kopt))
+ return PTR_ERR(kopt);
}
lock_sock(sk);
@@ -4698,179 +4467,174 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
switch (optname) {
case SCTP_SOCKOPT_BINDX_ADD:
/* 'optlen' is the size of the addresses buffer. */
- retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval,
- optlen, SCTP_BINDX_ADD_ADDR);
+ retval = sctp_setsockopt_bindx(sk, kopt, optlen,
+ SCTP_BINDX_ADD_ADDR);
break;
case SCTP_SOCKOPT_BINDX_REM:
/* 'optlen' is the size of the addresses buffer. */
- retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval,
- optlen, SCTP_BINDX_REM_ADDR);
+ retval = sctp_setsockopt_bindx(sk, kopt, optlen,
+ SCTP_BINDX_REM_ADDR);
break;
case SCTP_SOCKOPT_CONNECTX_OLD:
/* 'optlen' is the size of the addresses buffer. */
- retval = sctp_setsockopt_connectx_old(sk,
- (struct sockaddr __user *)optval,
- optlen);
+ retval = sctp_setsockopt_connectx_old(sk, kopt, optlen);
break;
case SCTP_SOCKOPT_CONNECTX:
/* 'optlen' is the size of the addresses buffer. */
- retval = sctp_setsockopt_connectx(sk,
- (struct sockaddr __user *)optval,
- optlen);
+ retval = sctp_setsockopt_connectx(sk, kopt, optlen);
break;
case SCTP_DISABLE_FRAGMENTS:
- retval = sctp_setsockopt_disable_fragments(sk, optval, optlen);
+ retval = sctp_setsockopt_disable_fragments(sk, kopt, optlen);
break;
case SCTP_EVENTS:
- retval = sctp_setsockopt_events(sk, optval, optlen);
+ retval = sctp_setsockopt_events(sk, kopt, optlen);
break;
case SCTP_AUTOCLOSE:
- retval = sctp_setsockopt_autoclose(sk, optval, optlen);
+ retval = sctp_setsockopt_autoclose(sk, kopt, optlen);
break;
case SCTP_PEER_ADDR_PARAMS:
- retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
+ retval = sctp_setsockopt_peer_addr_params(sk, kopt, optlen);
break;
case SCTP_DELAYED_SACK:
- retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
+ retval = sctp_setsockopt_delayed_ack(sk, kopt, optlen);
break;
case SCTP_PARTIAL_DELIVERY_POINT:
- retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen);
+ retval = sctp_setsockopt_partial_delivery_point(sk, kopt, optlen);
break;
case SCTP_INITMSG:
- retval = sctp_setsockopt_initmsg(sk, optval, optlen);
+ retval = sctp_setsockopt_initmsg(sk, kopt, optlen);
break;
case SCTP_DEFAULT_SEND_PARAM:
- retval = sctp_setsockopt_default_send_param(sk, optval,
- optlen);
+ retval = sctp_setsockopt_default_send_param(sk, kopt, optlen);
break;
case SCTP_DEFAULT_SNDINFO:
- retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen);
+ retval = sctp_setsockopt_default_sndinfo(sk, kopt, optlen);
break;
case SCTP_PRIMARY_ADDR:
- retval = sctp_setsockopt_primary_addr(sk, optval, optlen);
+ retval = sctp_setsockopt_primary_addr(sk, kopt, optlen);
break;
case SCTP_SET_PEER_PRIMARY_ADDR:
- retval = sctp_setsockopt_peer_primary_addr(sk, optval, optlen);
+ retval = sctp_setsockopt_peer_primary_addr(sk, kopt, optlen);
break;
case SCTP_NODELAY:
- retval = sctp_setsockopt_nodelay(sk, optval, optlen);
+ retval = sctp_setsockopt_nodelay(sk, kopt, optlen);
break;
case SCTP_RTOINFO:
- retval = sctp_setsockopt_rtoinfo(sk, optval, optlen);
+ retval = sctp_setsockopt_rtoinfo(sk, kopt, optlen);
break;
case SCTP_ASSOCINFO:
- retval = sctp_setsockopt_associnfo(sk, optval, optlen);
+ retval = sctp_setsockopt_associnfo(sk, kopt, optlen);
break;
case SCTP_I_WANT_MAPPED_V4_ADDR:
- retval = sctp_setsockopt_mappedv4(sk, optval, optlen);
+ retval = sctp_setsockopt_mappedv4(sk, kopt, optlen);
break;
case SCTP_MAXSEG:
- retval = sctp_setsockopt_maxseg(sk, optval, optlen);
+ retval = sctp_setsockopt_maxseg(sk, kopt, optlen);
break;
case SCTP_ADAPTATION_LAYER:
- retval = sctp_setsockopt_adaptation_layer(sk, optval, optlen);
+ retval = sctp_setsockopt_adaptation_layer(sk, kopt, optlen);
break;
case SCTP_CONTEXT:
- retval = sctp_setsockopt_context(sk, optval, optlen);
+ retval = sctp_setsockopt_context(sk, kopt, optlen);
break;
case SCTP_FRAGMENT_INTERLEAVE:
- retval = sctp_setsockopt_fragment_interleave(sk, optval, optlen);
+ retval = sctp_setsockopt_fragment_interleave(sk, kopt, optlen);
break;
case SCTP_MAX_BURST:
- retval = sctp_setsockopt_maxburst(sk, optval, optlen);
+ retval = sctp_setsockopt_maxburst(sk, kopt, optlen);
break;
case SCTP_AUTH_CHUNK:
- retval = sctp_setsockopt_auth_chunk(sk, optval, optlen);
+ retval = sctp_setsockopt_auth_chunk(sk, kopt, optlen);
break;
case SCTP_HMAC_IDENT:
- retval = sctp_setsockopt_hmac_ident(sk, optval, optlen);
+ retval = sctp_setsockopt_hmac_ident(sk, kopt, optlen);
break;
case SCTP_AUTH_KEY:
- retval = sctp_setsockopt_auth_key(sk, optval, optlen);
+ retval = sctp_setsockopt_auth_key(sk, kopt, optlen);
break;
case SCTP_AUTH_ACTIVE_KEY:
- retval = sctp_setsockopt_active_key(sk, optval, optlen);
+ retval = sctp_setsockopt_active_key(sk, kopt, optlen);
break;
case SCTP_AUTH_DELETE_KEY:
- retval = sctp_setsockopt_del_key(sk, optval, optlen);
+ retval = sctp_setsockopt_del_key(sk, kopt, optlen);
break;
case SCTP_AUTH_DEACTIVATE_KEY:
- retval = sctp_setsockopt_deactivate_key(sk, optval, optlen);
+ retval = sctp_setsockopt_deactivate_key(sk, kopt, optlen);
break;
case SCTP_AUTO_ASCONF:
- retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
+ retval = sctp_setsockopt_auto_asconf(sk, kopt, optlen);
break;
case SCTP_PEER_ADDR_THLDS:
- retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen,
+ retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen,
false);
break;
case SCTP_PEER_ADDR_THLDS_V2:
- retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen,
+ retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen,
true);
break;
case SCTP_RECVRCVINFO:
- retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen);
+ retval = sctp_setsockopt_recvrcvinfo(sk, kopt, optlen);
break;
case SCTP_RECVNXTINFO:
- retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen);
+ retval = sctp_setsockopt_recvnxtinfo(sk, kopt, optlen);
break;
case SCTP_PR_SUPPORTED:
- retval = sctp_setsockopt_pr_supported(sk, optval, optlen);
+ retval = sctp_setsockopt_pr_supported(sk, kopt, optlen);
break;
case SCTP_DEFAULT_PRINFO:
- retval = sctp_setsockopt_default_prinfo(sk, optval, optlen);
+ retval = sctp_setsockopt_default_prinfo(sk, kopt, optlen);
break;
case SCTP_RECONFIG_SUPPORTED:
- retval = sctp_setsockopt_reconfig_supported(sk, optval, optlen);
+ retval = sctp_setsockopt_reconfig_supported(sk, kopt, optlen);
break;
case SCTP_ENABLE_STREAM_RESET:
- retval = sctp_setsockopt_enable_strreset(sk, optval, optlen);
+ retval = sctp_setsockopt_enable_strreset(sk, kopt, optlen);
break;
case SCTP_RESET_STREAMS:
- retval = sctp_setsockopt_reset_streams(sk, optval, optlen);
+ retval = sctp_setsockopt_reset_streams(sk, kopt, optlen);
break;
case SCTP_RESET_ASSOC:
- retval = sctp_setsockopt_reset_assoc(sk, optval, optlen);
+ retval = sctp_setsockopt_reset_assoc(sk, kopt, optlen);
break;
case SCTP_ADD_STREAMS:
- retval = sctp_setsockopt_add_streams(sk, optval, optlen);
+ retval = sctp_setsockopt_add_streams(sk, kopt, optlen);
break;
case SCTP_STREAM_SCHEDULER:
- retval = sctp_setsockopt_scheduler(sk, optval, optlen);
+ retval = sctp_setsockopt_scheduler(sk, kopt, optlen);
break;
case SCTP_STREAM_SCHEDULER_VALUE:
- retval = sctp_setsockopt_scheduler_value(sk, optval, optlen);
+ retval = sctp_setsockopt_scheduler_value(sk, kopt, optlen);
break;
case SCTP_INTERLEAVING_SUPPORTED:
- retval = sctp_setsockopt_interleaving_supported(sk, optval,
+ retval = sctp_setsockopt_interleaving_supported(sk, kopt,
optlen);
break;
case SCTP_REUSE_PORT:
- retval = sctp_setsockopt_reuse_port(sk, optval, optlen);
+ retval = sctp_setsockopt_reuse_port(sk, kopt, optlen);
break;
case SCTP_EVENT:
- retval = sctp_setsockopt_event(sk, optval, optlen);
+ retval = sctp_setsockopt_event(sk, kopt, optlen);
break;
case SCTP_ASCONF_SUPPORTED:
- retval = sctp_setsockopt_asconf_supported(sk, optval, optlen);
+ retval = sctp_setsockopt_asconf_supported(sk, kopt, optlen);
break;
case SCTP_AUTH_SUPPORTED:
- retval = sctp_setsockopt_auth_supported(sk, optval, optlen);
+ retval = sctp_setsockopt_auth_supported(sk, kopt, optlen);
break;
case SCTP_ECN_SUPPORTED:
- retval = sctp_setsockopt_ecn_supported(sk, optval, optlen);
+ retval = sctp_setsockopt_ecn_supported(sk, kopt, optlen);
break;
case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
- retval = sctp_setsockopt_pf_expose(sk, optval, optlen);
+ retval = sctp_setsockopt_pf_expose(sk, kopt, optlen);
break;
default:
retval = -ENOPROTOOPT;
@@ -4878,8 +4642,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
}
release_sock(sk);
-
-out_nounlock:
+ kfree(kopt);
return retval;
}