diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2009-06-01 12:41:15 -0400 |
---|---|---|
committer | Vlad Yasevich <vladislav.yasevich@hp.com> | 2009-06-03 09:14:47 -0400 |
commit | c6ba68a26645dbc5029a9faa5687ebe6fcfc53e4 (patch) | |
tree | e47a8f343b7fd0ba0a5d3e49a740d5dbe73e430a | |
parent | 9919b455fc00c995ef8141848bdc0709ce50bf36 (diff) |
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>
-rw-r--r-- | include/net/sctp/user.h | 2 | ||||
-rw-r--r-- | net/sctp/associola.c | 4 | ||||
-rw-r--r-- | net/sctp/socket.c | 42 |
3 files changed, 47 insertions, 1 deletions
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index b259fc5798fb..1580c04f68bc 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h | |||
@@ -147,6 +147,8 @@ enum sctp_optname { | |||
147 | #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS | 147 | #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS |
148 | SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ | 148 | SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ |
149 | #define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX | 149 | #define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX |
150 | SCTP_SOCKOPT_CONNECTX3, /* CONNECTX requests. (new implementation) */ | ||
151 | #define SCTP_SOCKOPT_CONNECTX3 SCTP_SOCKOPT_CONNECTX3 | ||
150 | }; | 152 | }; |
151 | 153 | ||
152 | /* | 154 | /* |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 39f5166ae7af..525864bf4f07 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -1470,6 +1470,10 @@ int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp) | |||
1470 | { | 1470 | { |
1471 | int assoc_id; | 1471 | int assoc_id; |
1472 | int error = 0; | 1472 | int error = 0; |
1473 | |||
1474 | /* If the id is already assigned, keep it. */ | ||
1475 | if (asoc->assoc_id) | ||
1476 | return error; | ||
1473 | retry: | 1477 | retry: |
1474 | if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp))) | 1478 | if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp))) |
1475 | return -ENOMEM; | 1479 | return -ENOMEM; |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5fb3a8c9792e..7c3dfd2d9489 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -1100,6 +1100,15 @@ static int __sctp_connect(struct sock* sk, | |||
1100 | goto out_free; | 1100 | goto out_free; |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | /* In case the user of sctp_connectx() wants an association | ||
1104 | * id back, assign one now. | ||
1105 | */ | ||
1106 | if (assoc_id) { | ||
1107 | err = sctp_assoc_set_id(asoc, GFP_KERNEL); | ||
1108 | if (err < 0) | ||
1109 | goto out_free; | ||
1110 | } | ||
1111 | |||
1103 | err = sctp_primitive_ASSOCIATE(asoc, NULL); | 1112 | err = sctp_primitive_ASSOCIATE(asoc, NULL); |
1104 | if (err < 0) { | 1113 | if (err < 0) { |
1105 | goto out_free; | 1114 | goto out_free; |
@@ -1120,7 +1129,7 @@ static int __sctp_connect(struct sock* sk, | |||
1120 | timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK); | 1129 | timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK); |
1121 | 1130 | ||
1122 | err = sctp_wait_for_connect(asoc, &timeo); | 1131 | err = sctp_wait_for_connect(asoc, &timeo); |
1123 | if (!err && assoc_id) | 1132 | if ((err == 0 || err == -EINPROGRESS) && assoc_id) |
1124 | *assoc_id = asoc->assoc_id; | 1133 | *assoc_id = asoc->assoc_id; |
1125 | 1134 | ||
1126 | /* Don't free association on exit. */ | 1135 | /* Don't free association on exit. */ |
@@ -1264,6 +1273,34 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, | |||
1264 | return assoc_id; | 1273 | return assoc_id; |
1265 | } | 1274 | } |
1266 | 1275 | ||
1276 | /* | ||
1277 | * New (hopefully final) interface for the API. The option buffer is used | ||
1278 | * both for the returned association id and the addresses. | ||
1279 | */ | ||
1280 | SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len, | ||
1281 | char __user *optval, | ||
1282 | int __user *optlen) | ||
1283 | { | ||
1284 | sctp_assoc_t assoc_id = 0; | ||
1285 | int err = 0; | ||
1286 | |||
1287 | if (len < sizeof(assoc_id)) | ||
1288 | return -EINVAL; | ||
1289 | |||
1290 | err = __sctp_setsockopt_connectx(sk, | ||
1291 | (struct sockaddr __user *)(optval + sizeof(assoc_id)), | ||
1292 | len - sizeof(assoc_id), &assoc_id); | ||
1293 | |||
1294 | if (err == 0 || err == -EINPROGRESS) { | ||
1295 | if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) | ||
1296 | return -EFAULT; | ||
1297 | if (put_user(sizeof(assoc_id), optlen)) | ||
1298 | return -EFAULT; | ||
1299 | } | ||
1300 | |||
1301 | return err; | ||
1302 | } | ||
1303 | |||
1267 | /* API 3.1.4 close() - UDP Style Syntax | 1304 | /* API 3.1.4 close() - UDP Style Syntax |
1268 | * Applications use close() to perform graceful shutdown (as described in | 1305 | * Applications use close() to perform graceful shutdown (as described in |
1269 | * Section 10.1 of [SCTP]) on ALL the associations currently represented | 1306 | * 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 | retval = sctp_getsockopt_local_addrs(sk, len, optval, | 5615 | retval = sctp_getsockopt_local_addrs(sk, len, optval, |
5579 | optlen); | 5616 | optlen); |
5580 | break; | 5617 | break; |
5618 | case SCTP_SOCKOPT_CONNECTX3: | ||
5619 | retval = sctp_getsockopt_connectx3(sk, len, optval, optlen); | ||
5620 | break; | ||
5581 | case SCTP_DEFAULT_SEND_PARAM: | 5621 | case SCTP_DEFAULT_SEND_PARAM: |
5582 | retval = sctp_getsockopt_default_send_param(sk, len, | 5622 | retval = sctp_getsockopt_default_send_param(sk, len, |
5583 | optval, optlen); | 5623 | optval, optlen); |