Commit 88a0a948 authored by Vlad Yasevich's avatar Vlad Yasevich Committed by David S. Miller

sctp: Support the new specification of sctp_connectx()

The specification of sctp_connectx() has been changed to return
an association id.  We've added a new socket option that will
return the association id as the return value from the setsockopt()
call.  The library that implements sctp_connectx() interface will
implement both socket options.
Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d364d927
...@@ -137,12 +137,14 @@ enum sctp_optname { ...@@ -137,12 +137,14 @@ enum sctp_optname {
#define SCTP_GET_LOCAL_ADDRS_NUM_OLD SCTP_GET_LOCAL_ADDRS_NUM_OLD #define SCTP_GET_LOCAL_ADDRS_NUM_OLD SCTP_GET_LOCAL_ADDRS_NUM_OLD
SCTP_GET_LOCAL_ADDRS_OLD, /* Get all local addresss. */ SCTP_GET_LOCAL_ADDRS_OLD, /* Get all local addresss. */
#define SCTP_GET_LOCAL_ADDRS_OLD SCTP_GET_LOCAL_ADDRS_OLD #define SCTP_GET_LOCAL_ADDRS_OLD SCTP_GET_LOCAL_ADDRS_OLD
SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ SCTP_SOCKOPT_CONNECTX_OLD, /* CONNECTX old requests. */
#define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX #define SCTP_SOCKOPT_CONNECTX_OLD SCTP_SOCKOPT_CONNECTX_OLD
SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */ SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */
#define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS #define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS
SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */
#define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX
}; };
/* /*
......
...@@ -956,7 +956,8 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, ...@@ -956,7 +956,8 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
*/ */
static int __sctp_connect(struct sock* sk, static int __sctp_connect(struct sock* sk,
struct sockaddr *kaddrs, struct sockaddr *kaddrs,
int addrs_size) int addrs_size,
sctp_assoc_t *assoc_id)
{ {
struct sctp_sock *sp; struct sctp_sock *sp;
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
...@@ -1111,6 +1112,8 @@ static int __sctp_connect(struct sock* sk, ...@@ -1111,6 +1112,8 @@ 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)
*assoc_id = asoc->assoc_id;
/* Don't free association on exit. */ /* Don't free association on exit. */
asoc = NULL; asoc = NULL;
...@@ -1128,7 +1131,8 @@ static int __sctp_connect(struct sock* sk, ...@@ -1128,7 +1131,8 @@ static int __sctp_connect(struct sock* sk,
/* Helper for tunneling sctp_connectx() requests through sctp_setsockopt() /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt()
* *
* API 8.9 * API 8.9
* int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt); * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
* sctp_assoc_t *asoc);
* *
* If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
* If the sd is an IPv6 socket, the addresses passed can either be IPv4 * If the sd is an IPv6 socket, the addresses passed can either be IPv4
...@@ -1144,8 +1148,10 @@ static int __sctp_connect(struct sock* sk, ...@@ -1144,8 +1148,10 @@ static int __sctp_connect(struct sock* sk,
* representation is termed a "packed array" of addresses). The caller * representation is termed a "packed array" of addresses). The caller
* specifies the number of addresses in the array with addrcnt. * specifies the number of addresses in the array with addrcnt.
* *
* On success, sctp_connectx() returns 0. On failure, sctp_connectx() returns * On success, sctp_connectx() returns 0. It also sets the assoc_id to
* -1, and sets errno to the appropriate error code. * the association id of the new association. On failure, sctp_connectx()
* returns -1, and sets errno to the appropriate error code. The assoc_id
* is not touched by the kernel.
* *
* For SCTP, the port given in each socket address must be the same, or * For SCTP, the port given in each socket address must be the same, or
* sctp_connectx() will fail, setting errno to EINVAL. * sctp_connectx() will fail, setting errno to EINVAL.
...@@ -1182,11 +1188,12 @@ static int __sctp_connect(struct sock* sk, ...@@ -1182,11 +1188,12 @@ static int __sctp_connect(struct sock* sk,
* addrs The pointer to the addresses in user land * addrs The pointer to the addresses in user land
* 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.
*/ */
SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, SCTP_STATIC int __sctp_setsockopt_connectx(struct sock* sk,
struct sockaddr __user *addrs, struct sockaddr __user *addrs,
int addrs_size) int addrs_size,
sctp_assoc_t *assoc_id)
{ {
int err = 0; int err = 0;
struct sockaddr *kaddrs; struct sockaddr *kaddrs;
...@@ -1209,13 +1216,46 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, ...@@ -1209,13 +1216,46 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
if (__copy_from_user(kaddrs, addrs, addrs_size)) { if (__copy_from_user(kaddrs, addrs, addrs_size)) {
err = -EFAULT; err = -EFAULT;
} else { } else {
err = __sctp_connect(sk, kaddrs, addrs_size); err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
} }
kfree(kaddrs); kfree(kaddrs);
return err; return err;
} }
/*
* This is an older interface. It's kept for backward compatibility
* to the option that doesn't provide association id.
*/
SCTP_STATIC int sctp_setsockopt_connectx_old(struct sock* sk,
struct sockaddr __user *addrs,
int addrs_size)
{
return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL);
}
/*
* New interface for the API. The since the API is done with a socket
* option, to make it simple we feed back the association id is as a return
* indication to the call. Error is always negative and association id is
* always positive.
*/
SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
struct sockaddr __user *addrs,
int addrs_size)
{
sctp_assoc_t assoc_id = 0;
int err = 0;
err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id);
if (err)
return err;
else
return assoc_id;
}
/* 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
...@@ -3206,10 +3246,18 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -3206,10 +3246,18 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
optlen, SCTP_BINDX_REM_ADDR); optlen, SCTP_BINDX_REM_ADDR);
break; break;
case SCTP_SOCKOPT_CONNECTX_OLD:
/* 'optlen' is the size of the addresses buffer. */
retval = sctp_setsockopt_connectx_old(sk,
(struct sockaddr __user *)optval,
optlen);
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, (struct sockaddr __user *)optval, retval = sctp_setsockopt_connectx(sk,
optlen); (struct sockaddr __user *)optval,
optlen);
break; break;
case SCTP_DISABLE_FRAGMENTS: case SCTP_DISABLE_FRAGMENTS:
...@@ -3336,7 +3384,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr, ...@@ -3336,7 +3384,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr,
/* Pass correct addr len to common routine (so it knows there /* Pass correct addr len to common routine (so it knows there
* is only one address being passed. * is only one address being passed.
*/ */
err = __sctp_connect(sk, addr, af->sockaddr_len); err = __sctp_connect(sk, addr, af->sockaddr_len, NULL);
} }
sctp_release_sock(sk); sctp_release_sock(sk);
......
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