From 6ff6c64a3881ddc0ba539d06e7dfbc1170ebd519 Mon Sep 17 00:00:00 2001 From: hoelscher <jens.hoelscher@fh-muenster.de> Date: Tue, 20 Oct 2015 03:24:04 +0200 Subject: [PATCH] Add support for sctp_shutdown_event in recvmsg and sctp_recvv --- gtests/net/packetdrill/lexer.l | 3 + gtests/net/packetdrill/parser.y | 62 +++++- gtests/net/packetdrill/run_system_call.c | 186 +++++++++++++----- gtests/net/packetdrill/script.c | 63 ++++-- gtests/net/packetdrill/script.h | 9 + .../tests/bsd/sctp/sctp_notifications.pkt | 21 ++ 6 files changed, 280 insertions(+), 64 deletions(-) create mode 100644 gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index 357e4722..1f7ed9d5 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -278,6 +278,9 @@ nxt_ppid return NXT_PPID; nxt_length return NXT_LENGTH; recvv_rcvinfo return RECVV_RCVINFO; recvv_nxtinfo return RECVV_NXTINFO; +sse_type return SSE_TYPE; +sse_flags return SSE_FLAGS; +sse_length return SSE_LENGTH; CHUNK return CHUNK; DATA return DATA; INIT return INIT; diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 35c278a3..3fefbb34 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -547,6 +547,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> RCV_SID RCV_SSN RCV_FLAGS RCV_PPID RCV_TSN RCV_CUMTSN RCV_CONTEXT %token <reserved> NXT_SID NXT_FLAGS NXT_PPID NXT_LENGTH %token <reserved> RECVV_RCVINFO RECVV_NXTINFO +%token <reserved> SSE_TYPE SSE_FLAGS SSE_LENGTH %token <floating> FLOAT %token <integer> INTEGER HEX_INTEGER %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR @@ -581,7 +582,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <string> function_name %type <expression_list> expression_list function_arguments %type <expression> expression binary_expression array -%type <expression> decimal_integer hex_integer +%type <expression> decimal_integer hex_integer data %type <expression> inaddr sockaddr msghdr iovec pollfd opt_revents %type <expression> linger l_onoff l_linger %type <expression> sctp_status sstat_state sstat_rwnd sstat_unackdata sstat_penddata @@ -602,6 +603,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <expression> sctp_prinfo sctp_authinfo pr_policy sctp_sendv_spa %type <expression> sctp_rcvinfo rcv_sid rcv_ssn rcv_flags rcv_ppid rcv_tsn rcv_cumtsn rcv_context %type <expression> sctp_nxtinfo nxt_sid nxt_flags nxt_ppid nxt_length sctp_recvv_rn +%type <expression> sctp_shutdown_event sse_type sse_flags sse_length %type <errno_info> opt_errno %type <chunk_list> sctp_chunk_list_spec %type <chunk_list_item> sctp_chunk_spec @@ -2546,7 +2548,7 @@ sockaddr #endif ipv4->sin_port = htons($10); if (inet_pton(AF_INET, $17, &ipv4->sin_addr) == 1) { - $$ = new_expression(EXPR_SOCKET_ADDRESS_IPV4); + $$ = new_expression(EXPR_SOCKET_ADDRESS_IPV4); $$->value.socket_address_ipv4 = ipv4; } else { free(ipv4); @@ -2571,6 +2573,11 @@ sockaddr } ; +data +: ELLIPSIS { new_expression(EXPR_ELLIPSIS); } +| sctp_shutdown_event { $$ = $1; } +; + msghdr : '{' MSG_NAME '(' ELLIPSIS ')' '=' ELLIPSIS ',' MSG_IOV '(' decimal_integer ')' '=' array ',' @@ -2588,18 +2595,18 @@ msghdr ; iovec -: '{' ELLIPSIS ',' decimal_integer '}' { +: '{' data ',' decimal_integer '}' { struct iovec_expr *iov_expr = calloc(1, sizeof(struct iovec_expr)); $$ = new_expression(EXPR_IOVEC); $$->value.iovec = iov_expr; - iov_expr->iov_base = new_expression(EXPR_ELLIPSIS); + iov_expr->iov_base = $2; iov_expr->iov_len = $4; } -| '{' IOV_BASE '=' ELLIPSIS ',' IOV_LEN '=' decimal_integer '}' { +| '{' IOV_BASE '=' data ',' IOV_LEN '=' decimal_integer '}' { struct iovec_expr *iov_expr = calloc(1, sizeof(struct iovec_expr)); $$ = new_expression(EXPR_IOVEC); $$->value.iovec = iov_expr; - iov_expr->iov_base = new_expression(EXPR_ELLIPSIS); + iov_expr->iov_base = $4; iov_expr->iov_len = $8; } ; @@ -3460,6 +3467,49 @@ sctp_recvv_rn } ; +sse_type +: SSE_TYPE '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("sse_type out of range"); + } + $$ = new_integer_expression($3, "%hu"); +} +| SSE_TYPE '=' WORD { + $$ = new_expression(EXPR_WORD); + $$->value.string = $3; +} +| SSE_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sse_flags +: SSE_FLAGS '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("sse_flags out of range"); + } + $$ = new_integer_expression($3, "%hu"); +} +| SSE_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sse_length +: SSE_LENGTH '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("sse_length out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SSE_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sctp_shutdown_event +: '{' sse_type ',' sse_flags ',' sse_length '}' { + $$ = new_expression(EXPR_SCTP_SHUTDOWN_EVENT); + $$->value.sctp_shutdown_event = calloc(1, sizeof(struct sctp_shutdown_event_expr)); + $$->value.sctp_shutdown_event->sse_type = $2; + $$->value.sctp_shutdown_event->sse_flags = $4; + $$->value.sctp_shutdown_event->sse_length = $6; +}; + opt_errno : { $$ = NULL; } | WORD note { diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index 30e43bf6..782f9a3f 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -1,3 +1,4 @@ + /* * Copyright 2013 Google Inc. * @@ -48,6 +49,11 @@ static int to_live_fd(struct state *state, int script_fd, int *live_fd, char **error); +#if defined(__FreeBSD__) +static int check_sctp_notification(struct iovec *iov, struct expression *iovec_expr, + char **error); +#endif + /* Provide a wrapper for the Linux gettid() system call (glibc does not). */ static pid_t gettid(void) @@ -453,7 +459,8 @@ static int iovec_new(struct expression *expression, iov_expr = list->expression->value.iovec; - assert(iov_expr->iov_base->type == EXPR_ELLIPSIS); + assert(iov_expr->iov_base->type == EXPR_ELLIPSIS || + iov_expr->iov_base->type == EXPR_SCTP_SHUTDOWN_EVENT); assert(iov_expr->iov_len->type == EXPR_INTEGER); len = iov_expr->iov_len->value.num; @@ -1389,6 +1396,9 @@ static int syscall_recvmsg(struct state *state, struct syscall_spec *syscall, asprintf(error, "Expected msg_flags 0x%08X but got 0x%08X", expected_msg_flags, msg->msg_flags); goto error_out; + } else if (msg->msg_flags & MSG_NOTIFICATION) { + if (check_sctp_notification(msg->msg_iov, msg_expression->value.msghdr->msg_iov, error)) + goto error_out; } status = STATUS_OK; @@ -2552,7 +2562,7 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, if (live_optlen != script_optlen) { asprintf(error, "optlen: expected: %d actual: %d", - (int)script_optlen, (int)live_optlen); + (int)script_optlen, (int)live_optlen); free(live_optval); return STATUS_ERR; } @@ -2721,15 +2731,15 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, case EXPR_SCTP_RTOINFO: rtoinfo.srto_assoc_id = 0; if (get_u32(val_expression->value.sctp_rtoinfo->srto_initial, - &rtoinfo.srto_initial, error)) { + &rtoinfo.srto_initial, error)) { return STATUS_ERR; } if (get_u32(val_expression->value.sctp_rtoinfo->srto_max, - &rtoinfo.srto_max, error)) { + &rtoinfo.srto_max, error)) { return STATUS_ERR; } if (get_u32(val_expression->value.sctp_rtoinfo->srto_min, - &rtoinfo.srto_min, error)) { + &rtoinfo.srto_min, error)) { return STATUS_ERR; } optval = &rtoinfo; @@ -2739,23 +2749,23 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, case EXPR_SCTP_ASSOCPARAMS: assocparams.sasoc_assoc_id = 0; if (get_u16(val_expression->value.sctp_assocparams->sasoc_asocmaxrxt, - &assocparams.sasoc_asocmaxrxt, error)) { + &assocparams.sasoc_asocmaxrxt, error)) { return STATUS_ERR; } if (get_u16(val_expression->value.sctp_assocparams->sasoc_number_peer_destinations, - &assocparams.sasoc_number_peer_destinations, error)) { + &assocparams.sasoc_number_peer_destinations, error)) { return STATUS_ERR; } if (get_u32(val_expression->value.sctp_assocparams->sasoc_peer_rwnd, - &assocparams.sasoc_peer_rwnd, error)) { + &assocparams.sasoc_peer_rwnd, error)) { return STATUS_ERR; } if (get_u32(val_expression->value.sctp_assocparams->sasoc_local_rwnd, - &assocparams.sasoc_local_rwnd, error)) { + &assocparams.sasoc_local_rwnd, error)) { return STATUS_ERR; } if (get_u32(val_expression->value.sctp_assocparams->sasoc_cookie_life, - &assocparams.sasoc_cookie_life, error)) { + &assocparams.sasoc_cookie_life, error)) { return STATUS_ERR; } optval = &assocparams; @@ -2786,7 +2796,7 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, case EXPR_SCTP_ASSOC_VALUE: assoc_value.assoc_id = 0; if (get_u32(val_expression->value.sctp_assoc_value->assoc_value, - &assoc_value.assoc_value, error)) { + &assoc_value.assoc_value, error)) { return STATUS_ERR; } optval = &assoc_value; @@ -2796,11 +2806,11 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, case EXPR_SCTP_STREAM_VALUE: stream_value.assoc_id = 0; if (get_u16(val_expression->value.sctp_stream_value->stream_id, - &stream_value.stream_id, error)) { + &stream_value.stream_id, error)) { return STATUS_ERR; } if (get_u16(val_expression->value.sctp_stream_value->stream_value, - &stream_value.stream_value, error)) { + &stream_value.stream_value, error)) { return STATUS_ERR; } optval = &stream_value; @@ -2810,11 +2820,11 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, case EXPR_SCTP_SACKINFO: sack_info.sack_assoc_id = 0; if (get_u32(val_expression->value.sctp_sack_info->sack_delay, - &sack_info.sack_delay, error)) { + &sack_info.sack_delay, error)) { return STATUS_ERR; } if (get_u32(val_expression->value.sctp_sack_info->sack_freq, - &sack_info.sack_freq, error)) { + &sack_info.sack_freq, error)) { return STATUS_ERR; } optval = &sack_info; @@ -2886,46 +2896,46 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, case EXPR_SCTP_PEER_ADDR_PARAMS: paddrparams.spp_assoc_id = 0; if (get_sockstorage_arg(val_expression->value.sctp_paddrparams->spp_address, - &paddrparams.spp_address, live_fd)) { + &paddrparams.spp_address, live_fd)) { asprintf(error, "can't determine spp_address"); return STATUS_ERR; } if (get_u32(val_expression->value.sctp_paddrparams->spp_hbinterval, - &paddrparams.spp_hbinterval, error)) { + &paddrparams.spp_hbinterval, error)) { return STATUS_ERR; } if (get_u16(val_expression->value.sctp_paddrparams->spp_pathmaxrxt, - &paddrparams.spp_pathmaxrxt, error)) { + &paddrparams.spp_pathmaxrxt, error)) { return STATUS_ERR; } if (get_u32(val_expression->value.sctp_paddrparams->spp_pathmtu, - &paddrparams.spp_pathmtu, error)) { + &paddrparams.spp_pathmtu, error)) { return STATUS_ERR; } if (get_u32(val_expression->value.sctp_paddrparams->spp_flags, - &paddrparams.spp_flags, error)) { + &paddrparams.spp_flags, error)) { return STATUS_ERR; } #ifdef __FreeBSD__ if (get_u32(val_expression->value.sctp_paddrparams->spp_ipv6_flowlabel, - &paddrparams.spp_ipv6_flowlabel, error)) { + &paddrparams.spp_ipv6_flowlabel, error)) { return STATUS_ERR; } if (get_u8(val_expression->value.sctp_paddrparams->spp_dscp, - &paddrparams.spp_dscp, error)) { + &paddrparams.spp_dscp, error)) { return STATUS_ERR; } #endif #ifdef linux if (get_u32(val_expression->value.sctp_paddrparams->spp_ipv6_flowlabel, - &spp_ipv6_flowlabel, error)) { + &spp_ipv6_flowlabel, error)) { return STATUS_ERR; } else if (spp_ipv6_flowlabel != 0) { asprintf(error, "Linux doesn't support paddrparams.spp_ipv6_flowlabel"); return STATUS_ERR; } if (get_u8(val_expression->value.sctp_paddrparams->spp_dscp, - &spp_dscp, error)) { + &spp_dscp, error)) { return STATUS_ERR; } else if (spp_dscp != 0) { asprintf(error, "Linux doesn't support paddrparams.spp_dscp"); @@ -3679,6 +3689,85 @@ static int check_sctp_nxtinfo(struct sctp_nxtinfo_expr *expr, } #endif +#if defined(__FreeBSD__) +static int check_sctp_shutdown_event(struct sctp_shutdown_event_expr *expr, + struct sctp_shutdown_event *sctp_event, + char **error) { + if (expr->sse_type->type != EXPR_ELLIPSIS) { + u16 sse_type; + + if (get_u16(expr->sse_type, &sse_type, error)) { + return STATUS_ERR; + } + if (sctp_event->sse_type != sse_type) { + asprintf(error, "sctp_shutdown_event.sse_type: expected: %hu actual: %hu", + sse_type, sctp_event->sse_type); + return STATUS_ERR; + } + } + if (expr->sse_flags->type != EXPR_ELLIPSIS) { + u16 sse_flags; + + if (get_u16(expr->sse_flags, &sse_flags, error)) { + return STATUS_ERR; } + if (sctp_event->sse_flags != sse_flags) { + asprintf(error, "sctp_shutdown_event.sse_flags: expected: %hu actual: %hu", + sse_flags, sctp_event->sse_flags); + return STATUS_ERR; + } + } + if (expr->sse_length->type != EXPR_ELLIPSIS) { + u32 sse_length; + + if (get_u32(expr->sse_length, &sse_length, error)) { + return STATUS_ERR; + } + if (sctp_event->sse_length != sse_length) { + asprintf(error, "sctp_shutdown_event.sse_length: expected: %u actual: %u", + sse_length, sctp_event->sse_length); + return STATUS_ERR; + } + } + return STATUS_OK; +} +#endif + +#if defined(__FreeBSD__) +static int check_sctp_notification(struct iovec *iov, + struct expression *iovec_expr, + char **error) { + struct expression_list *iovec_expr_list; + struct expression *script_iov, *script_iov_base; + if (iovec_expr == NULL) + return STATUS_ERR; + if (check_type(iovec_expr, EXPR_LIST, error)) + return STATUS_ERR; + iovec_expr_list = iovec_expr->value.list; + int i=0; + while (iovec_expr_list != NULL) { + script_iov = iovec_expr_list->expression; + if (check_type(script_iov, EXPR_IOVEC, error)) + return STATUS_ERR; + script_iov_base = script_iov->value.iovec->iov_base; + switch (script_iov_base->type) { + case EXPR_SCTP_SHUTDOWN_EVENT: + if (check_sctp_shutdown_event(script_iov_base->value.sctp_shutdown_event, + (struct sctp_shutdown_event *) iov->iov_base, + error)) + return STATUS_ERR; + break; + case EXPR_ELLIPSIS: + break; + default: + break; + } + i++; + iovec_expr_list = iovec_expr_list->next; + } + return STATUS_OK; +} +#endif + #if defined(__FreeBSD__) static int check_sctp_recvv_rn(struct sctp_recvv_rn_expr *expr, struct sctp_recvv_rn *sctp_recvv_rn, @@ -3745,10 +3834,10 @@ static int syscall_sctp_recvv(struct state *state, struct syscall_spec *syscall, } else if (info_expr->type == EXPR_SCTP_RECVV_RN) { info = &recvv_rn; } else { - return STATUS_ERR; + goto error_out; } if (u32_bracketed_arg(args, 6, &infolen, error)) { - return STATUS_ERR; + goto error_out; } infotype = 0; flags = 0; @@ -3763,17 +3852,12 @@ static int syscall_sctp_recvv(struct state *state, struct syscall_spec *syscall, result = sctp_recvv(live_fd, iov, iovlen, (struct sockaddr *)from, &fromlen, info, &infolen, &infotype, &flags); - iovec_free(iov, script_iovec_list_len); + if (end_syscall(state, syscall, CHECK_EXACT, result, error)) + goto error_out; - if (end_syscall(state, syscall, CHECK_EXACT, result, error)) { - free(from); - return STATUS_ERR; - } if (from != NULL) { - if (check_sockaddr(addr_expr, from, error)) { - free(from); - return STATUS_ERR; - } + if (check_sockaddr(addr_expr, from, error)) + goto error_out; } free(from); @@ -3781,64 +3865,72 @@ static int syscall_sctp_recvv(struct state *state, struct syscall_spec *syscall, if (infotype_expr->type != EXPR_ELLIPSIS) { s32 script_infotype; if (s32_bracketed_arg(args, 7, &script_infotype, error)) - return STATUS_ERR; + goto error_out; if (infotype != script_infotype) { asprintf(error, "sctp_recvv infotype: expected: %u actual: %u", script_infotype, infotype); - return STATUS_ERR; + goto error_out; } } switch(infotype) { case SCTP_RECVV_NOINFO: if (infolen != 0) { asprintf(error, "infolen returned bad size for null. expected 0, actual %u", infolen); - return STATUS_ERR; + goto error_out; } break; case SCTP_RECVV_RCVINFO: if (infolen != sizeof(struct sctp_rcvinfo)) { asprintf(error, "infolen returned bad size for sctp_rcvinfo. expected %u, actual %u", sizeof(struct sctp_rcvinfo), infolen); - return STATUS_ERR; + goto error_out; } if (check_sctp_rcvinfo(info_expr->value.sctp_rcvinfo, info, error)) - return STATUS_ERR; + goto error_out; break; case SCTP_RECVV_NXTINFO: if (infolen != sizeof(struct sctp_nxtinfo)) { asprintf(error, "infolen returned bad size for sctp_nxtinfo. expected %u, actual %u", sizeof(struct sctp_nxtinfo), infolen); - return STATUS_ERR; + goto error_out; } if (check_sctp_nxtinfo(info_expr->value.sctp_nxtinfo, info, error)) - return STATUS_ERR; + goto error_out; break; case SCTP_RECVV_RN: if (infolen != sizeof(struct sctp_recvv_rn)) { asprintf(error, "infolen returned bad size for sctp_recvv_rn. expected %u, actual %u", sizeof(struct sctp_recvv_rn), infolen); - return STATUS_ERR; + goto error_out; } if (check_sctp_recvv_rn(info_expr->value.sctp_recvv_rn, info, error)) - return STATUS_ERR; + goto error_out; break; default: - return STATUS_ERR; + goto error_out; break; } flags_expr = get_arg(args, 8, error); if (flags_expr->type != EXPR_ELLIPSIS) { s32 script_flags; if (s32_bracketed_arg(args, 8, &script_flags, error)) - return STATUS_ERR; + goto error_out; if (flags != script_flags) { asprintf(error, "sctp_recvv flags bad return value. expected %d, actual %d", script_flags, flags); - return STATUS_ERR; + goto error_out; + } else if (flags & MSG_NOTIFICATION) { + if (check_sctp_notification(iov, iovec_expr_list, error)) + goto error_out; } } + iovec_free(iov, script_iovec_list_len); return STATUS_OK; +error_out: + free(from); + iovec_free(iov, script_iovec_list_len); + return STATUS_ERR; #else asprintf(error, "sctp_recvv is not supported"); return STATUS_ERR; diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c index 82f724ae..eaeea6ae 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -85,6 +85,7 @@ struct expression_type_entry expression_type_table[] = { { EXPR_SCTP_RCVINFO, "sctp_rcvinfo" }, { EXPR_SCTP_NXTINFO, "sctp_nxtinfo" }, { EXPR_SCTP_RECVV_RN, "sctp_recvv_rn " }, + { EXPR_SCTP_SHUTDOWN_EVENT, "sctp_shutdown_event"}, { NUM_EXPR_TYPES, NULL} }; @@ -416,6 +417,11 @@ void free_expression(struct expression *expression) free_expression(expression->value.sctp_recvv_rn->recvv_rcvinfo); free_expression(expression->value.sctp_recvv_rn->recvv_nxtinfo); break; + case EXPR_SCTP_SHUTDOWN_EVENT: + free_expression(expression->value.sctp_shutdown_event->sse_type); + free_expression(expression->value.sctp_shutdown_event->sse_flags); + free_expression(expression->value.sctp_shutdown_event->sse_length); + break; case EXPR_WORD: assert(expression->value.string); free(expression->value.string); @@ -1244,19 +1250,18 @@ static int evaluate_sctp_recvv_rn_expression(struct expression *in, struct expression *out, char **error) { - struct sctp_recvv_rn_expr *in_rn; - struct sctp_recvv_rn_expr *out_rn; + struct sctp_recvv_rn_expr *in_rn; + struct sctp_recvv_rn_expr *out_rn; - assert(in->type == EXPR_SCTP_RECVV_RN); - assert(in->value.sctp_recvv_rn); - assert(out->type == EXPR_SCTP_RECVV_RN); + assert(in->type == EXPR_SCTP_RECVV_RN); + assert(in->value.sctp_recvv_rn); + assert(out->type == EXPR_SCTP_RECVV_RN); - out->value.sctp_recvv_rn = calloc(1, sizeof(struct sctp_recvv_rn_expr)); - - in_rn = in->value.sctp_recvv_rn; - out_rn = out->value.sctp_recvv_rn; - - if (evaluate(in_rn->recvv_rcvinfo, + out->value.sctp_recvv_rn = calloc(1, sizeof(struct sctp_recvv_rn_expr)); + in_rn = in->value.sctp_recvv_rn; + out_rn = out->value.sctp_recvv_rn; + + if (evaluate(in_rn->recvv_rcvinfo, &out_rn->recvv_rcvinfo, error)) return STATUS_ERR; @@ -1267,6 +1272,39 @@ static int evaluate_sctp_recvv_rn_expression(struct expression *in, return STATUS_OK; } + +static int evaluate_sctp_shutdown_event_expression(struct expression *in, + struct expression *out, + char **error) +{ + struct sctp_shutdown_event_expr *in_event; + struct sctp_shutdown_event_expr *out_event; + + assert(in->type == EXPR_SCTP_SHUTDOWN_EVENT); + assert(in->value.sctp_shutdown_event); + assert(out->type == EXPR_SCTP_SHUTDOWN_EVENT); + + out->value.sctp_shutdown_event = calloc(1, sizeof(struct sctp_shutdown_event_expr)); + + in_event = in->value.sctp_shutdown_event; + out_event = out->value.sctp_shutdown_event; + + if (evaluate(in_event->sse_type, + &out_event->sse_type, + error)) + return STATUS_ERR; + if (evaluate(in_event->sse_flags, + &out_event->sse_flags, + error)) + return STATUS_ERR; + if (evaluate(in_event->sse_length, + &out_event->sse_length, + error)) + return STATUS_ERR; + + return STATUS_OK; +} + static int evaluate(struct expression *in, struct expression **out_ptr, char **error) { @@ -1349,6 +1387,9 @@ static int evaluate(struct expression *in, case EXPR_SCTP_RECVV_RN: result = evaluate_sctp_recvv_rn_expression(in, out, error); break; + case EXPR_SCTP_SHUTDOWN_EVENT: + result = evaluate_sctp_shutdown_event_expression(in, out, error); + break; case EXPR_WORD: out->type = EXPR_INTEGER; if (symbol_to_int(in->value.string, diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h index c47ec124..effbd571 100644 --- a/gtests/net/packetdrill/script.h +++ b/gtests/net/packetdrill/script.h @@ -65,6 +65,7 @@ enum expression_t { EXPR_SCTP_RCVINFO, /* struct sctp_rcvinfo for syscall sctp_recvv */ EXPR_SCTP_NXTINFO, /* struct sctp_nxtinfo for syscall sctp_recvv */ EXPR_SCTP_RECVV_RN, /* struct sctp_recvv_rn for syscall sctp_recvv */ + EXPR_SCTP_SHUTDOWN_EVENT, /* expression tree for sctp_shutdown_event */ NUM_EXPR_TYPES, }; /* Convert an expression type to a human-readable string */ @@ -103,6 +104,7 @@ struct expression { struct sctp_rcvinfo_expr *sctp_rcvinfo; struct sctp_nxtinfo_expr *sctp_nxtinfo; struct sctp_recvv_rn_expr *sctp_recvv_rn; + struct sctp_shutdown_event_expr *sctp_shutdown_event; } value; const char *format; /* the printf format for printing the value */ }; @@ -299,6 +301,13 @@ struct sctp_recvv_rn_expr { struct expression *recvv_nxtinfo; }; +/* Parse tree for sctp_shutdown_event for notifications. */ +struct sctp_shutdown_event_expr { + struct expression *sse_type; + struct expression *sse_flags; + struct expression *sse_length; +}; + /* The errno-related info from strace to summarize a system call error */ struct errno_spec { const char *errno_macro; /* errno symbol (C macro name) */ diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt new file mode 100644 index 00000000..d6662b38 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_notifications.pkt @@ -0,0 +1,21 @@ ++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 +// Check the handshake with an empty(!) cookie ++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) ++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=1, is=1, 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 +//enable shutdown events ++0.0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=1}, 8) = 0 +// Tear down the association ++0.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=0] +* > sctp: SHUTDOWN_ACK[flgs=0] ++0.0 < sctp: SHUTDOWN_COMPLETE[flgs=0] ++0.0 recvmsg(3, {msg_name(...)=..., + msg_iov(1)=[{iov_base={sse_type=SCTP_SHUTDOWN_EVENT, sse_flags=0, sse_length=12}, iov_len=1000}], + msg_flags=MSG_NOTIFICATION|MSG_EOR}, 0) = 12 +//+0.0 sctp_recvv(3, [{iov_base={sse_type=SCTP_SHUTDOWN_EVENT, sse_flags=1, sse_length=12}, iov_len=1000}], 1, +//..., 20, NULL, [0], [SCTP_RECVV_NOINFO], [MSG_NOTIFICATION|MSG_EOR]) = 12 -- GitLab