aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-06-01 12:41:15 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-06-03 09:14:47 -0400
commitc6ba68a26645dbc5029a9faa5687ebe6fcfc53e4 (patch)
treee47a8f343b7fd0ba0a5d3e49a740d5dbe73e430a
parent9919b455fc00c995ef8141848bdc0709ce50bf36 (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.h2
-rw-r--r--net/sctp/associola.c4
-rw-r--r--net/sctp/socket.c42
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;
1473retry: 1477retry:
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 */
1280SCTP_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);