sctp: support non-blocking version of the new sctp_connectx() API
Prior implementation of the new sctp_connectx() call that returns an association ID did not work correctly on non-blocking socket. This is because we could not return both a EINPROGRESS error and an association id. This is a new implementation that supports this. Originally from Ivan Skytte Jørgensen <isj-sctp@i1.dk Signed-off-by: Ivan Skytte Jørgensen <isj-sctp@i1.dk Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
This commit is contained in:
@@ -147,6 +147,8 @@ enum sctp_optname {
|
|||||||
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
|
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
|
||||||
SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */
|
SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */
|
||||||
#define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX
|
#define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX
|
||||||
|
SCTP_SOCKOPT_CONNECTX3, /* CONNECTX requests. (new implementation) */
|
||||||
|
#define SCTP_SOCKOPT_CONNECTX3 SCTP_SOCKOPT_CONNECTX3
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -1470,6 +1470,10 @@ int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
|
|||||||
{
|
{
|
||||||
int assoc_id;
|
int assoc_id;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
|
/* If the id is already assigned, keep it. */
|
||||||
|
if (asoc->assoc_id)
|
||||||
|
return error;
|
||||||
retry:
|
retry:
|
||||||
if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
|
if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@@ -1100,6 +1100,15 @@ static int __sctp_connect(struct sock* sk,
|
|||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In case the user of sctp_connectx() wants an association
|
||||||
|
* id back, assign one now.
|
||||||
|
*/
|
||||||
|
if (assoc_id) {
|
||||||
|
err = sctp_assoc_set_id(asoc, GFP_KERNEL);
|
||||||
|
if (err < 0)
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
err = sctp_primitive_ASSOCIATE(asoc, NULL);
|
err = sctp_primitive_ASSOCIATE(asoc, NULL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
goto out_free;
|
goto out_free;
|
||||||
@@ -1120,7 +1129,7 @@ static int __sctp_connect(struct sock* sk,
|
|||||||
timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
|
timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
|
||||||
|
|
||||||
err = sctp_wait_for_connect(asoc, &timeo);
|
err = sctp_wait_for_connect(asoc, &timeo);
|
||||||
if (!err && assoc_id)
|
if ((err == 0 || err == -EINPROGRESS) && assoc_id)
|
||||||
*assoc_id = asoc->assoc_id;
|
*assoc_id = asoc->assoc_id;
|
||||||
|
|
||||||
/* Don't free association on exit. */
|
/* Don't free association on exit. */
|
||||||
@@ -1264,6 +1273,34 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
|
|||||||
return assoc_id;
|
return assoc_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* New (hopefully final) interface for the API. The option buffer is used
|
||||||
|
* both for the returned association id and the addresses.
|
||||||
|
*/
|
||||||
|
SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len,
|
||||||
|
char __user *optval,
|
||||||
|
int __user *optlen)
|
||||||
|
{
|
||||||
|
sctp_assoc_t assoc_id = 0;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (len < sizeof(assoc_id))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
err = __sctp_setsockopt_connectx(sk,
|
||||||
|
(struct sockaddr __user *)(optval + sizeof(assoc_id)),
|
||||||
|
len - sizeof(assoc_id), &assoc_id);
|
||||||
|
|
||||||
|
if (err == 0 || err == -EINPROGRESS) {
|
||||||
|
if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
|
||||||
|
return -EFAULT;
|
||||||
|
if (put_user(sizeof(assoc_id), optlen))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* API 3.1.4 close() - UDP Style Syntax
|
/* API 3.1.4 close() - UDP Style Syntax
|
||||||
* Applications use close() to perform graceful shutdown (as described in
|
* Applications use close() to perform graceful shutdown (as described in
|
||||||
* Section 10.1 of [SCTP]) on ALL the associations currently represented
|
* Section 10.1 of [SCTP]) on ALL the associations currently represented
|
||||||
@@ -5578,6 +5615,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
|
|||||||
retval = sctp_getsockopt_local_addrs(sk, len, optval,
|
retval = sctp_getsockopt_local_addrs(sk, len, optval,
|
||||||
optlen);
|
optlen);
|
||||||
break;
|
break;
|
||||||
|
case SCTP_SOCKOPT_CONNECTX3:
|
||||||
|
retval = sctp_getsockopt_connectx3(sk, len, optval, optlen);
|
||||||
|
break;
|
||||||
case SCTP_DEFAULT_SEND_PARAM:
|
case SCTP_DEFAULT_SEND_PARAM:
|
||||||
retval = sctp_getsockopt_default_send_param(sk, len,
|
retval = sctp_getsockopt_default_send_param(sk, len,
|
||||||
optval, optlen);
|
optval, optlen);
|
||||||
|
Reference in New Issue
Block a user