From 22efa8c36a787a507766d3167359678227de13d6 Mon Sep 17 00:00:00 2001
From: hoelscher <jens.hoelscher@fh-muenster.de>
Date: Thu, 26 Nov 2015 16:14:54 +0100
Subject: [PATCH] add support for sctp_freeladdrs and sctp_getladdrs

---
 gtests/net/packetdrill/run_system_call.c      | 109 ++++++++++++++++--
 .../tests/bsd/sctp/sctp_active_x.pkt          |   6 +
 2 files changed, 104 insertions(+), 11 deletions(-)

diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index f87dd2c1..b25215d9 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -5020,7 +5020,7 @@ static int syscall_sctp_peeloff(struct state *state, struct syscall_spec *syscal
 
 static int syscall_sctp_getpaddrs(struct state *state, struct syscall_spec *syscall,
 				  struct expression_list *args,
-				   char **error)
+				  char **error)
 {
 #if defined(__FreeBSD__) || defined(linux)
 	int live_fd, script_fd, result;
@@ -5103,6 +5103,91 @@ static int syscall_sctp_freepaddrs(struct state *state, struct syscall_spec *sys
 #endif
 }
 
+static int syscall_sctp_getladdrs(struct state *state, struct syscall_spec *syscall,
+				  struct expression_list *args,
+				  char **error)
+{
+#if defined(__FreeBSD__) || defined(linux)
+	int live_fd, script_fd, result;
+	sctp_assoc_t assoc_id;
+	struct expression *assoc_expr, *addrs_list_expr;
+	struct sockaddr *live_addrs;
+
+	if (check_arg_count(args, 3, 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;
+	assoc_expr = get_arg(args, 1, error);
+	if (get_u32(assoc_expr, (u32 *)&assoc_id, error))
+		return STATUS_ERR;
+
+	begin_syscall(state, syscall);
+
+	result = sctp_getladdrs(live_fd, assoc_id, &live_addrs);
+
+	if (end_syscall(state, syscall, CHECK_EXACT, result, error))
+		goto error_out;
+	addrs_list_expr = get_arg(args, 2, error);
+	if (addrs_list_expr->type != EXPR_ELLIPSIS) {
+		int list_length = 0, i = 0;
+		struct sockaddr *live_addr = live_addrs;
+		if (check_type(addrs_list_expr, EXPR_LIST, error)) {
+			goto error_out;
+		}
+		list_length = get_arg_count(addrs_list_expr->value.list);
+		if (list_length != result) {
+			asprintf(error, "Bad length of struct sockaddr array. expected: %d, actual %d", list_length, result);
+			goto error_out;
+		}
+		for (i = 0; i < result; i++) {
+			struct expression *script_addr_expr;
+			script_addr_expr = get_arg(addrs_list_expr->value.list, i, error);
+			if (check_sockaddr(script_addr_expr,  live_addr, error)) {
+				goto error_out;
+			}
+			if (live_addr->sa_family == AF_INET) {
+                                live_addr = (struct sockaddr *)((caddr_t*)live_addr) + sizeof(struct sockaddr_in);
+			} else if (live_addr->sa_family == AF_INET6) {
+				live_addr = (struct sockaddr *)((caddr_t*)live_addr) + sizeof(struct sockaddr_in6);
+			} else {
+				asprintf(error, "Bad Type of addrs[%d]", i);
+				goto error_out;
+			}
+		}
+	}
+	return STATUS_OK;
+error_out:
+	sctp_freeladdrs(live_addrs);
+	return STATUS_ERR;
+#else
+	asprintf(error, "sctp_getladdrs is not supported");
+	return STATUS_ERR;
+#endif
+}
+
+static int syscall_sctp_freeladdrs(struct state *state, struct syscall_spec *syscall,
+				   struct expression_list *args,
+				   char **error)
+{
+#if defined(__FreeBSD__) || defined(linux)
+	struct expression *addrs_expr;
+	if (check_arg_count(args, 1, error))
+		return STATUS_ERR;
+	addrs_expr = get_arg(args, 0, error);
+	if (check_type(addrs_expr, EXPR_LIST, error))
+		return STATUS_ERR;
+	if (ellipsis_arg(addrs_expr->value.list, 0, error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+#else
+	asprintf(error, "sctp_freeladdrs is not supported");
+	return STATUS_ERR;
+#endif
+}
+
 
 
 /* A dispatch table with all the system calls that we support... */
@@ -5137,17 +5222,19 @@ struct system_call_entry system_call_table[] = {
 	{"getsockopt", syscall_getsockopt},
 	{"setsockopt", syscall_setsockopt},
 	{"poll",       syscall_poll},
-	{"sctp_send",     syscall_sctp_send},
-	{"sctp_sendx",    syscall_sctp_sendx},
-	{"sctp_sendmsg",  syscall_sctp_sendmsg},
-	{"sctp_recvmsg",  syscall_sctp_recvmsg},
-	{"sctp_sendv",    syscall_sctp_sendv},
-	{"sctp_recvv",    syscall_sctp_recvv},
-	{"sctp_bindx",    syscall_sctp_bindx},
-	{"sctp_connectx", syscall_sctp_connectx},
-	{"sctp_peeloff",  syscall_sctp_peeloff},
+	{"sctp_bindx",     syscall_sctp_bindx},
+	{"sctp_peeloff",   syscall_sctp_peeloff},
+	{"sctp_getpaddrs", syscall_sctp_getpaddrs},
 	{"sctp_freepaddrs",syscall_sctp_freepaddrs},
-	{"sctp_getpaddrs",syscall_sctp_getpaddrs}
+	{"sctp_getladdrs", syscall_sctp_getladdrs},
+	{"sctp_freeladdrs",syscall_sctp_freeladdrs},
+	{"sctp_sendmsg",   syscall_sctp_sendmsg},
+	{"sctp_recvmsg",   syscall_sctp_recvmsg},
+	{"sctp_connectx",  syscall_sctp_connectx},
+	{"sctp_send",      syscall_sctp_send},
+	{"sctp_sendx",     syscall_sctp_sendx},
+	{"sctp_sendv",     syscall_sctp_sendv},
+	{"sctp_recvv",     syscall_sctp_recvv}
 };
 
 /* 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 93595426..9424a9b6 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_active_x.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_active_x.pkt
@@ -18,6 +18,12 @@
 +0.0 sctp_getpaddrs(3, 3, [{sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")}]) = 1
 +0.0 sctp_freepaddrs([...]) = 0
 
++0.0 sctp_getladdrs(3, 3, [...]) = 1
++0.0 sctp_freeladdrs([...]) = 0
+
++0.0 sctp_getladdrs(3, 3, [{sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.168.0.1")}]) = 1
++0.0 sctp_freeladdrs([...]) = 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=[]]
-- 
GitLab