From 943cc8f9eb76c28e1eff5e856350a0ca7acc4905 Mon Sep 17 00:00:00 2001
From: Julian Cordes <julian.cordes@gmail.com>
Date: Sun, 3 Jan 2016 02:46:33 +0100
Subject: [PATCH] fixes for support of generic init messages.

---
 gtests/net/packetdrill/packet.c               |   5 +
 gtests/net/packetdrill/run_packet.c           | 213 ++++++++++--------
 gtests/net/packetdrill/sctp_packet.c          |   9 +-
 .../tests/bsd/sctp/sctp_generic_passive.pkt   |  16 ++
 4 files changed, 147 insertions(+), 96 deletions(-)
 create mode 100644 gtests/net/packetdrill/tests/bsd/sctp/sctp_generic_passive.pkt

diff --git a/gtests/net/packetdrill/packet.c b/gtests/net/packetdrill/packet.c
index a5edfebe..406e3465 100644
--- a/gtests/net/packetdrill/packet.c
+++ b/gtests/net/packetdrill/packet.c
@@ -177,6 +177,11 @@ static struct packet *packet_copy_with_headroom(struct packet *old_packet,
 	packet->udplite	= offset_ptr(old_base, new_base, old_packet->udplite);
 	packet->icmpv4	= offset_ptr(old_base, new_base, old_packet->icmpv4);
 	packet->icmpv6	= offset_ptr(old_base, new_base, old_packet->icmpv6);
+        
+        if (old_packet->chunk_list == NULL) {
+		packet->chunk_list = NULL;
+		return packet;
+        }
 
 	/* Go through the SCTP specific lists */
 	for (old_chunk_item = old_packet->chunk_list->first;
diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c
index 6d7b021b..caede856 100644
--- a/gtests/net/packetdrill/run_packet.c
+++ b/gtests/net/packetdrill/run_packet.c
@@ -191,7 +191,7 @@ static struct socket *handle_listen_for_script_packet(
 	 */
 	struct config *config = state->config;
 	struct socket *socket = state->socket_under_test;	/* shortcut */
-	struct sctp_init_chunk *init;
+	u32 initiate_tag, initial_tsn;
 	struct sctp_chunk_list_item *item;
 
 	bool match = (direction == DIRECTION_INBOUND);
@@ -210,17 +210,42 @@ static struct socket *handle_listen_for_script_packet(
 	}
 	if (!match)
 		return NULL;
-
+	
 	if (packet->sctp != NULL) {
-		assert(packet->chunk_list != NULL);
-		item = packet->chunk_list->first;
-		if ((item != NULL) &&
-		    (item->chunk->type == SCTP_INIT_CHUNK_TYPE)) {
-			init = (struct sctp_init_chunk *)item->chunk;
-		} else {
-			return NULL;
+		if (packet->chunk_list != NULL) {
+			item = packet->chunk_list->first;
+			if ((item != NULL) &&
+				(item->chunk->type == SCTP_INIT_CHUNK_TYPE)) {
+				struct sctp_init_chunk *init = (struct sctp_init_chunk *)item->chunk;
+				initiate_tag = ntohl(init->initiate_tag);
+				initial_tsn = ntohl(init->initial_tsn);
+			} else {
+				return NULL;
+			}
+		}
+		else {
+			if (packet->flags & FLAGS_SCTP_GENERIC_PACKET) {
+				u8 *sctp_chunk_start = (u8 *) (packet->sctp + 1);
+				if (sctp_chunk_start[0] == SCTP_INIT_CHUNK_TYPE) {
+					u8 *initiate_tag_start = (u8 *) (sctp_chunk_start + 4);
+					u8 *initial_tsn_start = (u8 *) (sctp_chunk_start + 16);
+					initiate_tag = initiate_tag_start[3] << 24 | initiate_tag_start[2] << 16 | initiate_tag_start[1] << 8 |  initiate_tag_start[0];
+					initial_tsn = initial_tsn_start[3] << 24 | initial_tsn_start[2] << 16 | initial_tsn_start[1] << 8 |  initial_tsn_start[0];
+					initiate_tag = ntohl(initiate_tag);
+					initial_tsn = ntohl(initial_tsn);
+				}
+				else {
+					return NULL;
+				}
+			}
+			else {
+				return NULL;
+			}
 		}
 	}
+	else {
+		DEBUGP("packet->sctp == NULL");
+	}
 
 	/* Create a child passive socket for this incoming SYN packet.
 	 * Any further packets in the test script will be directed to
@@ -241,8 +266,8 @@ static struct socket *handle_listen_for_script_packet(
 	if (packet->tcp != NULL) {
 		socket->script.remote_isn = ntohl(packet->tcp->seq);
 	} else {
-		socket->script.remote_initiate_tag = ntohl(init->initiate_tag);
-		socket->script.remote_initial_tsn = ntohl(init->initial_tsn);
+		socket->script.remote_initiate_tag = initiate_tag;
+		socket->script.remote_initial_tsn = initial_tsn;
 	}
 	socket->script.fd		= -1;
 
@@ -256,8 +281,8 @@ static struct socket *handle_listen_for_script_packet(
 	if (packet->tcp != NULL) {
 		socket->live.remote_isn = ntohl(packet->tcp->seq);
 	} else {
-		socket->live.remote_initiate_tag = ntohl(init->initiate_tag);
-		socket->live.remote_initial_tsn = ntohl(init->initial_tsn);
+		socket->live.remote_initiate_tag = initiate_tag;
+		socket->live.remote_initial_tsn = initial_tsn;
 	}
 	socket->live.fd			= -1;
 
@@ -2508,93 +2533,95 @@ static int do_inbound_script_packet(
 		}
 	}
 	if (packet->sctp) {
-		for (item = packet->chunk_list->first;
-		     item != NULL;
-		     item = item->next) {
-			switch (item->chunk->type) {
-			case SCTP_INIT_ACK_CHUNK_TYPE:
-				if (socket->state == SOCKET_ACTIVE_INIT_SENT) {
-					init_ack = (struct sctp_init_ack_chunk *)item->chunk;
-					DEBUGP("Moving socket in SOCKET_ACTIVE_INIT_ACK_RECEIVED\n");
-					socket->state = SOCKET_ACTIVE_INIT_ACK_RECEIVED;
-					socket->script.remote_initiate_tag = ntohl(init_ack->initiate_tag);
-					socket->script.remote_initial_tsn = ntohl(init_ack->initial_tsn);
-					socket->live.remote_initiate_tag = ntohl(init_ack->initiate_tag);
-					socket->live.remote_initial_tsn = ntohl(init_ack->initial_tsn);
-					DEBUGP("remote_initiate_tag 0x%08x, remote_initial_tsn 0x%08x\n", ntohl(init_ack->initiate_tag), ntohl(init_ack->initial_tsn));
-				}
-				break;
-			case SCTP_COOKIE_ECHO_CHUNK_TYPE:
-				if (item->flags & FLAG_CHUNK_VALUE_NOCHECK) {
-					temp_offset = socket->prepared_cookie_echo_length - item->length;
-					assert(packet->ip_bytes + temp_offset <= packet->buffer_bytes);
-					memmove((u8 *)item->chunk + item->length + temp_offset,
-						(u8 *)item->chunk + item->length,
-						packet_end(packet) - ((u8 *)item->chunk + item->length));
-					memcpy(item->chunk,
-					       socket->prepared_cookie_echo,
-					       socket->prepared_cookie_echo_length);
-					item->length = socket->prepared_cookie_echo_length;
-					packet->buffer_bytes += temp_offset;
-					packet->ip_bytes += temp_offset;
-					if (packet->ipv4) {
-						packet->ipv4->tot_len = htons(ntohs(packet->ipv4->tot_len) + temp_offset);
-					}
-					if (packet->ipv6) {
-						packet->ipv6->payload_len = htons(ntohs(packet->ipv6->payload_len) + temp_offset);
+		if (packet->chunk_list != NULL) {
+			for (item = packet->chunk_list->first;
+			     item != NULL;
+			     item = item->next) {
+				switch (item->chunk->type) {
+				case SCTP_INIT_ACK_CHUNK_TYPE:
+					if (socket->state == SOCKET_ACTIVE_INIT_SENT) {
+						init_ack = (struct sctp_init_ack_chunk *)item->chunk;
+						DEBUGP("Moving socket in SOCKET_ACTIVE_INIT_ACK_RECEIVED\n");
+						socket->state = SOCKET_ACTIVE_INIT_ACK_RECEIVED;
+						socket->script.remote_initiate_tag = ntohl(init_ack->initiate_tag);
+						socket->script.remote_initial_tsn = ntohl(init_ack->initial_tsn);
+						socket->live.remote_initiate_tag = ntohl(init_ack->initiate_tag);
+						socket->live.remote_initial_tsn = ntohl(init_ack->initial_tsn);
+						DEBUGP("remote_initiate_tag 0x%08x, remote_initial_tsn 0x%08x\n", ntohl(init_ack->initiate_tag), ntohl(init_ack->initial_tsn));
 					}
-					for (i = 0; i < PACKET_MAX_HEADERS; i++) {
-						if ((packet->ipv4 != NULL && packet->headers[i].h.ipv4 == packet->ipv4) ||
-						    (packet->ipv6 != NULL && packet->headers[i].h.ipv6 == packet->ipv6)) {
-							break;
+					break;
+				case SCTP_COOKIE_ECHO_CHUNK_TYPE:
+					if (item->flags & FLAG_CHUNK_VALUE_NOCHECK) {
+						temp_offset = socket->prepared_cookie_echo_length - item->length;
+						assert(packet->ip_bytes + temp_offset <= packet->buffer_bytes);
+						memmove((u8 *)item->chunk + item->length + temp_offset,
+							(u8 *)item->chunk + item->length,
+							packet_end(packet) - ((u8 *)item->chunk + item->length));
+						memcpy(item->chunk,
+						       socket->prepared_cookie_echo,
+						       socket->prepared_cookie_echo_length);
+						item->length = socket->prepared_cookie_echo_length;
+						packet->buffer_bytes += temp_offset;
+						packet->ip_bytes += temp_offset;
+						if (packet->ipv4) {
+							packet->ipv4->tot_len = htons(ntohs(packet->ipv4->tot_len) + temp_offset);
 						}
+						if (packet->ipv6) {
+							packet->ipv6->payload_len = htons(ntohs(packet->ipv6->payload_len) + temp_offset);
+						}
+						for (i = 0; i < PACKET_MAX_HEADERS; i++) {
+							if ((packet->ipv4 != NULL && packet->headers[i].h.ipv4 == packet->ipv4) ||
+							    (packet->ipv6 != NULL && packet->headers[i].h.ipv6 == packet->ipv6)) {
+								break;
+							}
+						}
+						assert(packet->headers[i + 1].type == HEADER_SCTP);
+						packet->headers[i].total_bytes += temp_offset;
+						packet->headers[i + 1].total_bytes += temp_offset;
+						offset += temp_offset;
 					}
-					assert(packet->headers[i + 1].type == HEADER_SCTP);
-					packet->headers[i].total_bytes += temp_offset;
-					packet->headers[i + 1].total_bytes += temp_offset;
-					offset += temp_offset;
-				}
-				if (((packet->flags & FLAGS_SCTP_BAD_CRC32C) == 0) &&
-				    (((packet->flags & FLAGS_SCTP_EXPLICIT_TAG) == 0) ||
-				     ((ntohl(packet->sctp->v_tag) == socket->script.local_initiate_tag) &&
-				      (socket->script.local_initiate_tag != 0)))) {
-					socket->state = SOCKET_PASSIVE_COOKIE_ECHO_RECEIVED;
-				}
-				break;
-			case SCTP_HEARTBEAT_ACK_CHUNK_TYPE:
-				if (item->flags & FLAG_CHUNK_VALUE_NOCHECK) {
-					temp_offset = socket->prepared_heartbeat_ack_length - item->length;
-					assert(packet->ip_bytes + temp_offset <= packet->buffer_bytes);
-					memmove((u8 *)item->chunk + item->length + temp_offset,
-						(u8 *)item->chunk + item->length,
-						packet_end(packet) - ((u8 *)item->chunk + item->length));
-					memcpy(item->chunk,
-					       socket->prepared_heartbeat_ack,
-					       socket->prepared_heartbeat_ack_length);
-					item->length = socket->prepared_heartbeat_ack_length;
-					packet->buffer_bytes += temp_offset;
-					packet->ip_bytes += temp_offset;
-					if (packet->ipv4) {
-						packet->ipv4->tot_len = htons(ntohs(packet->ipv4->tot_len) + temp_offset);
-					}
-					if (packet->ipv6) {
-						packet->ipv6->payload_len = htons(ntohs(packet->ipv6->payload_len) + temp_offset);
+					if (((packet->flags & FLAGS_SCTP_BAD_CRC32C) == 0) &&
+					    (((packet->flags & FLAGS_SCTP_EXPLICIT_TAG) == 0) ||
+					     ((ntohl(packet->sctp->v_tag) == socket->script.local_initiate_tag) &&
+					      (socket->script.local_initiate_tag != 0)))) {
+						socket->state = SOCKET_PASSIVE_COOKIE_ECHO_RECEIVED;
 					}
-					for (i = 0; i < PACKET_MAX_HEADERS; i++) {
-						if ((packet->ipv4 != NULL && packet->headers[i].h.ipv4 == packet->ipv4) ||
-						    (packet->ipv6 != NULL && packet->headers[i].h.ipv6 == packet->ipv6)) {
-							break;
+					break;
+				case SCTP_HEARTBEAT_ACK_CHUNK_TYPE:
+					if (item->flags & FLAG_CHUNK_VALUE_NOCHECK) {
+						temp_offset = socket->prepared_heartbeat_ack_length - item->length;
+						assert(packet->ip_bytes + temp_offset <= packet->buffer_bytes);
+						memmove((u8 *)item->chunk + item->length + temp_offset,
+							(u8 *)item->chunk + item->length,
+							packet_end(packet) - ((u8 *)item->chunk + item->length));
+						memcpy(item->chunk,
+						       socket->prepared_heartbeat_ack,
+						       socket->prepared_heartbeat_ack_length);
+						item->length = socket->prepared_heartbeat_ack_length;
+						packet->buffer_bytes += temp_offset;
+						packet->ip_bytes += temp_offset;
+						if (packet->ipv4) {
+							packet->ipv4->tot_len = htons(ntohs(packet->ipv4->tot_len) + temp_offset);
+						}
+						if (packet->ipv6) {
+							packet->ipv6->payload_len = htons(ntohs(packet->ipv6->payload_len) + temp_offset);
+						}
+						for (i = 0; i < PACKET_MAX_HEADERS; i++) {
+							if ((packet->ipv4 != NULL && packet->headers[i].h.ipv4 == packet->ipv4) ||
+							    (packet->ipv6 != NULL && packet->headers[i].h.ipv6 == packet->ipv6)) {
+								break;
+							}
 						}
+						assert(packet->headers[i + 1].type == HEADER_SCTP);
+						packet->headers[i].total_bytes += temp_offset;
+						packet->headers[i + 1].total_bytes += temp_offset;
+						offset += temp_offset;
 					}
-					assert(packet->headers[i + 1].type == HEADER_SCTP);
-					packet->headers[i].total_bytes += temp_offset;
-					packet->headers[i + 1].total_bytes += temp_offset;
-					offset += temp_offset;
+					break;
+				default:
+					item->chunk = (struct sctp_chunk *)((char *)item->chunk + offset);
+					break;
 				}
-				break;
-			default:
-				item->chunk = (struct sctp_chunk *)((char *)item->chunk + offset);
-				break;
 			}
 		}
 	}
diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c
index 0f5c66fd..8b743399 100644
--- a/gtests/net/packetdrill/sctp_packet.c
+++ b/gtests/net/packetdrill/sctp_packet.c
@@ -1254,8 +1254,11 @@ void
 sctp_chunk_list_free(struct sctp_chunk_list *list)
 {
 	struct sctp_chunk_list_item *current_item, *next_item;
-
-	assert(list != NULL);
+	
+	if (list == NULL) {
+		return;
+	}
+	
 	current_item = list->first;
 	while (current_item != NULL) {
 		next_item = current_item->next;
@@ -2683,7 +2686,7 @@ new_sctp_generic_packet(int address_family,
 		sctp_chunk_start[i] = item->byte;
 	}
 
-	packet->chunk_list = sctp_chunk_list_new();
+	packet->chunk_list = NULL;
 	packet->ip_bytes = ip_bytes;
 	return packet;
 }
\ No newline at end of file
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic_passive.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic_passive.pkt
new file mode 100644
index 00000000..d296713a
--- /dev/null
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic_passive.pkt
@@ -0,0 +1,16 @@
++0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
+// Check the handshake with en empty(!) cookie
++0.0 bind(3, ..., ...) = 0
++0.0 listen(3, 1) = 0
++0.0 < sctp: [0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0xDC, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01]
+//+0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=1500, os=1, is=1, tsn=1]
++0.0 > sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=..., os=..., is=..., tsn=1, ...]
++0.1 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...]
++0.0 > sctp: COOKIE_ACK[flgs=0]
++0.0 accept(3, ..., ...) = 4
+// Tear down the association
++1.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=0]
++0.0 > sctp: SHUTDOWN_ACK[flgs=0]
++0.0 < sctp: SHUTDOWN_COMPLETE[flgs=0]
++0.0 close(4) = 0
++0.0 close(3) = 0
-- 
GitLab