Commit c6ba68a2 authored by Vlad Yasevich's avatar Vlad Yasevich

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: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
parent 9919b455
...@@ -147,6 +147,8 @@ enum sctp_optname { ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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);
......
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