diff --git a/gtests/net/packetdrill/packet.c b/gtests/net/packetdrill/packet.c index a5edfebe07eeca5d3ea2f53ae8078265c620e4b2..406e34659560622b0dfac625fca6490ffce94185 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/packet.h b/gtests/net/packetdrill/packet.h index 8e931ec28528670813bf29749eb3f205f0d84528..a51c9e1162421ed59f972a2bec91e86fdda3045c 100644 --- a/gtests/net/packetdrill/packet.h +++ b/gtests/net/packetdrill/packet.h @@ -105,11 +105,12 @@ struct packet { s64 time_usecs; /* wall time of receive/send if non-zero */ - u32 flags; /* various meta-flags */ -#define FLAG_WIN_NOCHECK 0x1 /* don't check TCP receive window */ -#define FLAG_OPTIONS_NOCHECK 0x2 /* don't check TCP options */ -#define FLAGS_SCTP_BAD_CRC32C 0x4 /* compute bad CRC32C for SCTP packets */ -#define FLAGS_SCTP_EXPLICIT_TAG 0x8 /* verification tag specified */ + u32 flags; /* various meta-flags */ +#define FLAG_WIN_NOCHECK 0x1 /* don't check TCP receive window */ +#define FLAG_OPTIONS_NOCHECK 0x2 /* don't check TCP options */ +#define FLAGS_SCTP_BAD_CRC32C 0x4 /* compute bad CRC32C for SCTP packets */ +#define FLAGS_SCTP_EXPLICIT_TAG 0x8 /* verification tag specified */ +#define FLAGS_SCTP_GENERIC_PACKET 0x10 /* set if it is a generic packet */ enum ip_ecn_t ecn; /* IPv4/IPv6 ECN treatment for packet */ diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 7613efa1c7c60a9a96ec94edcb888d8fc645dc66..f5c85b66fe083778b3a6556f247c61649b1f9dae 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -933,6 +933,72 @@ sctp_packet_spec $$ = packet_encapsulate_and_free(outer, inner); } +| packet_prefix opt_ip_info SCTP ':' '[' byte_list ']' { + char *error = NULL; + struct packet *outer = $1, *inner = NULL; + enum direction_t direction = outer->direction; + + inner = new_sctp_generic_packet(in_config->wire_protocol, direction, $2, + -1, false, $6, &error); + if (inner == NULL) { + assert(error != NULL); + semantic_error(error); + free(error); + } + + $$ = packet_encapsulate_and_free(outer, inner); +} +| packet_prefix opt_ip_info SCTP '(' BAD_CRC32C ')' ':' '[' byte_list ']' { + char *error = NULL; + struct packet *outer = $1, *inner = NULL; + enum direction_t direction = outer->direction; + + inner = new_sctp_generic_packet(in_config->wire_protocol, direction, $2, + -1, true, $9, &error); + if (inner == NULL) { + assert(error != NULL); + semantic_error(error); + free(error); + } + + $$ = packet_encapsulate_and_free(outer, inner); +} +| packet_prefix opt_ip_info SCTP '(' TAG '=' INTEGER ')' ':' '[' byte_list ']' { + char *error = NULL; + struct packet *outer = $1, *inner = NULL; + enum direction_t direction = outer->direction; + + if (!is_valid_u32($7)) { + semantic_error("tag value out of range"); + } + inner = new_sctp_generic_packet(in_config->wire_protocol, direction, $2, + $7, false, $11, &error); + if (inner == NULL) { + assert(error != NULL); + semantic_error(error); + free(error); + } + + $$ = packet_encapsulate_and_free(outer, inner); +} +| packet_prefix opt_ip_info SCTP '(' BAD_CRC32C ',' TAG '=' INTEGER ')' ':' '[' byte_list ']' { + char *error = NULL; + struct packet *outer = $1, *inner = NULL; + enum direction_t direction = outer->direction; + + if (!is_valid_u32($9)) { + semantic_error("tag value out of range"); + } + inner = new_sctp_generic_packet(in_config->wire_protocol, direction, $2, + $9, true, $13, &error); + if (inner == NULL) { + assert(error != NULL); + semantic_error(error); + free(error); + } + + $$ = packet_encapsulate_and_free(outer, inner); +} ; sctp_chunk_list_spec diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index 6d7b021b7ff6c4c8a1d4e68f6059751768896341..57069c9a6cbd5b3f847e3ee0256ad9bb176f174a 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); @@ -212,14 +212,53 @@ static struct socket *handle_listen_for_script_packet( 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; + 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 { - return NULL; + if (packet->flags & FLAGS_SCTP_GENERIC_PACKET) { + struct header sctp_header; + unsigned int i; + bool found = false; + size_t chunk_length; + + for (i = 0; i < ARRAY_SIZE(packet->headers); ++i) { + if (packet->headers[i].type == HEADER_SCTP) { + sctp_header = packet->headers[i]; + found = true; + break; + } + } + + assert(found != false); + chunk_length = sctp_header.total_bytes - sizeof(struct sctp_common_header); + + if (chunk_length < sizeof(struct sctp_init_chunk)) { + fprintf(stderr, "length of init chunk too short. you must specify the whole init chunk."); + return NULL; + } + + u8 *sctp_chunk_start = (u8 *) (packet->sctp + 1); + if (sctp_chunk_start[0] == SCTP_INIT_CHUNK_TYPE) { + struct sctp_init_chunk *init = (struct sctp_init_chunk *) sctp_chunk_start; + initiate_tag = ntohl(init->initiate_tag); + initial_tsn = ntohl(init->initial_tsn); + } else { + return NULL; + } + } else { + return NULL; + } } + } else { + DEBUGP("packet->sctp == NULL"); } /* Create a child passive socket for this incoming SYN packet. @@ -241,8 +280,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 +295,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 +2547,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 5ddca4a72b388f1d5488bd6dd00a9e19e97d0f71..7c11497e881f6550805cce8eb55deb411d6a0796 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; @@ -2591,3 +2594,100 @@ new_sctp_packet(int address_family, packet->ip_bytes = ip_bytes; return packet; } + +#ifdef DEBUG_LOGGING +static void print_sctp_byte_list(struct sctp_byte_list *list) { + struct sctp_byte_list_item *item; + + for (item = list->first; item != NULL; item = item->next) { + DEBUGP("0x%.2x,", item->byte); + } +} +#endif + +struct packet * +new_sctp_generic_packet(int address_family, + enum direction_t direction, + enum ip_ecn_t ecn, + s64 tag, + bool bad_crc32c, + struct sctp_byte_list *bytes, + char **error) { + struct packet *packet; /* the newly-allocated result packet */ + struct header *sctp_header; /* the SCTP header info */ + struct sctp_byte_list_item *item = NULL; + /* Calculate lengths in bytes of all sections of the packet */ + const int ip_option_bytes = 0; + const int ip_header_bytes = (ip_header_min_len(address_family) + + ip_option_bytes); + const int sctp_header_bytes = sizeof(struct sctp_common_header); + const int sctp_chunk_bytes = bytes->nr_entries; + const int ip_bytes = + ip_header_bytes + sctp_header_bytes + sctp_chunk_bytes; + bool overbook = false; + u16 i; + +#ifdef DEBUG_LOGGING + print_sctp_byte_list(bytes); +#endif + + if (direction == DIRECTION_OUTBOUND) { + asprintf(error, + "generic packets can only be specified as inbound."); + return NULL; + } + + /* Sanity-check all the various lengths */ + if (ip_option_bytes & 0x3) { + asprintf(error, "IP options are not padded correctly " + "to ensure IP header is a multiple of 4 bytes: " + "%d excess bytes", ip_option_bytes & 0x3); + return NULL; + } + assert((ip_header_bytes & 0x3) == 0); + + if (ip_bytes > MAX_SCTP_DATAGRAM_BYTES) { + asprintf(error, "SCTP packet too large"); + return NULL; + } + + /* Allocate and zero out a packet object of the desired size */ + packet = packet_new(overbook ? MAX_SCTP_DATAGRAM_BYTES : ip_bytes); + memset(packet->buffer, 0, overbook ? MAX_SCTP_DATAGRAM_BYTES : ip_bytes); + + packet->direction = direction; + packet->flags = FLAGS_SCTP_GENERIC_PACKET; + if (bad_crc32c) { + packet->flags |= FLAGS_SCTP_BAD_CRC32C; + } + if (tag != -1) { + packet->flags |= FLAGS_SCTP_EXPLICIT_TAG; + } + packet->ecn = ecn; + + /* Set IP header fields */ + set_packet_ip_header(packet, address_family, ip_bytes, ecn, + IPPROTO_SCTP); + + sctp_header = packet_append_header(packet, HEADER_SCTP, sctp_header_bytes); + sctp_header->total_bytes = sctp_header_bytes + sctp_chunk_bytes; + + /* Find the start of the SCTP common header of the packet */ + packet->sctp = (struct sctp_common_header *) (ip_start(packet) + ip_header_bytes); + u8 *sctp_chunk_start = (u8 *) (packet->sctp + 1); + + /* Set SCTP header fields */ + packet->sctp->src_port = htons(0); + packet->sctp->dst_port = htons(0); + packet->sctp->v_tag = htonl((u32)tag); + packet->sctp->crc32c = htonl(0); + + for (i = 0, item = bytes->first; item != NULL; i++, item = item->next) { + sctp_chunk_start[i] = item->byte; + } + + packet->chunk_list = NULL; + packet->ip_bytes = ip_bytes; + + return packet; +} diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h index b492ebc736cb5e504e079ac981e59d1f3b933639..4defa5042fb64632b925e127c982306a4deeda5d 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -430,4 +430,13 @@ extern struct packet *new_sctp_packet(int address_family, bool bad_crc32c, struct sctp_chunk_list *chunk_list, char **error); + +struct packet * +new_sctp_generic_packet(int address_family, + enum direction_t direction, + enum ip_ecn_t ecn, + s64 tag, + bool bad_crc32c, + struct sctp_byte_list *bytes, + char **error); #endif /* __SCTP_PACKET_H__ */ diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic.pkt new file mode 100644 index 0000000000000000000000000000000000000000..eff794350f28d3071396f8473f62770d4e620990 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_generic.pkt @@ -0,0 +1,20 @@ +// Create a non-blocking 1-to-1 style socket + 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 ++0.0 bind(3, ..., ...) = 0 ++0.0 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR) ++0.0 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0 +// Trigger the active associtation setup ++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] +//+0.0 < sctp(t, tag=1): INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...]] ++0.0 < sctp: [0x02, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05, 0xDC, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x04] ++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...] +//+0.0 > sctp(tag=3): [0x0A, 0x00, 0x00, 0x04] ++0.0 < sctp: COOKIE_ACK[flgs=0] +// Check if the setup was sucessful ++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 +// Tear down the association ++0.0 close(3) = 0 ++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=0] ++0.1 < sctp: SHUTDOWN_ACK[flgs=0] ++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0] 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 0000000000000000000000000000000000000000..d296713a7f67c6903be0c3c273505ac394460421 --- /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