diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index f31c6d0f86ef82262248c2a6a45e444fd29b03c4..cc94918d6ffe3730631e20d34a9f0f903caf2fcb 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -306,6 +306,12 @@ sac_outbound_streams return SAC_OUTBOUND_STREAMS; sac_inbound_streams return SAC_INBOUND_STREAMS; sac_assoc_id return SAC_ASSOC_ID; sac_info return SAC_INFO; +sre_type return SRE_TYPE; +sre_flags return SRE_FLAGS; +sre_length return SRE_LENGTH; +sre_error return SRE_ERROR; +sre_assoc_id return SRE_ASSOC_ID; +sre_data return SRE_DATA; auth_type return AUTH_TYPE; auth_flags return AUTH_FLAGS; auth_length return AUTH_LENGTH; diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 14838d613145e41603fb7db3acbd9eb70e1bbf58..f88812d586196682fed3cc2258085091542d4f76 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -557,6 +557,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> SAC_INBOUND_STREAMS SAC_ASSOC_ID SAC_INFO %token <reserved> SSFE_TYPE SSFE_FLAGS SSFE_LENGTH SSFE_ERROR SSFE_INFO SSFE_ASSOC_ID SSFE_DATA %token <reserved> AUTH_TYPE AUTH_FLAGS AUTH_LENGTH AUTH_INDICATION AUTH_ASSOC_ID +%token <reserved> SRE_TYPE SRE_FLAGS SRE_LENGTH SRE_ERROR SRE_ASSOC_ID SRE_DATA %token <floating> FLOAT %token <integer> INTEGER HEX_INTEGER %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR @@ -619,6 +620,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <expression> sac_inbound_streams sac_assoc_id sac_info %type <expression> sctp_send_failed_event ssfe_type ssfe_flags ssfe_length ssfe_error ssfe_assoc_id %type <expression> sctp_authkey_event auth_type auth_flags auth_length auth_keynumber auth_indication auth_assoc_id +%type <expression> sctp_remote_error sre_type sre_flags sre_length sre_error sre_assoc_id sre_data %type <errno_info> opt_errno %type <chunk_list> sctp_chunk_list_spec %type <chunk_list_item> sctp_chunk_spec @@ -2594,6 +2596,7 @@ sockaddr data : ELLIPSIS { new_expression(EXPR_ELLIPSIS); } | sctp_assoc_change { $$ = $1; } +| sctp_remote_error { $$ = $1; } | sctp_shutdown_event { $$ = $1; } | sctp_sender_dry_event { $$ = $1; } | sctp_send_failed_event { $$ = $1; } @@ -3899,6 +3902,78 @@ sac_inbound_streams ',' sac_assoc_id ',' sac_info '}' { } ; +sre_type +: SRE_TYPE '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("sre_type out of range"); + } + $$ = new_integer_expression($3, "%hu"); +} +| SRE_TYPE '=' WORD { + $$ = new_expression(EXPR_WORD); + $$->value.string = $3; +} +| SRE_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sre_flags +: SRE_FLAGS '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("sre_flags out of range"); + } + $$ = new_integer_expression($3, "%hu"); +} +| SRE_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sre_length +: SRE_LENGTH '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("sre_length out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SRE_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sre_error +: SRE_ERROR '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("sre_error out of range"); + } + $$ = new_integer_expression($3, "%hu"); +} +| SRE_ERROR '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sre_assoc_id +: SRE_ASSOC_ID '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("sre_assoc_id out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SRE_ASSOC_ID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sre_data +: SRE_DATA '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +| SRE_DATA '=' array { $$ = $3; } +; + +sctp_remote_error +: '{' sre_type ',' sre_flags ',' sre_length ',' sre_error ',' sre_assoc_id ',' sre_data '}' { + $$ = new_expression(EXPR_SCTP_REMOTE_ERROR); + $$->value.sctp_remote_error = calloc(1, sizeof(struct sctp_remote_error_expr)); + $$->value.sctp_remote_error->sre_type = $2; + $$->value.sctp_remote_error->sre_flags = $4; + $$->value.sctp_remote_error->sre_length = $6; + $$->value.sctp_remote_error->sre_error = $8; + $$->value.sctp_remote_error->sre_assoc_id = $10; + $$->value.sctp_remote_error->sre_data = $12; +} +; + opt_errno : { $$ = NULL; } | WORD note { diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index b26843f797aff42dae5ca68a39799e9d4fdf11ce..fe1c166e48be4a9d8f400438ba56648ac8e73d23 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -527,6 +527,7 @@ static int iovec_new(struct expression *expression, assert(iov_expr->iov_base->type == EXPR_ELLIPSIS || iov_expr->iov_base->type == EXPR_SCTP_ASSOC_CHANGE || + iov_expr->iov_base->type == EXPR_SCTP_REMOTE_ERROR || iov_expr->iov_base->type == EXPR_SCTP_SHUTDOWN_EVENT || iov_expr->iov_base->type == EXPR_SCTP_AUTHKEY_EVENT || iov_expr->iov_base->type == EXPR_SCTP_SENDER_DRY_EVENT || @@ -3339,6 +3340,46 @@ static int check_sctp_nxtinfo(struct sctp_nxtinfo_expr *expr, } #endif +static int check_u8array_expr(struct expression *expr_list, u8 *data, size_t data_len, char *val_name, char **error) { + if ( expr_list->type != EXPR_ELLIPSIS) { + struct expression *expr = NULL; + unsigned int i; + + switch(expr_list->type) { + case EXPR_LIST: + if (data_len != expression_list_length(expr_list->value.list)) { + asprintf(error, "%s length: expected: %u actual %zu", + val_name, expression_list_length(expr_list->value.list), data_len); + return STATUS_ERR; + } + for (i = 0; i < data_len; i++) { + expr = get_arg(expr_list->value.list, i, error); + if (expr->type != EXPR_ELLIPSIS) { + u8 script_val; + + if (get_u8(expr, &script_val, error)) { + return STATUS_ERR; + } + if (script_val != data[i]) { + asprintf(error, "%s[%d]: expected: %hhu actual: %hhu", + val_name, i, script_val, data[i]); + return STATUS_ERR; + } + } + } + break; + case EXPR_NULL: + if (data != NULL) + return STATUS_ERR; + break; + default: asprintf(error, "Bad expressiontype for sac_info"); + return STATUS_ERR; + break; + } + } + return STATUS_OK; +} + #if defined(__FreeBSD__) || defined(linux) static int check_sctp_assoc_change(struct sctp_assoc_change_expr *expr, struct sctp_assoc_change *sctp_event, @@ -3367,40 +3408,36 @@ static int check_sctp_assoc_change(struct sctp_assoc_change_expr *expr, if (check_u32_expr(expr->sac_assoc_id, sctp_event->sac_assoc_id, "sctp_assoc_change.sac_assoc_id", error)) return STATUS_ERR; - if ( expr->sac_info->type != EXPR_ELLIPSIS) { - size_t infolen; - struct expression *info_expr = NULL; - unsigned int i; - - infolen = sctp_event->sac_length - sizeof(struct sctp_assoc_change); - switch(expr->sac_info->type) { - case EXPR_LIST: - if (infolen != expression_list_length(expr->sac_info->value.list)) { - asprintf(error, "sctp_assoc_change.sac_info length: expected: %u actual %zu", - expression_list_length(expr->sac_info->value.list), infolen); - return STATUS_ERR; - } - for (i = 0; i < infolen; i++) { - info_expr = get_arg(expr->sac_info->value.list, i, error); - if (info_expr->type != EXPR_ELLIPSIS) { - u8 script_val; + if (check_u8array_expr(expr->sac_info, sctp_event->sac_info, sctp_event->sac_length - sizeof(struct sctp_assoc_change), + "sctp_assoc_change.sac_info", error)) + return STATUS_ERR; + return STATUS_OK; +} +#endif - if (get_u8(info_expr, &script_val, error)) { - return STATUS_ERR; - } - if (script_val != sctp_event->sac_info[i]) { - asprintf(error, "sctp_assoc_change.sac_info[%d]: expected: %hhu actual: %hhu", - i, script_val, sctp_event->sac_info[i]); - return STATUS_ERR; - } - } - } - break; - default: asprintf(error, "Bad expressiontype for sac_info"); +#if defined(__FreeBSD__) || defined(linux) +static int check_sctp_remote_error(struct sctp_remote_error_expr *expr, + struct sctp_remote_error *sctp_event, + char **error) { + if (check_u16_expr(expr->sre_type, sctp_event->sre_type, + "sctp_remote_error.sre_type", error)) + return STATUS_ERR; + if (check_u16_expr(expr->sre_flags, sctp_event->sre_flags, + "sctp_remote_error.sre_flags", error)) + return STATUS_ERR; + if (check_u32_expr(expr->sre_length, sctp_event->sre_length, + "sctp_remote_error.sre_length", error)) + return STATUS_ERR; + if (check_u16_expr(expr->sre_error, sctp_event->sre_error, + "sctp_remote_error.sre_error", error)) + return STATUS_ERR; + if (check_u32_expr(expr->sre_assoc_id, sctp_event->sre_assoc_id, + "sctp_remote_error.sre_assoc_id", error)) + return STATUS_ERR; + if (check_u8array_expr(expr->sre_data, sctp_event->sre_data, sctp_event->sre_length - sizeof(struct sctp_remote_error), + "sctp_remote_error.sre_data", error)) return STATUS_ERR; - break; - } - } + return STATUS_OK; } #endif @@ -3526,6 +3563,12 @@ static int check_sctp_notification(struct iovec *iov, error)) return STATUS_ERR; break; + case EXPR_SCTP_REMOTE_ERROR: + if (check_sctp_remote_error(script_iov_base->value.sctp_remote_error, + (struct sctp_remote_error *) iov->iov_base, + error)) + return STATUS_ERR; + break; case EXPR_SCTP_SHUTDOWN_EVENT: if (check_sctp_shutdown_event(script_iov_base->value.sctp_shutdown_event, (struct sctp_shutdown_event *) iov->iov_base, diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c index a20c7f14d4f2eda680fd327bcff566a2bf3c610a..0ed1f1e636c5bf5c0eec13b11fca5826caa4754e 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -87,6 +87,7 @@ struct expression_type_entry expression_type_table[] = { { EXPR_SCTP_NXTINFO, "sctp_nxtinfo" }, { EXPR_SCTP_RECVV_RN, "sctp_recvv_rn " }, { EXPR_SCTP_ASSOC_CHANGE, "sctp_assoc_change"}, + { EXPR_SCTP_REMOTE_ERROR, "sctp_remote_error"}, { EXPR_SCTP_SHUTDOWN_EVENT, "sctp_shutdown_event"}, { EXPR_SCTP_AUTHKEY_EVENT, "sctp_authkey_event"}, { EXPR_SCTP_SENDER_DRY_EVENT,"sctp_sender_dry_event"}, @@ -445,6 +446,14 @@ void free_expression(struct expression *expression) free_expression(expression->value.sctp_assoc_change->sac_assoc_id); free_expression(expression->value.sctp_assoc_change->sac_info); break; + case EXPR_SCTP_REMOTE_ERROR: + free_expression(expression->value.sctp_remote_error->sre_type); + free_expression(expression->value.sctp_remote_error->sre_flags); + free_expression(expression->value.sctp_remote_error->sre_length); + free_expression(expression->value.sctp_remote_error->sre_error); + free_expression(expression->value.sctp_remote_error->sre_assoc_id); + free_expression(expression->value.sctp_remote_error->sre_data); + break; case EXPR_SCTP_SHUTDOWN_EVENT: free_expression(expression->value.sctp_shutdown_event->sse_type); free_expression(expression->value.sctp_shutdown_event->sse_flags); @@ -1384,8 +1393,8 @@ static int evaluate_sctp_recvv_rn_expression(struct expression *in, } static int evaluate_sctp_assoc_change_expression(struct expression *in, - struct expression *out, - char **error) + struct expression *out, + char **error) { struct sctp_assoc_change_expr *in_event; struct sctp_assoc_change_expr *out_event; @@ -1439,6 +1448,50 @@ static int evaluate_sctp_assoc_change_expression(struct expression *in, return STATUS_OK; } +static int evaluate_sctp_remote_error_expression(struct expression *in, + struct expression *out, + char **error) +{ + struct sctp_remote_error_expr *in_event; + struct sctp_remote_error_expr *out_event; + + assert(in->type == EXPR_SCTP_REMOTE_ERROR); + assert(in->value.sctp_remote_error); + assert(out->type == EXPR_SCTP_REMOTE_ERROR); + + out->value.sctp_remote_error = calloc(1, sizeof(struct sctp_remote_error_expr)); + + in_event = in->value.sctp_remote_error; + out_event = out->value.sctp_remote_error; + + if (evaluate(in_event->sre_type, + &out_event->sre_type, + error)) + return STATUS_ERR; + if (evaluate(in_event->sre_flags, + &out_event->sre_flags, + error)) + return STATUS_ERR; + if (evaluate(in_event->sre_length, + &out_event->sre_length, + error)) + return STATUS_ERR; + if (evaluate(in_event->sre_error, + &out_event->sre_error, + error)) + return STATUS_ERR; + if (evaluate(in_event->sre_assoc_id, + &out_event->sre_assoc_id, + error)) + return STATUS_ERR; + if (evaluate(in_event->sre_data, + &out_event->sre_data, + error)) + return STATUS_ERR; + + return STATUS_OK; +} + static int evaluate_sctp_shutdown_event_expression(struct expression *in, struct expression *out, char **error) @@ -1687,6 +1740,9 @@ static int evaluate(struct expression *in, case EXPR_SCTP_ASSOC_CHANGE: result = evaluate_sctp_assoc_change_expression(in, out, error); break; + case EXPR_SCTP_REMOTE_ERROR: + result = evaluate_sctp_remote_error_expression(in, out, error); + break; case EXPR_SCTP_SHUTDOWN_EVENT: result = evaluate_sctp_shutdown_event_expression(in, out, error); break; diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h index fdf4a7f148ccec9a679fadae22391a240a8c1667..82e269719df2aa46cb264ef5b702f7af173e2003 100644 --- a/gtests/net/packetdrill/script.h +++ b/gtests/net/packetdrill/script.h @@ -67,6 +67,7 @@ enum expression_t { EXPR_SCTP_NXTINFO, /* struct sctp_nxtinfo for syscall sctp_recvv */ EXPR_SCTP_RECVV_RN, /* struct sctp_recvv_rn for syscall sctp_recvv */ EXPR_SCTP_ASSOC_CHANGE, /* expression tree for sctp_assoc_change_event */ + EXPR_SCTP_REMOTE_ERROR, /* expression tree for sctp_remote_error_event */ EXPR_SCTP_SHUTDOWN_EVENT, /* expression tree for sctp_shutdown_event */ EXPR_SCTP_AUTHKEY_EVENT, /* expression tree for sctp_authentication_event */ EXPR_SCTP_SENDER_DRY_EVENT, /* expression tree for sctp_sender_dry_event */ @@ -111,6 +112,7 @@ struct expression { struct sctp_nxtinfo_expr *sctp_nxtinfo; struct sctp_recvv_rn_expr *sctp_recvv_rn; struct sctp_assoc_change_expr *sctp_assoc_change; + struct sctp_remote_error_expr *sctp_remote_error; struct sctp_shutdown_event_expr *sctp_shutdown_event; struct sctp_authkey_event_expr *sctp_authkey_event; struct sctp_sender_dry_event_expr *sctp_sender_dry_event; @@ -338,6 +340,15 @@ struct sctp_assoc_change_expr { struct expression *sac_info; }; +/* Parse tree for sctp_assoc_change for notifications. */ +struct sctp_remote_error_expr { + struct expression *sre_type; + struct expression *sre_flags; + struct expression *sre_length; + struct expression *sre_error; + struct expression *sre_assoc_id; + struct expression *sre_data; +}; /* Parse tree for sctp_shutdown_event for notifications. */ struct sctp_shutdown_event_expr { struct expression *sse_type; diff --git a/gtests/net/packetdrill/symbols_freebsd.c b/gtests/net/packetdrill/symbols_freebsd.c index d4ee1bef97420a83a94e6778e7aee9e60b66946c..5a54612f9c633b4af06d72afaa28fa6a2cca1504 100644 --- a/gtests/net/packetdrill/symbols_freebsd.c +++ b/gtests/net/packetdrill/symbols_freebsd.c @@ -168,7 +168,6 @@ struct int_symbol platform_symbols_table[] = { { SCTP_PEER_ADDR_CHANGE, "SCTP_PEER_ADDR_CHANGE" }, { SCTP_REMOTE_ERROR, "SCTP_REMOTE_ERROR" }, { SCTP_SEND_FAILED, "SCTP_SEND_FAILED" }, - { SCTP_ASSOC_CHANGE, "SCTP_ASSOC_CHANGE" }, { SCTP_SHUTDOWN_EVENT, "SCTP_SHUTDOWN_EVENT" }, { SCTP_SENDER_DRY_EVENT, "SCTP_SENDER_DRY_EVENT" }, { SCTP_SEND_FAILED_EVENT, "SCTP_SEND_FAILED_EVENT" }, @@ -177,7 +176,6 @@ struct int_symbol platform_symbols_table[] = { { SCTP_PARTIAL_DELIVERY_EVENT, "SCTP_PARTIAL_DELIVERY_EVENT" }, { SCTP_AUTHENTICATION_EVENT, "SCTP_AUTHENTICATION_EVENT" }, { SCTP_STREAM_RESET_EVENT, "SCTP_STREAM_RESET_EVENT" }, - { SCTP_SENDER_DRY_EVENT, "SCTP_SENDER_DRY_EVENT" }, { SCTP_NOTIFICATIONS_STOPPED_EVENT, "SCTP_NOTIFICATIONS_STOPPED_EVENT"}, { SCTP_ASSOC_RESET_EVENT, "SCTP_ASSOC_RESET_EVENT" }, { SCTP_STREAM_CHANGE_EVENT, "SCTP_STREAM_CHANGE_EVENT" }, diff --git a/gtests/net/packetdrill/tests/bsd/sctp/notifications/sctp_remote_error.pkt b/gtests/net/packetdrill/tests/bsd/sctp/notifications/sctp_remote_error.pkt new file mode 100644 index 0000000000000000000000000000000000000000..4d245235197b7f22585e70aa63536206b03cb82d --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/notifications/sctp_remote_error.pkt @@ -0,0 +1,19 @@ ++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 setsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_REMOTE_ERROR, se_on=1}, 8) = 0 ++0.0 getsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_REMOTE_ERROR, se_on=1}, [8]) = 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=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 + ++0.0 < sctp: ERROR[flgs=0, INVALID_STREAM_IDENTIFIER[sid=1]] + ++0.0 sctp_recvv(3, [{iov_base={sre_type=SCTP_REMOTE_ERROR, sre_flags=0, sre_length=32, sre_error=1, +sre_assoc_id=..., sre_data=[0x09, 0x00, 0x00 , 0x0C, 0x00, 0x01, 0x00 , 0x08, 0x00, 0x01, 0x00 , 0x00]}, iov_len=1000}], 1, ..., 20, NULL, [0], [SCTP_RECVV_NOINFO], +[MSG_NOTIFICATION|MSG_EOR]) = 32