From 468c9a07f5d73524c548438840e431cf9cb4e0be Mon Sep 17 00:00:00 2001
From: hoelscher <jens.hoelscher@fh-muenster.de>
Date: Mon, 16 Nov 2015 15:11:50 +0100
Subject: [PATCH] add sctp_peeloff

---
 gtests/net/packetdrill/run_system_call.c      | 77 ++++++++++++++++++-
 .../tests/bsd/sctp/sctp_active_x.pkt          | 19 ++++-
 2 files changed, 91 insertions(+), 5 deletions(-)

diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index 84a6a847..71fccfcf 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -1753,11 +1753,37 @@ static int run_syscall_connect(struct state *state,
 	socket->script.remote.port		= 0;
 	socket->script.local.port		= 0;
 	socket->live.remote.ip   = state->config->live_remote_ip;
-	socket->live.remote.port = htons(state->config->live_connect_port);
+	socket->live.remote.port = htons(state->config->live_connect_port);	
 	DEBUGP("success: setting socket to state %d\n", socket->state);
 	return STATUS_OK;
 }
 
+static int run_syscall_sctp_peeloff(struct state *state,
+				    int script_copy_fd,
+				    int script_new_fd,
+				    int live_new_fd,
+				    char **error) {
+	struct socket *copy_socket = NULL, *new_socket, *temp_socket;
+	copy_socket = find_socket_by_script_fd(state, script_copy_fd);
+	assert(copy_socket != NULL);
+	if (copy_socket->state == SOCKET_NEW) {
+		asprintf(error, "socket is not new");
+		return STATUS_ERR;
+	}
+	new_socket = find_socket_by_script_fd(state, script_new_fd);
+	assert(new_socket == NULL);
+	new_socket = socket_new(state);
+	temp_socket = new_socket->next;
+
+	memcpy(new_socket, copy_socket, sizeof(struct socket));
+	new_socket->next = temp_socket;
+	new_socket->live.fd		= live_new_fd;
+	new_socket->script.fd		= script_new_fd;
+	DEBUGP("success: setting socket to state %d\n", new_socket->state);
+	return STATUS_OK;
+}
+
+
 /****************************************************************************
  * Here we have the parsing and invocation of the system calls that
  * we support...
@@ -4792,6 +4818,11 @@ static int syscall_sctp_connectx(struct state *state, struct syscall_spec *sysca
 		return STATUS_ERR;
 
 	assoc_expr = get_arg(args, 3, error);
+	if (check_type(assoc_expr, EXPR_LIST, error))
+		return STATUS_ERR;
+	if (check_arg_count(assoc_expr->value.list, 1, error))
+		return STATUS_ERR;
+	assoc_expr = get_arg(assoc_expr->value.list, 0, error);
 	if (check_u32_expr(assoc_expr, (u32)live_associd,
 			   "sctp_connectx assoc_id", error))
 		return STATUS_ERR;
@@ -4803,6 +4834,46 @@ static int syscall_sctp_connectx(struct state *state, struct syscall_spec *sysca
 #endif
 }
 
+static int syscall_sctp_peeloff(struct state *state, struct syscall_spec *syscall,
+			        struct expression_list *args,
+			        char **error)
+{
+#if defined(__FreeBSD__) || defined(linux)
+	int live_fd, script_fd, result, script_new_fd;
+	sctp_assoc_t assoc_id;
+	struct expression *expr_assoc;
+	if (check_arg_count(args, 2, error))
+		return STATUS_ERR;
+	if (s32_arg(args, 0, &script_fd, error))
+		return STATUS_ERR;
+	if (to_live_fd(state, script_fd, &live_fd, error))
+		return STATUS_ERR;
+	expr_assoc = get_arg(args, 1, error);
+	if (get_u32(expr_assoc, &assoc_id, error))
+		return STATUS_ERR;
+
+	//check connection Type and set assoc_id if one-to-many style socket
+	
+	begin_syscall(state, syscall);
+
+	result = sctp_peeloff(live_fd, assoc_id);
+
+	if (end_syscall(state, syscall, CHECK_NON_NEGATIVE, result, error))
+		return STATUS_ERR;
+
+	if (get_s32(syscall->result, &script_new_fd, error))
+		return STATUS_ERR;
+	if (run_syscall_sctp_peeloff(state, script_fd, script_new_fd, result, error)) {
+		asprintf(error, "can't copy socket definition");
+		return STATUS_ERR;
+	}
+
+	return STATUS_OK;
+#else
+	asprintf(error, "sctp_connectx is not supported");
+	return STATUS_ERR;
+#endif
+}
 
 /* A dispatch table with all the system calls that we support... */
 struct system_call_entry {
@@ -4812,6 +4883,7 @@ struct system_call_entry {
 			 struct expression_list *args,
 			 char **error);
 };
+
 struct system_call_entry system_call_table[] = {
 	{"socket",     syscall_socket},
 	{"bind",       syscall_bind},
@@ -4840,7 +4912,8 @@ struct system_call_entry system_call_table[] = {
 	{"sctp_sendv",    syscall_sctp_sendv},
 	{"sctp_recvv",    syscall_sctp_recvv},
 	{"sctp_bindx",    syscall_sctp_bindx},
-	{"sctp_connectx", syscall_sctp_connectx}
+	{"sctp_connectx", syscall_sctp_connectx},
+	{"sctp_peeloff",  syscall_sctp_peeloff}
 };
 
 /* Evaluate the system call arguments and invoke the system call. */
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_active_x.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_active_x.pkt
index 15af1333..44c1d95e 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_active_x.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_active_x.pkt
@@ -1,17 +1,30 @@
-+0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
+
+ 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
 +0.0 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
 +0.0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
 
 +0.0 sctp_bindx(3, [...], 1, SCTP_BINDX_ADD_ADDR) = 0
 
 // Check the handshake with an empty(!) cookie
-+0.1 sctp_connectx(3, [...], 1, 3) = 0
++0.1 sctp_connectx(3, [...], 1, [3]) = 0
 +0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...]
 +0.1 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=16, is=16, tsn=1, STATE_COOKIE[len=4, val=...]]
 +0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...]
 +0.1 < sctp: COOKIE_ACK[flgs=0]
 
-+0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
++0.0 sctp_sendmsg(3, ..., 1000, ..., ..., htonl(1234), SCTP_UNORDERED, 1, 0, 0) = 1000
+*    > sctp: DATA[flgs=UBE, len=1016, tsn=1, sid=1, ssn=0, ppid=1234]
++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]]
+
++0.0 sctp_peeloff(3, 4) = 4
+
++0.0 sctp_sendmsg(3, ..., 1000, ..., ..., htonl(1234), SCTP_UNORDERED, 1, 0, 0) = 1000
+*    > sctp: DATA[flgs=UBE, len=1016, tsn=1, sid=1, ssn=0, ppid=1234]
++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]]
+
++0.0 sctp_sendmsg(4, ..., 1000, ..., ..., htonl(1234), SCTP_UNORDERED, 1, 0, 0) = 1000
+*    > sctp: DATA[flgs=UBE, len=1016, tsn=1, sid=1, ssn=0, ppid=1234]
++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]]
 
 +0.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=0]
 *    > sctp: SHUTDOWN_ACK[flgs=0]
-- 
GitLab