Commit bed1ce78 authored by David S. Miller's avatar David S. Miller

Merge branch 'do-a-single-memdup_user-in-sctp_setsockopt-v2'

Christoph Hellwig says:

====================
do a single memdup_user in sctp_setsockopt v2

here is a resend of my series to lift the copy_from_user out of the
individual sctp sockopt handlers into the main sctp_setsockopt
routine.

Changes since v1:
 - fixes a few sizeof calls.
 - use memzero_explicit in sctp_setsockopt_auth_key instead of special
   casing it for a kzfree in the caller
 - remove some minor cleanups from sctp_setsockopt_autoclose to keep
   it closer to the existing version
 - add another little only vaguely related cleanup patch
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9aa0dfe1 6c8983a6
...@@ -979,9 +979,8 @@ int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw) ...@@ -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. * Returns 0 if ok, <0 errno code on error.
*/ */
static int sctp_setsockopt_bindx_kernel(struct sock *sk, static int sctp_setsockopt_bindx(struct sock *sk, struct sockaddr *addrs,
struct sockaddr *addrs, int addrs_size, int addrs_size, int op)
int op)
{ {
int err; int err;
int addrcnt = 0; int addrcnt = 0;
...@@ -991,7 +990,7 @@ static int sctp_setsockopt_bindx_kernel(struct sock *sk, ...@@ -991,7 +990,7 @@ static int sctp_setsockopt_bindx_kernel(struct sock *sk,
struct sctp_af *af; struct sctp_af *af;
pr_debug("%s: sk:%p addrs:%p addrs_size:%d opt:%d\n", 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)) if (unlikely(addrs_size <= 0))
return -EINVAL; return -EINVAL;
...@@ -1037,29 +1036,13 @@ static int sctp_setsockopt_bindx_kernel(struct sock *sk, ...@@ -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, static int sctp_bind_add(struct sock *sk, struct sockaddr *addrs,
int addrlen) int addrlen)
{ {
int err; int err;
lock_sock(sk); lock_sock(sk);
err = sctp_setsockopt_bindx_kernel(sk, addrs, addrlen, err = sctp_setsockopt_bindx(sk, addrs, addrlen, SCTP_BINDX_ADD_ADDR);
SCTP_BINDX_ADD_ADDR);
release_sock(sk); release_sock(sk);
return err; return err;
} }
...@@ -1303,36 +1286,29 @@ static int __sctp_connect(struct sock *sk, struct sockaddr *kaddrs, ...@@ -1303,36 +1286,29 @@ static int __sctp_connect(struct sock *sk, struct sockaddr *kaddrs,
* it. * it.
* *
* sk The sk of the socket * 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 * addrssize Size of the addrs buffer
* *
* Returns >=0 if ok, <0 errno code on error. * Returns >=0 if ok, <0 errno code on error.
*/ */
static int __sctp_setsockopt_connectx(struct sock *sk, static int __sctp_setsockopt_connectx(struct sock *sk, struct sockaddr *kaddrs,
struct sockaddr __user *addrs, int addrs_size, sctp_assoc_t *assoc_id)
int addrs_size,
sctp_assoc_t *assoc_id)
{ {
struct sockaddr *kaddrs;
int err = 0, flags = 0; int err = 0, flags = 0;
pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n", 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 */ /* make sure the 1st addr's sa_family is accessible later */
if (unlikely(addrs_size < sizeof(sa_family_t))) if (unlikely(addrs_size < sizeof(sa_family_t)))
return -EINVAL; return -EINVAL;
kaddrs = memdup_user(addrs, addrs_size);
if (IS_ERR(kaddrs))
return PTR_ERR(kaddrs);
/* Allow security module to validate connectx addresses. */ /* Allow security module to validate connectx addresses. */
err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX, err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX,
(struct sockaddr *)kaddrs, (struct sockaddr *)kaddrs,
addrs_size); addrs_size);
if (err) if (err)
goto out_free; return err;
/* in-kernel sockets don't generally have a file allocated to them /* in-kernel sockets don't generally have a file allocated to them
* if all they do is call sock_create_kern(). * if all they do is call sock_create_kern().
...@@ -1340,12 +1316,7 @@ static int __sctp_setsockopt_connectx(struct sock *sk, ...@@ -1340,12 +1316,7 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
if (sk->sk_socket->file) if (sk->sk_socket->file)
flags = sk->sk_socket->file->f_flags; flags = sk->sk_socket->file->f_flags;
err = __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id); return __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
out_free:
kfree(kaddrs);
return err;
} }
/* /*
...@@ -1353,10 +1324,10 @@ static int __sctp_setsockopt_connectx(struct sock *sk, ...@@ -1353,10 +1324,10 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
* to the option that doesn't provide association id. * to the option that doesn't provide association id.
*/ */
static int sctp_setsockopt_connectx_old(struct sock *sk, static int sctp_setsockopt_connectx_old(struct sock *sk,
struct sockaddr __user *addrs, struct sockaddr *kaddrs,
int addrs_size) 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, ...@@ -1366,13 +1337,13 @@ static int sctp_setsockopt_connectx_old(struct sock *sk,
* always positive. * always positive.
*/ */
static int sctp_setsockopt_connectx(struct sock *sk, static int sctp_setsockopt_connectx(struct sock *sk,
struct sockaddr __user *addrs, struct sockaddr *kaddrs,
int addrs_size) int addrs_size)
{ {
sctp_assoc_t assoc_id = 0; sctp_assoc_t assoc_id = 0;
int err = 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) if (err)
return err; return err;
...@@ -1402,6 +1373,7 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len, ...@@ -1402,6 +1373,7 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len,
{ {
struct sctp_getaddrs_old param; struct sctp_getaddrs_old param;
sctp_assoc_t assoc_id = 0; sctp_assoc_t assoc_id = 0;
struct sockaddr *kaddrs;
int err = 0; int err = 0;
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -1425,9 +1397,12 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len, ...@@ -1425,9 +1397,12 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len,
return -EFAULT; return -EFAULT;
} }
err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *) kaddrs = memdup_user(param.addrs, param.addr_num);
param.addrs, param.addr_num, if (IS_ERR(kaddrs))
&assoc_id); return PTR_ERR(kaddrs);
err = __sctp_setsockopt_connectx(sk, kaddrs, param.addr_num, &assoc_id);
kfree(kaddrs);
if (err == 0 || err == -EINPROGRESS) { if (err == 0 || err == -EINPROGRESS) {
if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
return -EFAULT; return -EFAULT;
...@@ -2209,28 +2184,18 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, ...@@ -2209,28 +2184,18 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
* exceeds the current PMTU size, the message will NOT be sent and * exceeds the current PMTU size, the message will NOT be sent and
* instead a error will be indicated to the user. * instead a error will be indicated to the user.
*/ */
static int sctp_setsockopt_disable_fragments(struct sock *sk, static int sctp_setsockopt_disable_fragments(struct sock *sk, int *val,
char __user *optval,
unsigned int optlen) unsigned int optlen)
{ {
int val;
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return -EINVAL; return -EINVAL;
sctp_sk(sk)->disable_fragments = (*val == 0) ? 0 : 1;
if (get_user(val, (int __user *)optval))
return -EFAULT;
sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1;
return 0; 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) unsigned int optlen)
{ {
struct sctp_event_subscribe subscribe;
__u8 *sn_type = (__u8 *)&subscribe;
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc; struct sctp_association *asoc;
int i; int i;
...@@ -2238,9 +2203,6 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval, ...@@ -2238,9 +2203,6 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
if (optlen > sizeof(struct sctp_event_subscribe)) if (optlen > sizeof(struct sctp_event_subscribe))
return -EINVAL; return -EINVAL;
if (copy_from_user(&subscribe, optval, optlen))
return -EFAULT;
for (i = 0; i < optlen; i++) for (i = 0; i < optlen; i++)
sctp_ulpevent_type_set(&sp->subscribe, SCTP_SN_TYPE_BASE + i, sctp_ulpevent_type_set(&sp->subscribe, SCTP_SN_TYPE_BASE + i,
sn_type[i]); sn_type[i]);
...@@ -2280,7 +2242,7 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval, ...@@ -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 * integer defining the number of seconds of idle time before an
* association is closed. * 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) unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
...@@ -2291,9 +2253,8 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, ...@@ -2291,9 +2253,8 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (optlen != sizeof(int)) if (optlen != sizeof(int))
return -EINVAL; return -EINVAL;
if (copy_from_user(&sp->autoclose, optval, optlen))
return -EFAULT;
sp->autoclose = *optval;
if (sp->autoclose > net->sctp.max_autoclose) if (sp->autoclose > net->sctp.max_autoclose)
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, ...@@ -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, static int sctp_setsockopt_peer_addr_params(struct sock *sk,
char __user *optval, struct sctp_paddrparams *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_paddrparams params;
struct sctp_transport *trans = NULL; struct sctp_transport *trans = NULL;
struct sctp_association *asoc = NULL; struct sctp_association *asoc = NULL;
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
int error; int error;
int hb_change, pmtud_change, sackdelay_change; int hb_change, pmtud_change, sackdelay_change;
if (optlen == sizeof(params)) { if (optlen == ALIGN(offsetof(struct sctp_paddrparams,
if (copy_from_user(&params, optval, optlen))
return -EFAULT;
} else if (optlen == ALIGN(offsetof(struct sctp_paddrparams,
spp_ipv6_flowlabel), 4)) { spp_ipv6_flowlabel), 4)) {
if (copy_from_user(&params, optval, optlen)) if (params->spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL))
return -EFAULT;
if (params.spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL))
return -EINVAL; return -EINVAL;
} else { } else if (optlen != sizeof(*params)) {
return -EINVAL; return -EINVAL;
} }
/* Validate flags and value parameters. */ /* Validate flags and value parameters. */
hb_change = params.spp_flags & SPP_HB; hb_change = params->spp_flags & SPP_HB;
pmtud_change = params.spp_flags & SPP_PMTUD; pmtud_change = params->spp_flags & SPP_PMTUD;
sackdelay_change = params.spp_flags & SPP_SACKDELAY; sackdelay_change = params->spp_flags & SPP_SACKDELAY;
if (hb_change == SPP_HB || if (hb_change == SPP_HB ||
pmtud_change == SPP_PMTUD || pmtud_change == SPP_PMTUD ||
sackdelay_change == SPP_SACKDELAY || sackdelay_change == SPP_SACKDELAY ||
params.spp_sackdelay > 500 || params->spp_sackdelay > 500 ||
(params.spp_pathmtu && (params->spp_pathmtu &&
params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT)) params->spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
return -EINVAL; return -EINVAL;
/* If an address other than INADDR_ANY is specified, and /* If an address other than INADDR_ANY is specified, and
* no transport is found, then the request is invalid. * no transport is found, then the request is invalid.
*/ */
if (!sctp_is_any(sk, (union sctp_addr *)&params.spp_address)) { if (!sctp_is_any(sk, (union sctp_addr *)&params->spp_address)) {
trans = sctp_addr_id2transport(sk, &params.spp_address, trans = sctp_addr_id2transport(sk, &params->spp_address,
params.spp_assoc_id); params->spp_assoc_id);
if (!trans) if (!trans)
return -EINVAL; return -EINVAL;
} }
...@@ -2678,19 +2633,19 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, ...@@ -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 * socket is a one to many style socket, and an association
* was not found, then the id was invalid. * was not found, then the id was invalid.
*/ */
asoc = sctp_id2assoc(sk, params.spp_assoc_id); asoc = sctp_id2assoc(sk, params->spp_assoc_id);
if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC && if (!asoc && params->spp_assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
/* Heartbeat demand can only be sent on a transport or /* Heartbeat demand can only be sent on a transport or
* association, but not a socket. * 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; return -EINVAL;
/* Process parameters. */ /* 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, hb_change, pmtud_change,
sackdelay_change); sackdelay_change);
...@@ -2703,7 +2658,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, ...@@ -2703,7 +2658,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
if (!trans && asoc) { if (!trans && asoc) {
list_for_each_entry(trans, &asoc->peer.transport_addr_list, list_for_each_entry(trans, &asoc->peer.transport_addr_list,
transports) { transports) {
sctp_apply_peer_addr_params(&params, trans, asoc, sp, sctp_apply_peer_addr_params(params, trans, asoc, sp,
hb_change, pmtud_change, hb_change, pmtud_change,
sackdelay_change); sackdelay_change);
} }
...@@ -2796,17 +2751,14 @@ static void sctp_apply_asoc_delayed_ack(struct sctp_sack_info *params, ...@@ -2796,17 +2751,14 @@ static void sctp_apply_asoc_delayed_ack(struct sctp_sack_info *params,
*/ */
static int sctp_setsockopt_delayed_ack(struct sock *sk, static int sctp_setsockopt_delayed_ack(struct sock *sk,
char __user *optval, unsigned int optlen) struct sctp_sack_info *params,
unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_sack_info params;
if (optlen == sizeof(struct sctp_sack_info)) { if (optlen == sizeof(struct sctp_sack_info)) {
if (copy_from_user(&params, optval, optlen)) if (params->sack_delay == 0 && params->sack_freq == 0)
return -EFAULT;
if (params.sack_delay == 0 && params.sack_freq == 0)
return 0; return 0;
} else if (optlen == sizeof(struct sctp_assoc_value)) { } else if (optlen == sizeof(struct sctp_assoc_value)) {
pr_warn_ratelimited(DEPRECATED pr_warn_ratelimited(DEPRECATED
...@@ -2814,59 +2766,57 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, ...@@ -2814,59 +2766,57 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
"Use of struct sctp_assoc_value in delayed_ack socket option.\n" "Use of struct sctp_assoc_value in delayed_ack socket option.\n"
"Use struct sctp_sack_info instead\n", "Use struct sctp_sack_info instead\n",
current->comm, task_pid_nr(current)); current->comm, task_pid_nr(current));
if (copy_from_user(&params, optval, optlen))
return -EFAULT;
if (params.sack_delay == 0) if (params->sack_delay == 0)
params.sack_freq = 1; params->sack_freq = 1;
else else
params.sack_freq = 0; params->sack_freq = 0;
} else } else
return -EINVAL; return -EINVAL;
/* Validate value parameter. */ /* Validate value parameter. */
if (params.sack_delay > 500) if (params->sack_delay > 500)
return -EINVAL; return -EINVAL;
/* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the /* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the
* socket is a one to many style socket, and an association * socket is a one to many style socket, and an association
* was not found, then the id was invalid. * was not found, then the id was invalid.
*/ */
asoc = sctp_id2assoc(sk, params.sack_assoc_id); asoc = sctp_id2assoc(sk, params->sack_assoc_id);
if (!asoc && params.sack_assoc_id > SCTP_ALL_ASSOC && if (!asoc && params->sack_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) { if (asoc) {
sctp_apply_asoc_delayed_ack(&params, asoc); sctp_apply_asoc_delayed_ack(params, asoc);
return 0; return 0;
} }
if (sctp_style(sk, TCP)) 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 || if (params->sack_assoc_id == SCTP_FUTURE_ASSOC ||
params.sack_assoc_id == SCTP_ALL_ASSOC) { params->sack_assoc_id == SCTP_ALL_ASSOC) {
if (params.sack_delay) { if (params->sack_delay) {
sp->sackdelay = params.sack_delay; sp->sackdelay = params->sack_delay;
sp->param_flags = sp->param_flags =
sctp_spp_sackdelay_enable(sp->param_flags); sctp_spp_sackdelay_enable(sp->param_flags);
} }
if (params.sack_freq == 1) { if (params->sack_freq == 1) {
sp->param_flags = sp->param_flags =
sctp_spp_sackdelay_disable(sp->param_flags); sctp_spp_sackdelay_disable(sp->param_flags);
} else if (params.sack_freq > 1) { } else if (params->sack_freq > 1) {
sp->sackfreq = params.sack_freq; sp->sackfreq = params->sack_freq;
sp->param_flags = sp->param_flags =
sctp_spp_sackdelay_enable(sp->param_flags); sctp_spp_sackdelay_enable(sp->param_flags);
} }
} }
if (params.sack_assoc_id == SCTP_CURRENT_ASSOC || if (params->sack_assoc_id == SCTP_CURRENT_ASSOC ||
params.sack_assoc_id == SCTP_ALL_ASSOC) params->sack_assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &sp->ep->asocs, asocs) 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; return 0;
} }
...@@ -2882,24 +2832,22 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, ...@@ -2882,24 +2832,22 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
* by the change). With TCP-style sockets, this option is inherited by * by the change). With TCP-style sockets, this option is inherited by
* sockets derived from a listener socket. * 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); struct sctp_sock *sp = sctp_sk(sk);
if (optlen != sizeof(struct sctp_initmsg)) if (optlen != sizeof(struct sctp_initmsg))
return -EINVAL; return -EINVAL;
if (copy_from_user(&sinit, optval, optlen))
return -EFAULT;
if (sinit.sinit_num_ostreams) if (sinit->sinit_num_ostreams)
sp->initmsg.sinit_num_ostreams = sinit.sinit_num_ostreams; sp->initmsg.sinit_num_ostreams = sinit->sinit_num_ostreams;
if (sinit.sinit_max_instreams) if (sinit->sinit_max_instreams)
sp->initmsg.sinit_max_instreams = sinit.sinit_max_instreams; sp->initmsg.sinit_max_instreams = sinit->sinit_max_instreams;
if (sinit.sinit_max_attempts) if (sinit->sinit_max_attempts)
sp->initmsg.sinit_max_attempts = sinit.sinit_max_attempts; sp->initmsg.sinit_max_attempts = sinit->sinit_max_attempts;
if (sinit.sinit_max_init_timeo) if (sinit->sinit_max_init_timeo)
sp->initmsg.sinit_max_init_timeo = sinit.sinit_max_init_timeo; sp->initmsg.sinit_max_init_timeo = sinit->sinit_max_init_timeo;
return 0; return 0;
} }
...@@ -2919,57 +2867,54 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigne ...@@ -2919,57 +2867,54 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigne
* to this call if the caller is using the UDP model. * to this call if the caller is using the UDP model.
*/ */
static int sctp_setsockopt_default_send_param(struct sock *sk, static int sctp_setsockopt_default_send_param(struct sock *sk,
char __user *optval, struct sctp_sndrcvinfo *info,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_sndrcvinfo info;
if (optlen != sizeof(info)) if (optlen != sizeof(*info))
return -EINVAL; return -EINVAL;
if (copy_from_user(&info, optval, optlen)) if (info->sinfo_flags &
return -EFAULT;
if (info.sinfo_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER | ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF)) SCTP_ABORT | SCTP_EOF))
return -EINVAL; return -EINVAL;
asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); asoc = sctp_id2assoc(sk, info->sinfo_assoc_id);
if (!asoc && info.sinfo_assoc_id > SCTP_ALL_ASSOC && if (!asoc && info->sinfo_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) { if (asoc) {
asoc->default_stream = info.sinfo_stream; asoc->default_stream = info->sinfo_stream;
asoc->default_flags = info.sinfo_flags; asoc->default_flags = info->sinfo_flags;
asoc->default_ppid = info.sinfo_ppid; asoc->default_ppid = info->sinfo_ppid;
asoc->default_context = info.sinfo_context; asoc->default_context = info->sinfo_context;
asoc->default_timetolive = info.sinfo_timetolive; asoc->default_timetolive = info->sinfo_timetolive;
return 0; return 0;
} }
if (sctp_style(sk, TCP)) 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 || if (info->sinfo_assoc_id == SCTP_FUTURE_ASSOC ||
info.sinfo_assoc_id == SCTP_ALL_ASSOC) { info->sinfo_assoc_id == SCTP_ALL_ASSOC) {
sp->default_stream = info.sinfo_stream; sp->default_stream = info->sinfo_stream;
sp->default_flags = info.sinfo_flags; sp->default_flags = info->sinfo_flags;
sp->default_ppid = info.sinfo_ppid; sp->default_ppid = info->sinfo_ppid;
sp->default_context = info.sinfo_context; sp->default_context = info->sinfo_context;
sp->default_timetolive = info.sinfo_timetolive; sp->default_timetolive = info->sinfo_timetolive;
} }
if (info.sinfo_assoc_id == SCTP_CURRENT_ASSOC || if (info->sinfo_assoc_id == SCTP_CURRENT_ASSOC ||
info.sinfo_assoc_id == SCTP_ALL_ASSOC) { info->sinfo_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) { list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
asoc->default_stream = info.sinfo_stream; asoc->default_stream = info->sinfo_stream;
asoc->default_flags = info.sinfo_flags; asoc->default_flags = info->sinfo_flags;
asoc->default_ppid = info.sinfo_ppid; asoc->default_ppid = info->sinfo_ppid;
asoc->default_context = info.sinfo_context; asoc->default_context = info->sinfo_context;
asoc->default_timetolive = info.sinfo_timetolive; asoc->default_timetolive = info->sinfo_timetolive;
} }
} }
...@@ -2980,54 +2925,51 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, ...@@ -2980,54 +2925,51 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
* (SCTP_DEFAULT_SNDINFO) * (SCTP_DEFAULT_SNDINFO)
*/ */
static int sctp_setsockopt_default_sndinfo(struct sock *sk, static int sctp_setsockopt_default_sndinfo(struct sock *sk,
char __user *optval, struct sctp_sndinfo *info,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_sndinfo info;
if (optlen != sizeof(info)) if (optlen != sizeof(*info))
return -EINVAL; return -EINVAL;
if (copy_from_user(&info, optval, optlen)) if (info->snd_flags &
return -EFAULT;
if (info.snd_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER | ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF)) SCTP_ABORT | SCTP_EOF))
return -EINVAL; return -EINVAL;
asoc = sctp_id2assoc(sk, info.snd_assoc_id); asoc = sctp_id2assoc(sk, info->snd_assoc_id);
if (!asoc && info.snd_assoc_id > SCTP_ALL_ASSOC && if (!asoc && info->snd_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) { if (asoc) {
asoc->default_stream = info.snd_sid; asoc->default_stream = info->snd_sid;
asoc->default_flags = info.snd_flags; asoc->default_flags = info->snd_flags;
asoc->default_ppid = info.snd_ppid; asoc->default_ppid = info->snd_ppid;
asoc->default_context = info.snd_context; asoc->default_context = info->snd_context;
return 0; return 0;
} }
if (sctp_style(sk, TCP)) 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 || if (info->snd_assoc_id == SCTP_FUTURE_ASSOC ||
info.snd_assoc_id == SCTP_ALL_ASSOC) { info->snd_assoc_id == SCTP_ALL_ASSOC) {
sp->default_stream = info.snd_sid; sp->default_stream = info->snd_sid;
sp->default_flags = info.snd_flags; sp->default_flags = info->snd_flags;
sp->default_ppid = info.snd_ppid; sp->default_ppid = info->snd_ppid;
sp->default_context = info.snd_context; sp->default_context = info->snd_context;
} }
if (info.snd_assoc_id == SCTP_CURRENT_ASSOC || if (info->snd_assoc_id == SCTP_CURRENT_ASSOC ||
info.snd_assoc_id == SCTP_ALL_ASSOC) { info->snd_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) { list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
asoc->default_stream = info.snd_sid; asoc->default_stream = info->snd_sid;
asoc->default_flags = info.snd_flags; asoc->default_flags = info->snd_flags;
asoc->default_ppid = info.snd_ppid; asoc->default_ppid = info->snd_ppid;
asoc->default_context = info.snd_context; asoc->default_context = info->snd_context;
} }
} }
...@@ -3040,10 +2982,9 @@ static int sctp_setsockopt_default_sndinfo(struct sock *sk, ...@@ -3040,10 +2982,9 @@ static int sctp_setsockopt_default_sndinfo(struct sock *sk,
* the association primary. The enclosed address must be one of the * the association primary. The enclosed address must be one of the
* association peer's addresses. * 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) unsigned int optlen)
{ {
struct sctp_prim prim;
struct sctp_transport *trans; struct sctp_transport *trans;
struct sctp_af *af; struct sctp_af *af;
int err; int err;
...@@ -3051,21 +2992,18 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, ...@@ -3051,21 +2992,18 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
if (optlen != sizeof(struct sctp_prim)) if (optlen != sizeof(struct sctp_prim))
return -EINVAL; return -EINVAL;
if (copy_from_user(&prim, optval, sizeof(struct sctp_prim)))
return -EFAULT;
/* Allow security module to validate address but need address len. */ /* 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) if (!af)
return -EINVAL; return -EINVAL;
err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR, err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR,
(struct sockaddr *)&prim.ssp_addr, (struct sockaddr *)&prim->ssp_addr,
af->sockaddr_len); af->sockaddr_len);
if (err) if (err)
return 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) if (!trans)
return -EINVAL; return -EINVAL;
...@@ -3082,17 +3020,12 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, ...@@ -3082,17 +3020,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 * introduced, at the cost of more packets in the network. Expects an
* integer boolean flag. * 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) unsigned int optlen)
{ {
int val;
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return -EINVAL; return -EINVAL;
if (get_user(val, (int __user *)optval)) sctp_sk(sk)->nodelay = (*val == 0) ? 0 : 1;
return -EFAULT;
sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1;
return 0; return 0;
} }
...@@ -3108,9 +3041,10 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval, ...@@ -3108,9 +3041,10 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
* be changed. * 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; struct sctp_association *asoc;
unsigned long rto_min, rto_max; unsigned long rto_min, rto_max;
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
...@@ -3118,18 +3052,15 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne ...@@ -3118,18 +3052,15 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne
if (optlen != sizeof (struct sctp_rtoinfo)) if (optlen != sizeof (struct sctp_rtoinfo))
return -EINVAL; return -EINVAL;
if (copy_from_user(&rtoinfo, optval, optlen)) asoc = sctp_id2assoc(sk, rtoinfo->srto_assoc_id);
return -EFAULT;
asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id);
/* Set the values to the specific association */ /* 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)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
rto_max = rtoinfo.srto_max; rto_max = rtoinfo->srto_max;
rto_min = rtoinfo.srto_min; rto_min = rtoinfo->srto_min;
if (rto_max) if (rto_max)
rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max; rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max;
...@@ -3145,17 +3076,17 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne ...@@ -3145,17 +3076,17 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne
return -EINVAL; return -EINVAL;
if (asoc) { if (asoc) {
if (rtoinfo.srto_initial != 0) if (rtoinfo->srto_initial != 0)
asoc->rto_initial = asoc->rto_initial =
msecs_to_jiffies(rtoinfo.srto_initial); msecs_to_jiffies(rtoinfo->srto_initial);
asoc->rto_max = rto_max; asoc->rto_max = rto_max;
asoc->rto_min = rto_min; asoc->rto_min = rto_min;
} else { } else {
/* If there is no association or the association-id = 0 /* If there is no association or the association-id = 0
* set the values to the endpoint. * set the values to the endpoint.
*/ */
if (rtoinfo.srto_initial != 0) if (rtoinfo->srto_initial != 0)
sp->rtoinfo.srto_initial = rtoinfo.srto_initial; sp->rtoinfo.srto_initial = rtoinfo->srto_initial;
sp->rtoinfo.srto_max = rto_max; sp->rtoinfo.srto_max = rto_max;
sp->rtoinfo.srto_min = rto_min; sp->rtoinfo.srto_min = rto_min;
} }
...@@ -3174,26 +3105,25 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne ...@@ -3174,26 +3105,25 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne
* See [SCTP] for more information. * 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; struct sctp_association *asoc;
if (optlen != sizeof(struct sctp_assocparams)) if (optlen != sizeof(struct sctp_assocparams))
return -EINVAL; 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)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
/* Set the values to the specific association */ /* Set the values to the specific association */
if (asoc) { if (asoc) {
if (assocparams.sasoc_asocmaxrxt != 0) { if (assocparams->sasoc_asocmaxrxt != 0) {
__u32 path_sum = 0; __u32 path_sum = 0;
int paths = 0; int paths = 0;
struct sctp_transport *peer_addr; struct sctp_transport *peer_addr;
...@@ -3210,24 +3140,25 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsig ...@@ -3210,24 +3140,25 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsig
* then one path. * then one path.
*/ */
if (paths > 1 && if (paths > 1 &&
assocparams.sasoc_asocmaxrxt > path_sum) assocparams->sasoc_asocmaxrxt > path_sum)
return -EINVAL; return -EINVAL;
asoc->max_retrans = assocparams.sasoc_asocmaxrxt; asoc->max_retrans = assocparams->sasoc_asocmaxrxt;
} }
if (assocparams.sasoc_cookie_life != 0) if (assocparams->sasoc_cookie_life != 0)
asoc->cookie_life = ms_to_ktime(assocparams.sasoc_cookie_life); asoc->cookie_life =
ms_to_ktime(assocparams->sasoc_cookie_life);
} else { } else {
/* Set the values to the endpoint */ /* Set the values to the endpoint */
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
if (assocparams.sasoc_asocmaxrxt != 0) if (assocparams->sasoc_asocmaxrxt != 0)
sp->assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt =
assocparams.sasoc_asocmaxrxt; assocparams->sasoc_asocmaxrxt;
if (assocparams.sasoc_cookie_life != 0) if (assocparams->sasoc_cookie_life != 0)
sp->assocparams.sasoc_cookie_life = sp->assocparams.sasoc_cookie_life =
assocparams.sasoc_cookie_life; assocparams->sasoc_cookie_life;
} }
return 0; return 0;
} }
...@@ -3242,16 +3173,14 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsig ...@@ -3242,16 +3173,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 and a user will receive both PF_INET6 and PF_INET type
* addresses on the socket. * 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); struct sctp_sock *sp = sctp_sk(sk);
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return -EINVAL; return -EINVAL;
if (get_user(val, (int __user *)optval)) if (*val)
return -EFAULT;
if (val)
sp->v4mapped = 1; sp->v4mapped = 1;
else else
sp->v4mapped = 0; sp->v4mapped = 0;
...@@ -3286,11 +3215,13 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign ...@@ -3286,11 +3215,13 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign
* changed (effecting future associations only). * changed (effecting future associations only).
* assoc_value: This parameter specifies the maximum size in bytes. * 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_sock *sp = sctp_sk(sk);
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
sctp_assoc_t assoc_id;
int val; int val;
if (optlen == sizeof(int)) { if (optlen == sizeof(int)) {
...@@ -3299,19 +3230,17 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned ...@@ -3299,19 +3230,17 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
"Use of int in maxseg socket option.\n" "Use of int in maxseg socket option.\n"
"Use struct sctp_assoc_value instead\n", "Use struct sctp_assoc_value instead\n",
current->comm, task_pid_nr(current)); current->comm, task_pid_nr(current));
if (copy_from_user(&val, optval, optlen)) assoc_id = SCTP_FUTURE_ASSOC;
return -EFAULT; val = *(int *)params;
params.assoc_id = SCTP_FUTURE_ASSOC;
} else if (optlen == sizeof(struct sctp_assoc_value)) { } else if (optlen == sizeof(struct sctp_assoc_value)) {
if (copy_from_user(&params, optval, optlen)) assoc_id = params->assoc_id;
return -EFAULT; val = params->assoc_value;
val = params.assoc_value;
} else { } else {
return -EINVAL; return -EINVAL;
} }
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && if (!asoc && assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
...@@ -3346,12 +3275,12 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned ...@@ -3346,12 +3275,12 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
* locally bound addresses. The following structure is used to make a * locally bound addresses. The following structure is used to make a
* set primary request: * 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) unsigned int optlen)
{ {
struct sctp_sock *sp; struct sctp_sock *sp;
struct sctp_association *asoc = NULL; struct sctp_association *asoc = NULL;
struct sctp_setpeerprim prim;
struct sctp_chunk *chunk; struct sctp_chunk *chunk;
struct sctp_af *af; struct sctp_af *af;
int err; int err;
...@@ -3364,10 +3293,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva ...@@ -3364,10 +3293,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
if (optlen != sizeof(struct sctp_setpeerprim)) if (optlen != sizeof(struct sctp_setpeerprim))
return -EINVAL; return -EINVAL;
if (copy_from_user(&prim, optval, optlen)) asoc = sctp_id2assoc(sk, prim->sspp_assoc_id);
return -EFAULT;
asoc = sctp_id2assoc(sk, prim.sspp_assoc_id);
if (!asoc) if (!asoc)
return -EINVAL; return -EINVAL;
...@@ -3380,26 +3306,26 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva ...@@ -3380,26 +3306,26 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
if (!sctp_state(asoc, ESTABLISHED)) if (!sctp_state(asoc, ESTABLISHED))
return -ENOTCONN; return -ENOTCONN;
af = sctp_get_af_specific(prim.sspp_addr.ss_family); af = sctp_get_af_specific(prim->sspp_addr.ss_family);
if (!af) if (!af)
return -EINVAL; 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; 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; return -EADDRNOTAVAIL;
/* Allow security module to validate address. */ /* Allow security module to validate address. */
err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR, err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR,
(struct sockaddr *)&prim.sspp_addr, (struct sockaddr *)&prim->sspp_addr,
af->sockaddr_len); af->sockaddr_len);
if (err) if (err)
return err; return err;
/* Create an ASCONF chunk with SET_PRIMARY parameter */ /* Create an ASCONF chunk with SET_PRIMARY parameter */
chunk = sctp_make_asconf_set_prim(asoc, chunk = sctp_make_asconf_set_prim(asoc,
(union sctp_addr *)&prim.sspp_addr); (union sctp_addr *)&prim->sspp_addr);
if (!chunk) if (!chunk)
return -ENOMEM; return -ENOMEM;
...@@ -3410,17 +3336,14 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva ...@@ -3410,17 +3336,14 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
return err; 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) unsigned int optlen)
{ {
struct sctp_setadaptation adaptation;
if (optlen != sizeof(struct sctp_setadaptation)) if (optlen != sizeof(struct sctp_setadaptation))
return -EINVAL; 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; return 0;
} }
...@@ -3439,40 +3362,38 @@ static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval ...@@ -3439,40 +3362,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 * received messages from the peer and does not effect the value that is
* saved with outbound messages. * 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) unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
if (optlen != sizeof(struct sctp_assoc_value)) if (optlen != sizeof(struct sctp_assoc_value))
return -EINVAL; return -EINVAL;
if (copy_from_user(&params, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, params->assoc_id);
if (!asoc && params.assoc_id > SCTP_ALL_ASSOC && if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) { if (asoc) {
asoc->default_rcv_context = params.assoc_value; asoc->default_rcv_context = params->assoc_value;
return 0; return 0;
} }
if (sctp_style(sk, TCP)) if (sctp_style(sk, TCP))
params.assoc_id = SCTP_FUTURE_ASSOC; params->assoc_id = SCTP_FUTURE_ASSOC;
if (params.assoc_id == SCTP_FUTURE_ASSOC || if (params->assoc_id == SCTP_FUTURE_ASSOC ||
params.assoc_id == SCTP_ALL_ASSOC) params->assoc_id == SCTP_ALL_ASSOC)
sp->default_rcv_context = params.assoc_value; sp->default_rcv_context = params->assoc_value;
if (params.assoc_id == SCTP_CURRENT_ASSOC || if (params->assoc_id == SCTP_CURRENT_ASSOC ||
params.assoc_id == SCTP_ALL_ASSOC) params->assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &sp->ep->asocs, asocs) 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; return 0;
} }
...@@ -3501,18 +3422,13 @@ static int sctp_setsockopt_context(struct sock *sk, char __user *optval, ...@@ -3501,18 +3422,13 @@ static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
* application using the one to many model may become confused and act * application using the one to many model may become confused and act
* incorrectly. * incorrectly.
*/ */
static int sctp_setsockopt_fragment_interleave(struct sock *sk, static int sctp_setsockopt_fragment_interleave(struct sock *sk, int *val,
char __user *optval,
unsigned int optlen) unsigned int optlen)
{ {
int val;
if (optlen != sizeof(int)) if (optlen != sizeof(int))
return -EINVAL; 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) if (!sctp_sk(sk)->frag_interleave)
sctp_sk(sk)->ep->intl_enable = 0; sctp_sk(sk)->ep->intl_enable = 0;
...@@ -3537,24 +3453,19 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk, ...@@ -3537,24 +3453,19 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk,
* call as long as the user provided buffer is large enough to hold the * call as long as the user provided buffer is large enough to hold the
* message. * message.
*/ */
static int sctp_setsockopt_partial_delivery_point(struct sock *sk, static int sctp_setsockopt_partial_delivery_point(struct sock *sk, u32 *val,
char __user *optval,
unsigned int optlen) unsigned int optlen)
{ {
u32 val;
if (optlen != sizeof(u32)) if (optlen != sizeof(u32))
return -EINVAL; return -EINVAL;
if (get_user(val, (int __user *)optval))
return -EFAULT;
/* Note: We double the receive buffer from what the user sets /* Note: We double the receive buffer from what the user sets
* it to be, also initial rwnd is based on rcvbuf/2. * 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; return -EINVAL;
sctp_sk(sk)->pd_point = val; sctp_sk(sk)->pd_point = *val;
return 0; /* is this the right error code? */ return 0; /* is this the right error code? */
} }
...@@ -3571,12 +3482,13 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk, ...@@ -3571,12 +3482,13 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
* future associations inheriting the socket value. * future associations inheriting the socket value.
*/ */
static int sctp_setsockopt_maxburst(struct sock *sk, static int sctp_setsockopt_maxburst(struct sock *sk,
char __user *optval, struct sctp_assoc_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
sctp_assoc_t assoc_id;
u32 assoc_value;
if (optlen == sizeof(int)) { if (optlen == sizeof(int)) {
pr_warn_ratelimited(DEPRECATED pr_warn_ratelimited(DEPRECATED
...@@ -3584,37 +3496,33 @@ static int sctp_setsockopt_maxburst(struct sock *sk, ...@@ -3584,37 +3496,33 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
"Use of int in max_burst socket option deprecated.\n" "Use of int in max_burst socket option deprecated.\n"
"Use struct sctp_assoc_value instead\n", "Use struct sctp_assoc_value instead\n",
current->comm, task_pid_nr(current)); current->comm, task_pid_nr(current));
if (copy_from_user(&params.assoc_value, optval, optlen)) assoc_id = SCTP_FUTURE_ASSOC;
return -EFAULT; assoc_value = *((int *)params);
params.assoc_id = SCTP_FUTURE_ASSOC;
} else if (optlen == sizeof(struct sctp_assoc_value)) { } else if (optlen == sizeof(struct sctp_assoc_value)) {
if (copy_from_user(&params, optval, optlen)) assoc_id = params->assoc_id;
return -EFAULT; assoc_value = params->assoc_value;
} else } else
return -EINVAL; return -EINVAL;
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, assoc_id);
if (!asoc && params.assoc_id > SCTP_ALL_ASSOC && if (!asoc && assoc_id > SCTP_ALL_ASSOC && sctp_style(sk, UDP))
sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) { if (asoc) {
asoc->max_burst = params.assoc_value; asoc->max_burst = assoc_value;
return 0; return 0;
} }
if (sctp_style(sk, TCP)) if (sctp_style(sk, TCP))
params.assoc_id = SCTP_FUTURE_ASSOC; assoc_id = SCTP_FUTURE_ASSOC;
if (params.assoc_id == SCTP_FUTURE_ASSOC || if (assoc_id == SCTP_FUTURE_ASSOC || assoc_id == SCTP_ALL_ASSOC)
params.assoc_id == SCTP_ALL_ASSOC) sp->max_burst = assoc_value;
sp->max_burst = params.assoc_value;
if (params.assoc_id == SCTP_CURRENT_ASSOC || if (assoc_id == SCTP_CURRENT_ASSOC || assoc_id == SCTP_ALL_ASSOC)
params.assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &sp->ep->asocs, asocs) list_for_each_entry(asoc, &sp->ep->asocs, asocs)
asoc->max_burst = params.assoc_value; asoc->max_burst = assoc_value;
return 0; return 0;
} }
...@@ -3627,21 +3535,18 @@ static int sctp_setsockopt_maxburst(struct sock *sk, ...@@ -3627,21 +3535,18 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
* will only effect future associations on the socket. * will only effect future associations on the socket.
*/ */
static int sctp_setsockopt_auth_chunk(struct sock *sk, static int sctp_setsockopt_auth_chunk(struct sock *sk,
char __user *optval, struct sctp_authchunk *val,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_endpoint *ep = sctp_sk(sk)->ep; struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_authchunk val;
if (!ep->auth_enable) if (!ep->auth_enable)
return -EACCES; return -EACCES;
if (optlen != sizeof(struct sctp_authchunk)) if (optlen != sizeof(struct sctp_authchunk))
return -EINVAL; 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:
case SCTP_CID_INIT_ACK: case SCTP_CID_INIT_ACK:
case SCTP_CID_SHUTDOWN_COMPLETE: case SCTP_CID_SHUTDOWN_COMPLETE:
...@@ -3650,7 +3555,7 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk, ...@@ -3650,7 +3555,7 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,
} }
/* add this chunk id to the endpoint */ /* 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 +3565,11 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk, ...@@ -3660,13 +3565,11 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,
* endpoint requires the peer to use. * endpoint requires the peer to use.
*/ */
static int sctp_setsockopt_hmac_ident(struct sock *sk, static int sctp_setsockopt_hmac_ident(struct sock *sk,
char __user *optval, struct sctp_hmacalgo *hmacs,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_endpoint *ep = sctp_sk(sk)->ep; struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_hmacalgo *hmacs;
u32 idents; u32 idents;
int err;
if (!ep->auth_enable) if (!ep->auth_enable)
return -EACCES; return -EACCES;
...@@ -3676,21 +3579,12 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, ...@@ -3676,21 +3579,12 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) + optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) +
SCTP_AUTH_NUM_HMACS * sizeof(u16)); SCTP_AUTH_NUM_HMACS * sizeof(u16));
hmacs = memdup_user(optval, optlen);
if (IS_ERR(hmacs))
return PTR_ERR(hmacs);
idents = hmacs->shmac_num_idents; idents = hmacs->shmac_num_idents;
if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS ||
(idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) { (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo)))
err = -EINVAL; return -EINVAL;
goto out;
}
err = sctp_auth_ep_set_hmacs(ep, hmacs); return sctp_auth_ep_set_hmacs(ep, hmacs);
out:
kfree(hmacs);
return err;
} }
/* /*
...@@ -3700,11 +3594,10 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, ...@@ -3700,11 +3594,10 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
* association shared key. * association shared key.
*/ */
static int sctp_setsockopt_auth_key(struct sock *sk, static int sctp_setsockopt_auth_key(struct sock *sk,
char __user *optval, struct sctp_authkey *authkey,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_endpoint *ep = sctp_sk(sk)->ep; struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_authkey *authkey;
struct sctp_association *asoc; struct sctp_association *asoc;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -3715,10 +3608,6 @@ static int sctp_setsockopt_auth_key(struct sock *sk, ...@@ -3715,10 +3608,6 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
*/ */
optlen = min_t(unsigned int, optlen, USHRT_MAX + sizeof(*authkey)); 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)) if (authkey->sca_keylength > optlen - sizeof(*authkey))
goto out; goto out;
...@@ -3755,7 +3644,7 @@ static int sctp_setsockopt_auth_key(struct sock *sk, ...@@ -3755,7 +3644,7 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
} }
out: out:
kzfree(authkey); memzero_explicit(authkey, optlen);
return ret; return ret;
} }
...@@ -3766,42 +3655,39 @@ static int sctp_setsockopt_auth_key(struct sock *sk, ...@@ -3766,42 +3655,39 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
* the association shared key. * the association shared key.
*/ */
static int sctp_setsockopt_active_key(struct sock *sk, static int sctp_setsockopt_active_key(struct sock *sk,
char __user *optval, struct sctp_authkeyid *val,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_endpoint *ep = sctp_sk(sk)->ep; struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_authkeyid val;
int ret = 0; int ret = 0;
if (optlen != sizeof(struct sctp_authkeyid)) if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL; return -EINVAL;
if (copy_from_user(&val, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, val.scact_assoc_id); asoc = sctp_id2assoc(sk, val->scact_assoc_id);
if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC && if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) 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)) 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 || if (val->scact_assoc_id == SCTP_FUTURE_ASSOC ||
val.scact_assoc_id == SCTP_ALL_ASSOC) { val->scact_assoc_id == SCTP_ALL_ASSOC) {
ret = sctp_auth_set_active_key(ep, asoc, val.scact_keynumber); ret = sctp_auth_set_active_key(ep, asoc, val->scact_keynumber);
if (ret) if (ret)
return ret; return ret;
} }
if (val.scact_assoc_id == SCTP_CURRENT_ASSOC || if (val->scact_assoc_id == SCTP_CURRENT_ASSOC ||
val.scact_assoc_id == SCTP_ALL_ASSOC) { val->scact_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &ep->asocs, asocs) { list_for_each_entry(asoc, &ep->asocs, asocs) {
int res = sctp_auth_set_active_key(ep, asoc, int res = sctp_auth_set_active_key(ep, asoc,
val.scact_keynumber); val->scact_keynumber);
if (res && !ret) if (res && !ret)
ret = res; ret = res;
...@@ -3817,42 +3703,39 @@ static int sctp_setsockopt_active_key(struct sock *sk, ...@@ -3817,42 +3703,39 @@ static int sctp_setsockopt_active_key(struct sock *sk,
* This set option will delete a shared secret key from use. * This set option will delete a shared secret key from use.
*/ */
static int sctp_setsockopt_del_key(struct sock *sk, static int sctp_setsockopt_del_key(struct sock *sk,
char __user *optval, struct sctp_authkeyid *val,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_endpoint *ep = sctp_sk(sk)->ep; struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_authkeyid val;
int ret = 0; int ret = 0;
if (optlen != sizeof(struct sctp_authkeyid)) if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL; return -EINVAL;
if (copy_from_user(&val, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, val.scact_assoc_id); asoc = sctp_id2assoc(sk, val->scact_assoc_id);
if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC && if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) 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)) 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 || if (val->scact_assoc_id == SCTP_FUTURE_ASSOC ||
val.scact_assoc_id == SCTP_ALL_ASSOC) { val->scact_assoc_id == SCTP_ALL_ASSOC) {
ret = sctp_auth_del_key_id(ep, asoc, val.scact_keynumber); ret = sctp_auth_del_key_id(ep, asoc, val->scact_keynumber);
if (ret) if (ret)
return ret; return ret;
} }
if (val.scact_assoc_id == SCTP_CURRENT_ASSOC || if (val->scact_assoc_id == SCTP_CURRENT_ASSOC ||
val.scact_assoc_id == SCTP_ALL_ASSOC) { val->scact_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &ep->asocs, asocs) { list_for_each_entry(asoc, &ep->asocs, asocs) {
int res = sctp_auth_del_key_id(ep, asoc, int res = sctp_auth_del_key_id(ep, asoc,
val.scact_keynumber); val->scact_keynumber);
if (res && !ret) if (res && !ret)
ret = res; ret = res;
...@@ -3867,42 +3750,40 @@ static int sctp_setsockopt_del_key(struct sock *sk, ...@@ -3867,42 +3750,40 @@ static int sctp_setsockopt_del_key(struct sock *sk,
* *
* This set option will deactivate a shared secret key. * 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) unsigned int optlen)
{ {
struct sctp_endpoint *ep = sctp_sk(sk)->ep; struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_authkeyid val;
int ret = 0; int ret = 0;
if (optlen != sizeof(struct sctp_authkeyid)) if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL; return -EINVAL;
if (copy_from_user(&val, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, val.scact_assoc_id); asoc = sctp_id2assoc(sk, val->scact_assoc_id);
if (!asoc && val.scact_assoc_id > SCTP_ALL_ASSOC && if (!asoc && val->scact_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) 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)) 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 || if (val->scact_assoc_id == SCTP_FUTURE_ASSOC ||
val.scact_assoc_id == SCTP_ALL_ASSOC) { val->scact_assoc_id == SCTP_ALL_ASSOC) {
ret = sctp_auth_deact_key_id(ep, asoc, val.scact_keynumber); ret = sctp_auth_deact_key_id(ep, asoc, val->scact_keynumber);
if (ret) if (ret)
return ret; return ret;
} }
if (val.scact_assoc_id == SCTP_CURRENT_ASSOC || if (val->scact_assoc_id == SCTP_CURRENT_ASSOC ||
val.scact_assoc_id == SCTP_ALL_ASSOC) { val->scact_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &ep->asocs, asocs) { list_for_each_entry(asoc, &ep->asocs, asocs) {
int res = sctp_auth_deact_key_id(ep, asoc, int res = sctp_auth_deact_key_id(ep, asoc,
val.scact_keynumber); val->scact_keynumber);
if (res && !ret) if (res && !ret)
ret = res; ret = res;
...@@ -3926,26 +3807,23 @@ static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval, ...@@ -3926,26 +3807,23 @@ static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval,
* Note. In this implementation, socket operation overrides default parameter * Note. In this implementation, socket operation overrides default parameter
* being set by sysctl as well as FreeBSD implementation * 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) unsigned int optlen)
{ {
int val;
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return -EINVAL; return -EINVAL;
if (get_user(val, (int __user *)optval)) if (!sctp_is_ep_boundall(sk) && *val)
return -EFAULT;
if (!sctp_is_ep_boundall(sk) && val)
return -EINVAL; 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; return 0;
spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock); 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); list_del(&sp->auto_asconf_list);
sp->do_auto_asconf = 0; 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, list_add_tail(&sp->auto_asconf_list,
&sock_net(sk)->sctp.auto_asconf_splist); &sock_net(sk)->sctp.auto_asconf_splist);
sp->do_auto_asconf = 1; sp->do_auto_asconf = 1;
...@@ -3962,176 +3840,154 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, ...@@ -3962,176 +3840,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 * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt
*/ */
static int sctp_setsockopt_paddr_thresholds(struct sock *sk, static int sctp_setsockopt_paddr_thresholds(struct sock *sk,
char __user *optval, struct sctp_paddrthlds_v2 *val,
unsigned int optlen, bool v2) unsigned int optlen, bool v2)
{ {
struct sctp_paddrthlds_v2 val;
struct sctp_transport *trans; struct sctp_transport *trans;
struct sctp_association *asoc; struct sctp_association *asoc;
int len; int len;
len = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds); len = v2 ? sizeof(*val) : sizeof(struct sctp_paddrthlds);
if (optlen < len) if (optlen < len)
return -EINVAL; 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; return -EINVAL;
if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { if (!sctp_is_any(sk, (const union sctp_addr *)&val->spt_address)) {
trans = sctp_addr_id2transport(sk, &val.spt_address, trans = sctp_addr_id2transport(sk, &val->spt_address,
val.spt_assoc_id); val->spt_assoc_id);
if (!trans) if (!trans)
return -ENOENT; return -ENOENT;
if (val.spt_pathmaxrxt) if (val->spt_pathmaxrxt)
trans->pathmaxrxt = val.spt_pathmaxrxt; trans->pathmaxrxt = val->spt_pathmaxrxt;
if (v2) if (v2)
trans->ps_retrans = val.spt_pathcpthld; trans->ps_retrans = val->spt_pathcpthld;
trans->pf_retrans = val.spt_pathpfthld; trans->pf_retrans = val->spt_pathpfthld;
return 0; return 0;
} }
asoc = sctp_id2assoc(sk, val.spt_assoc_id); asoc = sctp_id2assoc(sk, val->spt_assoc_id);
if (!asoc && val.spt_assoc_id != SCTP_FUTURE_ASSOC && if (!asoc && val->spt_assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) { if (asoc) {
list_for_each_entry(trans, &asoc->peer.transport_addr_list, list_for_each_entry(trans, &asoc->peer.transport_addr_list,
transports) { transports) {
if (val.spt_pathmaxrxt) if (val->spt_pathmaxrxt)
trans->pathmaxrxt = val.spt_pathmaxrxt; trans->pathmaxrxt = val->spt_pathmaxrxt;
if (v2) if (v2)
trans->ps_retrans = val.spt_pathcpthld; trans->ps_retrans = val->spt_pathcpthld;
trans->pf_retrans = val.spt_pathpfthld; trans->pf_retrans = val->spt_pathpfthld;
} }
if (val.spt_pathmaxrxt) if (val->spt_pathmaxrxt)
asoc->pathmaxrxt = val.spt_pathmaxrxt; asoc->pathmaxrxt = val->spt_pathmaxrxt;
if (v2) if (v2)
asoc->ps_retrans = val.spt_pathcpthld; asoc->ps_retrans = val->spt_pathcpthld;
asoc->pf_retrans = val.spt_pathpfthld; asoc->pf_retrans = val->spt_pathpfthld;
} else { } else {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
if (val.spt_pathmaxrxt) if (val->spt_pathmaxrxt)
sp->pathmaxrxt = val.spt_pathmaxrxt; sp->pathmaxrxt = val->spt_pathmaxrxt;
if (v2) if (v2)
sp->ps_retrans = val.spt_pathcpthld; sp->ps_retrans = val->spt_pathcpthld;
sp->pf_retrans = val.spt_pathpfthld; sp->pf_retrans = val->spt_pathpfthld;
} }
return 0; return 0;
} }
static int sctp_setsockopt_recvrcvinfo(struct sock *sk, static int sctp_setsockopt_recvrcvinfo(struct sock *sk, int *val,
char __user *optval,
unsigned int optlen) unsigned int optlen)
{ {
int val;
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return -EINVAL; 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; return 0;
} }
static int sctp_setsockopt_recvnxtinfo(struct sock *sk, static int sctp_setsockopt_recvnxtinfo(struct sock *sk, int *val,
char __user *optval,
unsigned int optlen) unsigned int optlen)
{ {
int val;
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return -EINVAL; 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; return 0;
} }
static int sctp_setsockopt_pr_supported(struct sock *sk, static int sctp_setsockopt_pr_supported(struct sock *sk,
char __user *optval, struct sctp_assoc_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
if (optlen != sizeof(params)) if (optlen != sizeof(*params))
return -EINVAL; return -EINVAL;
if (copy_from_user(&params, optval, optlen)) asoc = sctp_id2assoc(sk, params->assoc_id);
return -EFAULT; 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)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
sctp_sk(sk)->ep->prsctp_enable = !!params.assoc_value; sctp_sk(sk)->ep->prsctp_enable = !!params->assoc_value;
return 0; return 0;
} }
static int sctp_setsockopt_default_prinfo(struct sock *sk, static int sctp_setsockopt_default_prinfo(struct sock *sk,
char __user *optval, struct sctp_default_prinfo *info,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_default_prinfo info;
struct sctp_association *asoc; struct sctp_association *asoc;
int retval = -EINVAL; int retval = -EINVAL;
if (optlen != sizeof(info)) if (optlen != sizeof(*info))
goto out;
if (copy_from_user(&info, optval, sizeof(info))) {
retval = -EFAULT;
goto out; goto out;
}
if (info.pr_policy & ~SCTP_PR_SCTP_MASK) if (info->pr_policy & ~SCTP_PR_SCTP_MASK)
goto out; goto out;
if (info.pr_policy == SCTP_PR_SCTP_NONE) if (info->pr_policy == SCTP_PR_SCTP_NONE)
info.pr_value = 0; info->pr_value = 0;
asoc = sctp_id2assoc(sk, info.pr_assoc_id); asoc = sctp_id2assoc(sk, info->pr_assoc_id);
if (!asoc && info.pr_assoc_id > SCTP_ALL_ASSOC && if (!asoc && info->pr_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
goto out; goto out;
retval = 0; retval = 0;
if (asoc) { if (asoc) {
SCTP_PR_SET_POLICY(asoc->default_flags, info.pr_policy); SCTP_PR_SET_POLICY(asoc->default_flags, info->pr_policy);
asoc->default_timetolive = info.pr_value; asoc->default_timetolive = info->pr_value;
goto out; goto out;
} }
if (sctp_style(sk, TCP)) 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 || if (info->pr_assoc_id == SCTP_FUTURE_ASSOC ||
info.pr_assoc_id == SCTP_ALL_ASSOC) { info->pr_assoc_id == SCTP_ALL_ASSOC) {
SCTP_PR_SET_POLICY(sp->default_flags, info.pr_policy); SCTP_PR_SET_POLICY(sp->default_flags, info->pr_policy);
sp->default_timetolive = info.pr_value; sp->default_timetolive = info->pr_value;
} }
if (info.pr_assoc_id == SCTP_CURRENT_ASSOC || if (info->pr_assoc_id == SCTP_CURRENT_ASSOC ||
info.pr_assoc_id == SCTP_ALL_ASSOC) { info->pr_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) { list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
SCTP_PR_SET_POLICY(asoc->default_flags, info.pr_policy); SCTP_PR_SET_POLICY(asoc->default_flags,
asoc->default_timetolive = info.pr_value; info->pr_policy);
asoc->default_timetolive = info->pr_value;
} }
} }
...@@ -4140,27 +3996,21 @@ static int sctp_setsockopt_default_prinfo(struct sock *sk, ...@@ -4140,27 +3996,21 @@ static int sctp_setsockopt_default_prinfo(struct sock *sk,
} }
static int sctp_setsockopt_reconfig_supported(struct sock *sk, static int sctp_setsockopt_reconfig_supported(struct sock *sk,
char __user *optval, struct sctp_assoc_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
int retval = -EINVAL; int retval = -EINVAL;
if (optlen != sizeof(params)) if (optlen != sizeof(*params))
goto out; goto out;
if (copy_from_user(&params, optval, optlen)) { asoc = sctp_id2assoc(sk, params->assoc_id);
retval = -EFAULT; if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
goto out;
}
asoc = sctp_id2assoc(sk, params.assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
goto out; goto out;
sctp_sk(sk)->ep->reconf_enable = !!params.assoc_value; sctp_sk(sk)->ep->reconf_enable = !!params->assoc_value;
retval = 0; retval = 0;
...@@ -4169,60 +4019,52 @@ static int sctp_setsockopt_reconfig_supported(struct sock *sk, ...@@ -4169,60 +4019,52 @@ static int sctp_setsockopt_reconfig_supported(struct sock *sk,
} }
static int sctp_setsockopt_enable_strreset(struct sock *sk, static int sctp_setsockopt_enable_strreset(struct sock *sk,
char __user *optval, struct sctp_assoc_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_endpoint *ep = sctp_sk(sk)->ep; struct sctp_endpoint *ep = sctp_sk(sk)->ep;
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
int retval = -EINVAL; int retval = -EINVAL;
if (optlen != sizeof(params)) if (optlen != sizeof(*params))
goto out;
if (copy_from_user(&params, optval, optlen)) {
retval = -EFAULT;
goto out; goto out;
}
if (params.assoc_value & (~SCTP_ENABLE_STRRESET_MASK)) if (params->assoc_value & (~SCTP_ENABLE_STRRESET_MASK))
goto out; goto out;
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, params->assoc_id);
if (!asoc && params.assoc_id > SCTP_ALL_ASSOC && if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
goto out; goto out;
retval = 0; retval = 0;
if (asoc) { if (asoc) {
asoc->strreset_enable = params.assoc_value; asoc->strreset_enable = params->assoc_value;
goto out; goto out;
} }
if (sctp_style(sk, TCP)) if (sctp_style(sk, TCP))
params.assoc_id = SCTP_FUTURE_ASSOC; params->assoc_id = SCTP_FUTURE_ASSOC;
if (params.assoc_id == SCTP_FUTURE_ASSOC || if (params->assoc_id == SCTP_FUTURE_ASSOC ||
params.assoc_id == SCTP_ALL_ASSOC) params->assoc_id == SCTP_ALL_ASSOC)
ep->strreset_enable = params.assoc_value; ep->strreset_enable = params->assoc_value;
if (params.assoc_id == SCTP_CURRENT_ASSOC || if (params->assoc_id == SCTP_CURRENT_ASSOC ||
params.assoc_id == SCTP_ALL_ASSOC) params->assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &ep->asocs, asocs) list_for_each_entry(asoc, &ep->asocs, asocs)
asoc->strreset_enable = params.assoc_value; asoc->strreset_enable = params->assoc_value;
out: out:
return retval; return retval;
} }
static int sctp_setsockopt_reset_streams(struct sock *sk, static int sctp_setsockopt_reset_streams(struct sock *sk,
char __user *optval, struct sctp_reset_streams *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_reset_streams *params;
struct sctp_association *asoc; struct sctp_association *asoc;
int retval = -EINVAL;
if (optlen < sizeof(*params)) if (optlen < sizeof(*params))
return -EINVAL; return -EINVAL;
...@@ -4230,116 +4072,82 @@ static int sctp_setsockopt_reset_streams(struct sock *sk, ...@@ -4230,116 +4072,82 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,
optlen = min_t(unsigned int, optlen, USHRT_MAX + optlen = min_t(unsigned int, optlen, USHRT_MAX +
sizeof(__u16) * sizeof(*params)); sizeof(__u16) * sizeof(*params));
params = memdup_user(optval, optlen);
if (IS_ERR(params))
return PTR_ERR(params);
if (params->srs_number_streams * sizeof(__u16) > if (params->srs_number_streams * sizeof(__u16) >
optlen - sizeof(*params)) optlen - sizeof(*params))
goto out; return -EINVAL;
asoc = sctp_id2assoc(sk, params->srs_assoc_id); asoc = sctp_id2assoc(sk, params->srs_assoc_id);
if (!asoc) if (!asoc)
goto out; return -EINVAL;
retval = sctp_send_reset_streams(asoc, params);
out: return sctp_send_reset_streams(asoc, params);
kfree(params);
return retval;
} }
static int sctp_setsockopt_reset_assoc(struct sock *sk, static int sctp_setsockopt_reset_assoc(struct sock *sk, sctp_assoc_t *associd,
char __user *optval,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_association *asoc; struct sctp_association *asoc;
sctp_assoc_t associd;
int retval = -EINVAL;
if (optlen != sizeof(associd))
goto out;
if (copy_from_user(&associd, optval, optlen)) { if (optlen != sizeof(*associd))
retval = -EFAULT; return -EINVAL;
goto out;
}
asoc = sctp_id2assoc(sk, associd); asoc = sctp_id2assoc(sk, *associd);
if (!asoc) if (!asoc)
goto out; return -EINVAL;
retval = sctp_send_reset_assoc(asoc);
out: return sctp_send_reset_assoc(asoc);
return retval;
} }
static int sctp_setsockopt_add_streams(struct sock *sk, static int sctp_setsockopt_add_streams(struct sock *sk,
char __user *optval, struct sctp_add_streams *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_add_streams params;
int retval = -EINVAL;
if (optlen != sizeof(params)) if (optlen != sizeof(*params))
goto out; return -EINVAL;
if (copy_from_user(&params, optval, optlen)) {
retval = -EFAULT;
goto out;
}
asoc = sctp_id2assoc(sk, params.sas_assoc_id); asoc = sctp_id2assoc(sk, params->sas_assoc_id);
if (!asoc) if (!asoc)
goto out; return -EINVAL;
retval = sctp_send_add_streams(asoc, &params);
out: return sctp_send_add_streams(asoc, params);
return retval;
} }
static int sctp_setsockopt_scheduler(struct sock *sk, static int sctp_setsockopt_scheduler(struct sock *sk,
char __user *optval, struct sctp_assoc_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_assoc_value params;
int retval = 0; int retval = 0;
if (optlen < sizeof(params)) if (optlen < sizeof(*params))
return -EINVAL; return -EINVAL;
optlen = sizeof(params); if (params->assoc_value > SCTP_SS_MAX)
if (copy_from_user(&params, optval, optlen))
return -EFAULT;
if (params.assoc_value > SCTP_SS_MAX)
return -EINVAL; return -EINVAL;
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, params->assoc_id);
if (!asoc && params.assoc_id > SCTP_ALL_ASSOC && if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) 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)) if (sctp_style(sk, TCP))
params.assoc_id = SCTP_FUTURE_ASSOC; params->assoc_id = SCTP_FUTURE_ASSOC;
if (params.assoc_id == SCTP_FUTURE_ASSOC || if (params->assoc_id == SCTP_FUTURE_ASSOC ||
params.assoc_id == SCTP_ALL_ASSOC) params->assoc_id == SCTP_ALL_ASSOC)
sp->default_ss = params.assoc_value; sp->default_ss = params->assoc_value;
if (params.assoc_id == SCTP_CURRENT_ASSOC || if (params->assoc_id == SCTP_CURRENT_ASSOC ||
params.assoc_id == SCTP_ALL_ASSOC) { params->assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) { list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
int ret = sctp_sched_set_sched(asoc, int ret = sctp_sched_set_sched(asoc,
params.assoc_value); params->assoc_value);
if (ret && !retval) if (ret && !retval)
retval = ret; retval = ret;
...@@ -4350,38 +4158,32 @@ static int sctp_setsockopt_scheduler(struct sock *sk, ...@@ -4350,38 +4158,32 @@ static int sctp_setsockopt_scheduler(struct sock *sk,
} }
static int sctp_setsockopt_scheduler_value(struct sock *sk, static int sctp_setsockopt_scheduler_value(struct sock *sk,
char __user *optval, struct sctp_stream_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_stream_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
int retval = -EINVAL; int retval = -EINVAL;
if (optlen < sizeof(params)) if (optlen < sizeof(*params))
goto out;
optlen = sizeof(params);
if (copy_from_user(&params, optval, optlen)) {
retval = -EFAULT;
goto out; goto out;
}
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, params->assoc_id);
if (!asoc && params.assoc_id != SCTP_CURRENT_ASSOC && if (!asoc && params->assoc_id != SCTP_CURRENT_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
goto out; goto out;
if (asoc) { if (asoc) {
retval = sctp_sched_set_value(asoc, params.stream_id, retval = sctp_sched_set_value(asoc, params->stream_id,
params.stream_value, GFP_KERNEL); params->stream_value, GFP_KERNEL);
goto out; goto out;
} }
retval = 0; retval = 0;
list_for_each_entry(asoc, &sctp_sk(sk)->ep->asocs, asocs) { list_for_each_entry(asoc, &sctp_sk(sk)->ep->asocs, asocs) {
int ret = sctp_sched_set_value(asoc, params.stream_id, int ret = sctp_sched_set_value(asoc, params->stream_id,
params.stream_value, GFP_KERNEL); params->stream_value,
GFP_KERNEL);
if (ret && !retval) /* try to return the 1st error. */ if (ret && !retval) /* try to return the 1st error. */
retval = ret; retval = ret;
} }
...@@ -4391,46 +4193,30 @@ static int sctp_setsockopt_scheduler_value(struct sock *sk, ...@@ -4391,46 +4193,30 @@ static int sctp_setsockopt_scheduler_value(struct sock *sk,
} }
static int sctp_setsockopt_interleaving_supported(struct sock *sk, static int sctp_setsockopt_interleaving_supported(struct sock *sk,
char __user *optval, struct sctp_assoc_value *p,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
int retval = -EINVAL;
if (optlen < sizeof(params)) if (optlen < sizeof(*p))
goto out; return -EINVAL;
optlen = sizeof(params);
if (copy_from_user(&params, optval, optlen)) {
retval = -EFAULT;
goto out;
}
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, p->assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && if (!asoc && p->assoc_id != SCTP_FUTURE_ASSOC && sctp_style(sk, UDP))
sctp_style(sk, UDP)) return -EINVAL;
goto out;
if (!sock_net(sk)->sctp.intl_enable || !sp->frag_interleave) { if (!sock_net(sk)->sctp.intl_enable || !sp->frag_interleave) {
retval = -EPERM; return -EPERM;
goto out;
} }
sp->ep->intl_enable = !!params.assoc_value; sp->ep->intl_enable = !!p->assoc_value;
return 0;
retval = 0;
out:
return retval;
} }
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) unsigned int optlen)
{ {
int val;
if (!sctp_style(sk, TCP)) if (!sctp_style(sk, TCP))
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -4440,10 +4226,7 @@ static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval, ...@@ -4440,10 +4226,7 @@ static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval,
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return -EINVAL; return -EINVAL;
if (get_user(val, (int __user *)optval)) sctp_sk(sk)->reuse = !!*val;
return -EFAULT;
sctp_sk(sk)->reuse = !!val;
return 0; return 0;
} }
...@@ -4469,45 +4252,40 @@ static int sctp_assoc_ulpevent_type_set(struct sctp_event *param, ...@@ -4469,45 +4252,40 @@ static int sctp_assoc_ulpevent_type_set(struct sctp_event *param,
return 0; 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) unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_event param;
int retval = 0; int retval = 0;
if (optlen < sizeof(param)) if (optlen < sizeof(*param))
return -EINVAL; return -EINVAL;
optlen = sizeof(param); if (param->se_type < SCTP_SN_TYPE_BASE ||
if (copy_from_user(&param, optval, optlen)) param->se_type > SCTP_SN_TYPE_MAX)
return -EFAULT;
if (param.se_type < SCTP_SN_TYPE_BASE ||
param.se_type > SCTP_SN_TYPE_MAX)
return -EINVAL; return -EINVAL;
asoc = sctp_id2assoc(sk, param.se_assoc_id); asoc = sctp_id2assoc(sk, param->se_assoc_id);
if (!asoc && param.se_assoc_id > SCTP_ALL_ASSOC && if (!asoc && param->se_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) if (asoc)
return sctp_assoc_ulpevent_type_set(&param, asoc); return sctp_assoc_ulpevent_type_set(param, asoc);
if (sctp_style(sk, TCP)) 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 || if (param->se_assoc_id == SCTP_FUTURE_ASSOC ||
param.se_assoc_id == SCTP_ALL_ASSOC) param->se_assoc_id == SCTP_ALL_ASSOC)
sctp_ulpevent_type_set(&sp->subscribe, 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 || if (param->se_assoc_id == SCTP_CURRENT_ASSOC ||
param.se_assoc_id == SCTP_ALL_ASSOC) { param->se_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) { 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) if (ret && !retval)
retval = ret; retval = ret;
...@@ -4518,29 +4296,23 @@ static int sctp_setsockopt_event(struct sock *sk, char __user *optval, ...@@ -4518,29 +4296,23 @@ static int sctp_setsockopt_event(struct sock *sk, char __user *optval,
} }
static int sctp_setsockopt_asconf_supported(struct sock *sk, static int sctp_setsockopt_asconf_supported(struct sock *sk,
char __user *optval, struct sctp_assoc_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
int retval = -EINVAL; int retval = -EINVAL;
if (optlen != sizeof(params)) if (optlen != sizeof(*params))
goto out;
if (copy_from_user(&params, optval, optlen)) {
retval = -EFAULT;
goto out; goto out;
}
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, params->assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
goto out; goto out;
ep = sctp_sk(sk)->ep; ep = sctp_sk(sk)->ep;
ep->asconf_enable = !!params.assoc_value; ep->asconf_enable = !!params->assoc_value;
if (ep->asconf_enable && ep->auth_enable) { if (ep->asconf_enable && ep->auth_enable) {
sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF); sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
...@@ -4554,29 +4326,23 @@ static int sctp_setsockopt_asconf_supported(struct sock *sk, ...@@ -4554,29 +4326,23 @@ static int sctp_setsockopt_asconf_supported(struct sock *sk,
} }
static int sctp_setsockopt_auth_supported(struct sock *sk, static int sctp_setsockopt_auth_supported(struct sock *sk,
char __user *optval, struct sctp_assoc_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
int retval = -EINVAL; int retval = -EINVAL;
if (optlen != sizeof(params)) if (optlen != sizeof(*params))
goto out;
if (copy_from_user(&params, optval, optlen)) {
retval = -EFAULT;
goto out; goto out;
}
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, params->assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC && if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
goto out; goto out;
ep = sctp_sk(sk)->ep; ep = sctp_sk(sk)->ep;
if (params.assoc_value) { if (params->assoc_value) {
retval = sctp_auth_init(ep, GFP_KERNEL); retval = sctp_auth_init(ep, GFP_KERNEL);
if (retval) if (retval)
goto out; goto out;
...@@ -4586,7 +4352,7 @@ static int sctp_setsockopt_auth_supported(struct sock *sk, ...@@ -4586,7 +4352,7 @@ static int sctp_setsockopt_auth_supported(struct sock *sk,
} }
} }
ep->auth_enable = !!params.assoc_value; ep->auth_enable = !!params->assoc_value;
retval = 0; retval = 0;
out: out:
...@@ -4594,27 +4360,21 @@ static int sctp_setsockopt_auth_supported(struct sock *sk, ...@@ -4594,27 +4360,21 @@ static int sctp_setsockopt_auth_supported(struct sock *sk,
} }
static int sctp_setsockopt_ecn_supported(struct sock *sk, static int sctp_setsockopt_ecn_supported(struct sock *sk,
char __user *optval, struct sctp_assoc_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
int retval = -EINVAL; int retval = -EINVAL;
if (optlen != sizeof(params)) if (optlen != sizeof(*params))
goto out; goto out;
if (copy_from_user(&params, optval, optlen)) { asoc = sctp_id2assoc(sk, params->assoc_id);
retval = -EFAULT; if (!asoc && params->assoc_id != SCTP_FUTURE_ASSOC &&
goto out;
}
asoc = sctp_id2assoc(sk, params.assoc_id);
if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP)) sctp_style(sk, UDP))
goto out; goto out;
sctp_sk(sk)->ep->ecn_enable = !!params.assoc_value; sctp_sk(sk)->ep->ecn_enable = !!params->assoc_value;
retval = 0; retval = 0;
out: out:
...@@ -4622,33 +4382,27 @@ static int sctp_setsockopt_ecn_supported(struct sock *sk, ...@@ -4622,33 +4382,27 @@ static int sctp_setsockopt_ecn_supported(struct sock *sk,
} }
static int sctp_setsockopt_pf_expose(struct sock *sk, static int sctp_setsockopt_pf_expose(struct sock *sk,
char __user *optval, struct sctp_assoc_value *params,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
int retval = -EINVAL; int retval = -EINVAL;
if (optlen != sizeof(params)) if (optlen != sizeof(*params))
goto out; goto out;
if (copy_from_user(&params, optval, optlen)) { if (params->assoc_value > SCTP_PF_EXPOSE_MAX)
retval = -EFAULT;
goto out; goto out;
}
if (params.assoc_value > SCTP_PF_EXPOSE_MAX) asoc = sctp_id2assoc(sk, params->assoc_id);
goto out; 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)) sctp_style(sk, UDP))
goto out; goto out;
if (asoc) if (asoc)
asoc->pf_expose = params.assoc_value; asoc->pf_expose = params->assoc_value;
else else
sctp_sk(sk)->pf_expose = params.assoc_value; sctp_sk(sk)->pf_expose = params->assoc_value;
retval = 0; retval = 0;
out: out:
...@@ -4677,6 +4431,7 @@ static int sctp_setsockopt_pf_expose(struct sock *sk, ...@@ -4677,6 +4431,7 @@ static int sctp_setsockopt_pf_expose(struct sock *sk,
static int sctp_setsockopt(struct sock *sk, int level, int optname, static int sctp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen) char __user *optval, unsigned int optlen)
{ {
void *kopt = NULL;
int retval = 0; int retval = 0;
pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname); pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname);
...@@ -4689,8 +4444,14 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -4689,8 +4444,14 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
*/ */
if (level != SOL_SCTP) { if (level != SOL_SCTP) {
struct sctp_af *af = sctp_sk(sk)->pf->af; 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_user(optval, optlen);
if (IS_ERR(kopt))
return PTR_ERR(kopt);
} }
lock_sock(sk); lock_sock(sk);
...@@ -4698,179 +4459,174 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -4698,179 +4459,174 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
switch (optname) { switch (optname) {
case SCTP_SOCKOPT_BINDX_ADD: case SCTP_SOCKOPT_BINDX_ADD:
/* 'optlen' is the size of the addresses buffer. */ /* 'optlen' is the size of the addresses buffer. */
retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval, retval = sctp_setsockopt_bindx(sk, kopt, optlen,
optlen, SCTP_BINDX_ADD_ADDR); SCTP_BINDX_ADD_ADDR);
break; break;
case SCTP_SOCKOPT_BINDX_REM: case SCTP_SOCKOPT_BINDX_REM:
/* 'optlen' is the size of the addresses buffer. */ /* 'optlen' is the size of the addresses buffer. */
retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval, retval = sctp_setsockopt_bindx(sk, kopt, optlen,
optlen, SCTP_BINDX_REM_ADDR); SCTP_BINDX_REM_ADDR);
break; break;
case SCTP_SOCKOPT_CONNECTX_OLD: case SCTP_SOCKOPT_CONNECTX_OLD:
/* 'optlen' is the size of the addresses buffer. */ /* 'optlen' is the size of the addresses buffer. */
retval = sctp_setsockopt_connectx_old(sk, retval = sctp_setsockopt_connectx_old(sk, kopt, optlen);
(struct sockaddr __user *)optval,
optlen);
break; break;
case SCTP_SOCKOPT_CONNECTX: case SCTP_SOCKOPT_CONNECTX:
/* 'optlen' is the size of the addresses buffer. */ /* 'optlen' is the size of the addresses buffer. */
retval = sctp_setsockopt_connectx(sk, retval = sctp_setsockopt_connectx(sk, kopt, optlen);
(struct sockaddr __user *)optval,
optlen);
break; break;
case SCTP_DISABLE_FRAGMENTS: case SCTP_DISABLE_FRAGMENTS:
retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); retval = sctp_setsockopt_disable_fragments(sk, kopt, optlen);
break; break;
case SCTP_EVENTS: case SCTP_EVENTS:
retval = sctp_setsockopt_events(sk, optval, optlen); retval = sctp_setsockopt_events(sk, kopt, optlen);
break; break;
case SCTP_AUTOCLOSE: case SCTP_AUTOCLOSE:
retval = sctp_setsockopt_autoclose(sk, optval, optlen); retval = sctp_setsockopt_autoclose(sk, kopt, optlen);
break; break;
case SCTP_PEER_ADDR_PARAMS: case SCTP_PEER_ADDR_PARAMS:
retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen); retval = sctp_setsockopt_peer_addr_params(sk, kopt, optlen);
break; break;
case SCTP_DELAYED_SACK: case SCTP_DELAYED_SACK:
retval = sctp_setsockopt_delayed_ack(sk, optval, optlen); retval = sctp_setsockopt_delayed_ack(sk, kopt, optlen);
break; break;
case SCTP_PARTIAL_DELIVERY_POINT: case SCTP_PARTIAL_DELIVERY_POINT:
retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen); retval = sctp_setsockopt_partial_delivery_point(sk, kopt, optlen);
break; break;
case SCTP_INITMSG: case SCTP_INITMSG:
retval = sctp_setsockopt_initmsg(sk, optval, optlen); retval = sctp_setsockopt_initmsg(sk, kopt, optlen);
break; break;
case SCTP_DEFAULT_SEND_PARAM: case SCTP_DEFAULT_SEND_PARAM:
retval = sctp_setsockopt_default_send_param(sk, optval, retval = sctp_setsockopt_default_send_param(sk, kopt, optlen);
optlen);
break; break;
case SCTP_DEFAULT_SNDINFO: case SCTP_DEFAULT_SNDINFO:
retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen); retval = sctp_setsockopt_default_sndinfo(sk, kopt, optlen);
break; break;
case SCTP_PRIMARY_ADDR: case SCTP_PRIMARY_ADDR:
retval = sctp_setsockopt_primary_addr(sk, optval, optlen); retval = sctp_setsockopt_primary_addr(sk, kopt, optlen);
break; break;
case SCTP_SET_PEER_PRIMARY_ADDR: 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; break;
case SCTP_NODELAY: case SCTP_NODELAY:
retval = sctp_setsockopt_nodelay(sk, optval, optlen); retval = sctp_setsockopt_nodelay(sk, kopt, optlen);
break; break;
case SCTP_RTOINFO: case SCTP_RTOINFO:
retval = sctp_setsockopt_rtoinfo(sk, optval, optlen); retval = sctp_setsockopt_rtoinfo(sk, kopt, optlen);
break; break;
case SCTP_ASSOCINFO: case SCTP_ASSOCINFO:
retval = sctp_setsockopt_associnfo(sk, optval, optlen); retval = sctp_setsockopt_associnfo(sk, kopt, optlen);
break; break;
case SCTP_I_WANT_MAPPED_V4_ADDR: case SCTP_I_WANT_MAPPED_V4_ADDR:
retval = sctp_setsockopt_mappedv4(sk, optval, optlen); retval = sctp_setsockopt_mappedv4(sk, kopt, optlen);
break; break;
case SCTP_MAXSEG: case SCTP_MAXSEG:
retval = sctp_setsockopt_maxseg(sk, optval, optlen); retval = sctp_setsockopt_maxseg(sk, kopt, optlen);
break; break;
case SCTP_ADAPTATION_LAYER: case SCTP_ADAPTATION_LAYER:
retval = sctp_setsockopt_adaptation_layer(sk, optval, optlen); retval = sctp_setsockopt_adaptation_layer(sk, kopt, optlen);
break; break;
case SCTP_CONTEXT: case SCTP_CONTEXT:
retval = sctp_setsockopt_context(sk, optval, optlen); retval = sctp_setsockopt_context(sk, kopt, optlen);
break; break;
case SCTP_FRAGMENT_INTERLEAVE: case SCTP_FRAGMENT_INTERLEAVE:
retval = sctp_setsockopt_fragment_interleave(sk, optval, optlen); retval = sctp_setsockopt_fragment_interleave(sk, kopt, optlen);
break; break;
case SCTP_MAX_BURST: case SCTP_MAX_BURST:
retval = sctp_setsockopt_maxburst(sk, optval, optlen); retval = sctp_setsockopt_maxburst(sk, kopt, optlen);
break; break;
case SCTP_AUTH_CHUNK: case SCTP_AUTH_CHUNK:
retval = sctp_setsockopt_auth_chunk(sk, optval, optlen); retval = sctp_setsockopt_auth_chunk(sk, kopt, optlen);
break; break;
case SCTP_HMAC_IDENT: case SCTP_HMAC_IDENT:
retval = sctp_setsockopt_hmac_ident(sk, optval, optlen); retval = sctp_setsockopt_hmac_ident(sk, kopt, optlen);
break; break;
case SCTP_AUTH_KEY: case SCTP_AUTH_KEY:
retval = sctp_setsockopt_auth_key(sk, optval, optlen); retval = sctp_setsockopt_auth_key(sk, kopt, optlen);
break; break;
case SCTP_AUTH_ACTIVE_KEY: case SCTP_AUTH_ACTIVE_KEY:
retval = sctp_setsockopt_active_key(sk, optval, optlen); retval = sctp_setsockopt_active_key(sk, kopt, optlen);
break; break;
case SCTP_AUTH_DELETE_KEY: case SCTP_AUTH_DELETE_KEY:
retval = sctp_setsockopt_del_key(sk, optval, optlen); retval = sctp_setsockopt_del_key(sk, kopt, optlen);
break; break;
case SCTP_AUTH_DEACTIVATE_KEY: case SCTP_AUTH_DEACTIVATE_KEY:
retval = sctp_setsockopt_deactivate_key(sk, optval, optlen); retval = sctp_setsockopt_deactivate_key(sk, kopt, optlen);
break; break;
case SCTP_AUTO_ASCONF: case SCTP_AUTO_ASCONF:
retval = sctp_setsockopt_auto_asconf(sk, optval, optlen); retval = sctp_setsockopt_auto_asconf(sk, kopt, optlen);
break; break;
case SCTP_PEER_ADDR_THLDS: case SCTP_PEER_ADDR_THLDS:
retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen, retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen,
false); false);
break; break;
case SCTP_PEER_ADDR_THLDS_V2: case SCTP_PEER_ADDR_THLDS_V2:
retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen, retval = sctp_setsockopt_paddr_thresholds(sk, kopt, optlen,
true); true);
break; break;
case SCTP_RECVRCVINFO: case SCTP_RECVRCVINFO:
retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); retval = sctp_setsockopt_recvrcvinfo(sk, kopt, optlen);
break; break;
case SCTP_RECVNXTINFO: case SCTP_RECVNXTINFO:
retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen); retval = sctp_setsockopt_recvnxtinfo(sk, kopt, optlen);
break; break;
case SCTP_PR_SUPPORTED: case SCTP_PR_SUPPORTED:
retval = sctp_setsockopt_pr_supported(sk, optval, optlen); retval = sctp_setsockopt_pr_supported(sk, kopt, optlen);
break; break;
case SCTP_DEFAULT_PRINFO: case SCTP_DEFAULT_PRINFO:
retval = sctp_setsockopt_default_prinfo(sk, optval, optlen); retval = sctp_setsockopt_default_prinfo(sk, kopt, optlen);
break; break;
case SCTP_RECONFIG_SUPPORTED: case SCTP_RECONFIG_SUPPORTED:
retval = sctp_setsockopt_reconfig_supported(sk, optval, optlen); retval = sctp_setsockopt_reconfig_supported(sk, kopt, optlen);
break; break;
case SCTP_ENABLE_STREAM_RESET: case SCTP_ENABLE_STREAM_RESET:
retval = sctp_setsockopt_enable_strreset(sk, optval, optlen); retval = sctp_setsockopt_enable_strreset(sk, kopt, optlen);
break; break;
case SCTP_RESET_STREAMS: case SCTP_RESET_STREAMS:
retval = sctp_setsockopt_reset_streams(sk, optval, optlen); retval = sctp_setsockopt_reset_streams(sk, kopt, optlen);
break; break;
case SCTP_RESET_ASSOC: case SCTP_RESET_ASSOC:
retval = sctp_setsockopt_reset_assoc(sk, optval, optlen); retval = sctp_setsockopt_reset_assoc(sk, kopt, optlen);
break; break;
case SCTP_ADD_STREAMS: case SCTP_ADD_STREAMS:
retval = sctp_setsockopt_add_streams(sk, optval, optlen); retval = sctp_setsockopt_add_streams(sk, kopt, optlen);
break; break;
case SCTP_STREAM_SCHEDULER: case SCTP_STREAM_SCHEDULER:
retval = sctp_setsockopt_scheduler(sk, optval, optlen); retval = sctp_setsockopt_scheduler(sk, kopt, optlen);
break; break;
case SCTP_STREAM_SCHEDULER_VALUE: case SCTP_STREAM_SCHEDULER_VALUE:
retval = sctp_setsockopt_scheduler_value(sk, optval, optlen); retval = sctp_setsockopt_scheduler_value(sk, kopt, optlen);
break; break;
case SCTP_INTERLEAVING_SUPPORTED: case SCTP_INTERLEAVING_SUPPORTED:
retval = sctp_setsockopt_interleaving_supported(sk, optval, retval = sctp_setsockopt_interleaving_supported(sk, kopt,
optlen); optlen);
break; break;
case SCTP_REUSE_PORT: case SCTP_REUSE_PORT:
retval = sctp_setsockopt_reuse_port(sk, optval, optlen); retval = sctp_setsockopt_reuse_port(sk, kopt, optlen);
break; break;
case SCTP_EVENT: case SCTP_EVENT:
retval = sctp_setsockopt_event(sk, optval, optlen); retval = sctp_setsockopt_event(sk, kopt, optlen);
break; break;
case SCTP_ASCONF_SUPPORTED: case SCTP_ASCONF_SUPPORTED:
retval = sctp_setsockopt_asconf_supported(sk, optval, optlen); retval = sctp_setsockopt_asconf_supported(sk, kopt, optlen);
break; break;
case SCTP_AUTH_SUPPORTED: case SCTP_AUTH_SUPPORTED:
retval = sctp_setsockopt_auth_supported(sk, optval, optlen); retval = sctp_setsockopt_auth_supported(sk, kopt, optlen);
break; break;
case SCTP_ECN_SUPPORTED: case SCTP_ECN_SUPPORTED:
retval = sctp_setsockopt_ecn_supported(sk, optval, optlen); retval = sctp_setsockopt_ecn_supported(sk, kopt, optlen);
break; break;
case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
retval = sctp_setsockopt_pf_expose(sk, optval, optlen); retval = sctp_setsockopt_pf_expose(sk, kopt, optlen);
break; break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
...@@ -4878,8 +4634,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -4878,8 +4634,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
} }
release_sock(sk); release_sock(sk);
kfree(kopt);
out_nounlock:
return retval; return retval;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment