lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Sat, 11 Sep 2010 21:13:03 -0400
From:	Yaogong Wang <ywang15@...u.edu>
To:	linux-sctp@...r.kernel.org,
	Vlad Yasevich <vladislav.yasevich@...com>
Cc:	linux-kernel@...r.kernel.org
Subject: [PATCHv2 3/5] sctp: extend socket API for sched configuration

Augment SCTP socket API with a new socket option SCTP_SCHED
to choose and configure multistream scheduling algorithm.

Signed-off-by: Yaogong Wang <ywang15@...u.edu>
---
 include/net/sctp/structs.h |    4 ++
 include/net/sctp/user.h    |   19 ++++++++++
 net/sctp/outqueue.c        |    4 ++
 net/sctp/sm_sideeffect.c   |   45 +++++++++++++++++++++++--
 net/sctp/socket.c          |   80 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 149 insertions(+), 3 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 52af764..1a76417 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -333,6 +333,8 @@ struct sctp_sock {

 	/* Multistream scheduling */
 	const struct sctp_sched_ops *sched_ops;
+	__u16 sched_config_len;
+	void *sched_config;

 	struct sctp_initmsg initmsg;
 	struct sctp_rtoinfo rtoinfo;
@@ -1173,6 +1175,8 @@ struct sctp_outq {

 	/* Multistream scheduling */
 	const struct sctp_sched_ops *sched_ops;
+	__u16 sched_config_len;
+	void *sched_config;

 	unsigned out_qlen;	/* Total length of queued data chunks. */

diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index 1e084f9..bb853d0 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -90,6 +90,7 @@ typedef __s32 sctp_assoc_t;
 #define SCTP_PEER_AUTH_CHUNKS	26	/* Read only */
 #define SCTP_LOCAL_AUTH_CHUNKS	27	/* Read only */
 #define SCTP_GET_ASSOC_NUMBER	28	/* Read only */
+#define SCTP_SCHED	29	/* Configure multistream scheduling */

 /* Internal Socket Options. Some of the sctp library functions are
  * implemented using these socket options.
@@ -708,6 +709,24 @@ typedef struct {
 	int sd;
 } sctp_peeloff_arg_t;

+/*
+ * SCTP Multistream Scheduling Structure (SCTP_SCHED)
+ *
+ *   This cmsghdr structure provides information for the multistream
+ *   scheduling algorithm used by a socket. The SCTP_SCHED socket option
+ *   uses this same data structure.
+ *
+ *   cmsg_level    cmsg_type      cmsg_data[]
+ *   ------------  ------------   ----------------------
+ *   IPPROTO_SCTP  SCTP_SCHED     struct sctp_sched
+ *
+ */
+
 #define SCTP_SCHED_NAME_MAX	16
+struct sctp_sched {
+	char  ssched_name[SCTP_SCHED_NAME_MAX];
+	__u16 ssched_config_len;
+	__u16 ssched_config[0];
+};

 #endif /* __net_sctp_user_h__ */
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 37ffa21..1d3bd2e 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -178,6 +178,8 @@ int sctp_outq_init(struct sctp_association *asoc,
struct sctp_outq *q,

 	/* initialize to the default FCFS at this stage */
 	q->sched_ops = sctp_default_sched_ops;
+	q->sched_config_len = 0;
+	q->sched_config = NULL;
 	err = q->sched_ops->init(q, gfp);
 	if (err)
 		return err;
@@ -269,6 +271,8 @@ void sctp_outq_free(struct sctp_outq *q)
 	sctp_outq_teardown(q);

 	q->sched_ops->release(q);
+	kfree(q->sched_config);
+	module_put(q->sched_ops->owner);

 	/* If we were kmalloc()'d, free the memory.  */
 	if (q->malloced)
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index f5e5e27..e240557 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -744,17 +744,54 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
 }

 /* Helper function to change the state of an association. */
-static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds,
+static int sctp_cmd_new_state(sctp_cmd_seq_t *cmds,
 			       struct sctp_association *asoc,
-			       sctp_state_t state)
+			       sctp_state_t state,
+				gfp_t gfp)
 {
 	struct sock *sk = asoc->base.sk;
+	struct sctp_sock *sp = sctp_sk(sk);

 	asoc->state = state;

 	SCTP_DEBUG_PRINTK("sctp_cmd_new_state: asoc %p[%s]\n",
 			  asoc, sctp_state_tbl[state]);

+	/* Initialize mulitstream scheduling if user has customized it
+	 * Otherwise do nothing
+	 * Client: when entering COOKIE_ECHOED state
+	 * Server: when entering ESTABLISHED state
+	 */
+	if (sp->sched_ops != asoc->outqueue.sched_ops &&
+	(sctp_state(asoc, COOKIE_ECHOED) || sctp_state(asoc, ESTABLISHED))) {
+		if (!try_module_get(sp->sched_ops->owner))
+			return -EBUSY;
+		asoc->outqueue.sched_ops = sp->sched_ops;
+		asoc->outqueue.sched_config_len = sp->sched_config_len;
+		if (sp->sched_config_len) {
+			asoc->outqueue.sched_config = kmemdup(sp->sched_config,
+					sp->sched_config_len, gfp);
+			if (!asoc->outqueue.sched_config)
+				return -ENOMEM;
+		}
+		/* Initialize new data chunk queue(s)
+		 * Move data chunks from old queue to new queue(s)
+		 */
+		struct list_head *old = asoc->outqueue.out_chunk_list;
+		struct sctp_chunk *ch = NULL;
+		if (0 != asoc->outqueue.sched_ops->init(&asoc->outqueue, gfp))
+			return -ENOMEM;
+		while (!list_empty(old)) {
+			struct list_head *entry = old->next;
+			ch = list_entry(entry, struct sctp_chunk, list);
+			list_del_init(entry);
+			asoc->outqueue.out_qlen -= ch->skb->len;
+			asoc->outqueue.sched_ops->
+				enqueue_tail_data(&asoc->outqueue, ch);
+		}
+		kfree(old);
+	}
+
 	if (sctp_style(sk, TCP)) {
 		/* Change the sk->sk_state of a TCP-style socket that has
 		 * successfully completed a connect() call.
@@ -796,6 +833,7 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds,
 		if (!sctp_style(sk, UDP))
 			sk->sk_state_change(sk);
 	}
+	return 0;
 }

 /* Helper function to delete an association. */
@@ -1250,7 +1288,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,

 		case SCTP_CMD_NEW_STATE:
 			/* Enter a new state.  */
-			sctp_cmd_new_state(commands, asoc, cmd->obj.state);
+			error = sctp_cmd_new_state(commands, asoc,
+						cmd->obj.state, gfp);
 			break;

 		case SCTP_CMD_REPORT_TSN:
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7d461be..481f231 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2582,6 +2582,44 @@ static int sctp_setsockopt_initmsg(struct sock
*sk, char __user *optval, unsigne
 	return 0;
 }

+/* Set the multistream scheduling algorithm */
+static int sctp_setsockopt_sched(struct sock *sk, char __user *optval,
+						unsigned int optlen)
+{
+	struct sctp_sched *ssched = NULL;
+	struct sctp_sock *sp = sctp_sk(sk);
+	int ret = 0;
+
+	if (optlen < sizeof(struct sctp_sched))
+		return -EINVAL;
+
+	ssched = memdup_user(optval, optlen);
+	if (IS_ERR(ssched)) {
+		ret = PTR_ERR(ssched);
+		goto out;
+	}
+
+	if (optlen != sizeof(struct sctp_sched) + ssched->ssched_config_len) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = sctp_set_sched(sk, ssched->ssched_name);
+	if (ret)
+		goto out;
+	sp->sched_config_len = ssched->ssched_config_len;
+	kfree(sp->sched_config);
+	if (sp->sched_config_len) {
+		sp->sched_config = kmemdup(ssched->ssched_config,
+					sp->sched_config_len, GFP_KERNEL);
+		if (!sp->sched_config)
+			ret = -ENOMEM;
+	}
+out:
+	kfree(ssched);
+	return ret;
+}
+
 /*
  * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM)
  *
@@ -3422,6 +3460,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk,
int level, int optname,
 	case SCTP_INITMSG:
 		retval = sctp_setsockopt_initmsg(sk, optval, optlen);
 		break;
+	case SCTP_SCHED:
+		retval = sctp_setsockopt_sched(sk, optval, optlen);
+		break;
 	case SCTP_DEFAULT_SEND_PARAM:
 		retval = sctp_setsockopt_default_send_param(sk, optval,
 							    optlen);
@@ -3646,6 +3687,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)

 	/* Initialize default multistream scheduling algorithm */
 	sp->sched_ops = sctp_default_sched_ops;
+	sp->sched_config_len = 0;
+	sp->sched_config = NULL;

 	/* Initialize default RTO related parameters.  These parameters can
 	 * be modified for with the SCTP_RTOINFO socket option.
@@ -3738,6 +3781,9 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk)

 	SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk);

+	sctp_cleanup_sched(sk);
+	kfree(sctp_sk(sk)->sched_config);
+
 	/* Release our hold on the endpoint. */
 	ep = sctp_sk(sk)->ep;
 	sctp_endpoint_free(ep);
@@ -4354,7 +4400,38 @@ static int sctp_getsockopt_initmsg(struct sock
*sk, int len, char __user *optval
 	return 0;
 }

+/* Get the multistream scheduling algorithm */
+static int sctp_getsockopt_sched(struct sock *sk, int len, char __user *optval,
+							int __user *optlen)
+{
+	struct sctp_sched *ssched;
+	int sz = sizeof(struct sctp_sched) + sctp_sk(sk)->sched_config_len;
+	int ret = 0;
+
+	if (len < sz)
+		return -EINVAL;
+
+	ssched = kmalloc(sz, GFP_KERNEL);
+	if (!ssched)
+		return -ENOMEM;
+	memcpy(ssched->ssched_name, sctp_sk(sk)->sched_ops->name,
+					SCTP_SCHED_NAME_MAX);
+	ssched->ssched_config_len = sctp_sk(sk)->sched_config_len;
+	memcpy(ssched->ssched_config, sctp_sk(sk)->sched_config,
+					ssched->ssched_config_len);
+
+	if (copy_to_user(optval, ssched, sz)) {
+		ret = -EFAULT;
+		goto out;
+	}
+	if (put_user(sz, optlen))
+		ret = -EFAULT;

+out:
+	kfree(ssched);
+	return ret;
+}
+
 static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
 				      char __user *optval, int __user *optlen)
 {
@@ -5299,6 +5376,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk,
int level, int optname,
 	case SCTP_INITMSG:
 		retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
 		break;
+	case SCTP_SCHED:
+		retval = sctp_getsockopt_sched(sk, len, optval, optlen);
+		break;
 	case SCTP_GET_PEER_ADDRS:
 		retval = sctp_getsockopt_peer_addrs(sk, len, optval,
 						    optlen);
-- 
1.7.0.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ