Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6ba68a2 authored by Vlad Yasevich's avatar Vlad Yasevich
Browse files

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: default avatarIvan Skytte Jørgensen <isj-sctp@i1.dk>
Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
parent 9919b455
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -147,6 +147,8 @@ enum sctp_optname {
#define SCTP_GET_LOCAL_ADDRS	SCTP_GET_LOCAL_ADDRS
	SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */
#define SCTP_SOCKOPT_CONNECTX	SCTP_SOCKOPT_CONNECTX
	SCTP_SOCKOPT_CONNECTX3, /* CONNECTX requests. (new implementation) */
#define SCTP_SOCKOPT_CONNECTX3	SCTP_SOCKOPT_CONNECTX3
};

/*
+4 −0
Original line number Diff line number Diff line
@@ -1470,6 +1470,10 @@ int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
{
	int assoc_id;
	int error = 0;

	/* If the id is already assigned, keep it. */
	if (asoc->assoc_id)
		return error;
retry:
	if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
		return -ENOMEM;
+41 −1
Original line number Diff line number Diff line
@@ -1100,6 +1100,15 @@ static int __sctp_connect(struct sock* sk,
		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);
	if (err < 0) {
		goto out_free;
@@ -1120,7 +1129,7 @@ static int __sctp_connect(struct sock* sk,
	timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);

	err = sctp_wait_for_connect(asoc, &timeo);
	if (!err && assoc_id)
	if ((err == 0 || err == -EINPROGRESS) && assoc_id)
		*assoc_id = asoc->assoc_id;

	/* Don't free association on exit. */
@@ -1264,6 +1273,34 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
		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
 * Applications use close() to perform graceful shutdown (as described in
 * 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,
						     optlen);
		break;
	case SCTP_SOCKOPT_CONNECTX3:
		retval = sctp_getsockopt_connectx3(sk, len, optval, optlen);
		break;
	case SCTP_DEFAULT_SEND_PARAM:
		retval = sctp_getsockopt_default_send_param(sk, len,
							    optval, optlen);