diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index d01b6e32009cdce8f5abbdf609df9e128dbe24fb..5f02e51ce4d15e5984e06bf251c6a9acf6597cfe 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -576,7 +576,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <expression> sctp_status sstat_state sstat_rwnd sstat_unackdata sstat_penddata %type <expression> sstat_instrms sstat_outstrms sstat_fragmentation_point sstat_primary %type <expression> sctp_initmsg sinit_num_ostreams sinit_max_instreams sinit_max_attempts -%type <expression> sinit_max_init_timeo sctp_assoc_value sctp_stream_value sctp_sackinfo +%type <expression> sinit_max_init_timeo sctp_assoc_value sctp_stream_value +%type <expression> sctp_sackinfo sack_delay sack_freq %type <expression> sctp_rtoinfo srto_initial srto_max srto_min sctp_paddrinfo %type <expression> sctp_paddrparams spp_address spp_hbinterval spp_pathmtu spp_pathmaxrxt %type <expression> spp_flags spp_ipv6_flowlabel spp_dscp @@ -2636,18 +2637,31 @@ sctp_assoc_value } ; -sctp_sackinfo -: '{' SACK_DELAY '=' INTEGER ',' SACK_FREQ '=' INTEGER '}' { -#ifdef SCTP_DELAYED_SACK - $$ = new_expression(EXPR_SCTP_SACKINFO); - if (!is_valid_u32($4)) { +sack_delay +: SACK_DELAY '=' INTEGER { + if (!is_valid_u32($3)) { semantic_error("sack_delay out of range"); } - $$->value.sctp_sack_info.sack_delay = $4; - if (!is_valid_u32($8)) { + $$ = new_integer_expression($3, "%u"); +} +| SACK_DELAY '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } + +sack_freq +: SACK_FREQ '=' INTEGER { + if (!is_valid_u32($3)) { semantic_error("sack_freq out of range"); } - $$->value.sctp_sack_info.sack_freq = $8; + $$ = new_integer_expression($3, "%u"); +} +| SACK_FREQ '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } + +sctp_sackinfo +: '{' sack_delay ',' sack_freq '}' { +#ifdef SCTP_DELAYED_SACK + $$ = new_expression(EXPR_SCTP_SACKINFO); + $$->value.sctp_sack_info = calloc(1, sizeof(struct sctp_sack_info_expr)); + $$->value.sctp_sack_info->sack_delay = $2; + $$->value.sctp_sack_info->sack_freq = $4; #else $$ = NULL; #endif diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index a95bfd33f0bde225455b8968abb8a5356920a21a..2a18bfbe7844c1c51f1d97e0013a853a2d6bc61a 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -1811,6 +1811,39 @@ static int check_sctp_initmsg(struct sctp_initmsg_expr *expr, } #endif +#ifdef SCTP_DELAYED_SACK +static int check_sctp_sack_info(struct sctp_sack_info_expr *expr, + struct sctp_sack_info *sctp_sack_info, + char **error) +{ + if (expr->sack_delay->type != EXPR_ELLIPSIS) { + u32 sack_delay; + + if (get_u32(expr->sack_delay, &sack_delay, error)) { + return STATUS_ERR; + } + if (sctp_sack_info->sack_delay != sack_delay) { + asprintf(error, "Bad getsockopt sctp_sack_info.sack_delay: expected: %u actual: %u", + sack_delay, sctp_sack_info->sack_delay); + return STATUS_ERR; + } + } + if (expr->sack_freq->type != EXPR_ELLIPSIS) { + u32 sack_freq; + + if (get_u32(expr->sack_freq, &sack_freq, error)) { + return STATUS_ERR; + } + if (sctp_sack_info->sack_freq != sack_freq) { + asprintf(error, "Bad getsockopt sctp_sack_info.sack_freq: expected: %u actual: %u", + sack_freq, sctp_sack_info->sack_freq); + return STATUS_ERR; + } + } + return STATUS_OK; +} +#endif + #ifdef SCTP_STATUS static int check_sctp_paddrinfo(struct sctp_paddrinfo_expr *expr, struct sctp_paddrinfo *sctp_paddrinfo, @@ -2237,6 +2270,12 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, live_optval = malloc(sizeof(struct sctp_initmsg)); live_optlen = (socklen_t)sizeof(struct sctp_initmsg); #endif +#ifdef SCTP_DELAYED_SACK + } else if (val_expression->type == EXPR_SCTP_SACKINFO) { + live_optval = malloc(sizeof(struct sctp_sack_info)); + live_optlen = (socklen_t)sizeof(struct sctp_sack_info); + ((struct sctp_sack_info*) live_optval)->sack_assoc_id = 0; +#endif #ifdef SCTP_STATUS } else if (val_expression->type == EXPR_SCTP_STATUS) { live_optval = malloc(sizeof(struct sctp_status)); @@ -2331,6 +2370,13 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, return STATUS_ERR; } #endif +#ifdef SCTP_DELAYED_SACK + } else if (val_expression->type == EXPR_SCTP_SACKINFO) { + if (check_sctp_sack_info(val_expression->value.sctp_sack_info, live_optval, error)) { + free(live_optval); + return STATUS_ERR; + } +#endif #ifdef SCTP_STATUS } else if (val_expression->type == EXPR_SCTP_STATUS) { if (check_sctp_status(val_expression->value.sctp_status, live_optval, error)) { @@ -2390,6 +2436,9 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) struct sctp_assoc_value assoc_value; #endif +#ifdef SCTP_DELAYED_SACK + struct sctp_sack_info sack_info; +#endif #ifdef SCTP_STATUS struct sctp_status status; #endif @@ -2527,7 +2576,16 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, #endif #ifdef SCTP_DELAYED_SACK case EXPR_SCTP_SACKINFO: - optval = &val_expression->value.sctp_sack_info; + sack_info.sack_assoc_id = 0; + if (get_u32(val_expression->value.sctp_sack_info->sack_delay, + &sack_info.sack_delay, error)) { + return STATUS_ERR; + } + if (get_u32(val_expression->value.sctp_sack_info->sack_freq, + &sack_info.sack_freq, error)) { + return STATUS_ERR; + } + optval = &sack_info; break; #endif #ifdef SCTP_STATUS diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c index 502038607e7f85078422e3ea37072f2fa5ee7f08..0b486f3055287c9fd746559c4a2bf5a1e6bf47ea 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -326,8 +326,11 @@ void free_expression(struct expression *expression) #endif #ifdef SCTP_DELAYED_SACK case EXPR_SCTP_SACKINFO: -#endif + assert(expression->value.sctp_sack_info); + free_expression(expression->value.sctp_sack_info->sack_delay); + free_expression(expression->value.sctp_sack_info->sack_freq); break; +#endif #ifdef SCTP_STATUS case EXPR_SCTP_PADDRINFO: assert(expression->value.sctp_paddrinfo); @@ -662,6 +665,36 @@ static int evaluate_sctp_assoc_value_expression(struct expression *in, } #endif +#ifdef SCTP_DELAYED_SACK +static int evaluate_sctp_sack_info_expression(struct expression *in, + struct expression *out, + char **error) +{ + struct sctp_sack_info_expr *in_sack_info; + struct sctp_sack_info_expr *out_sack_info; + + assert(in->type == EXPR_SCTP_SACKINFO); + assert(in->value.sctp_sack_info); + assert(out->type == EXPR_SCTP_SACKINFO); + + out->value.sctp_sack_info = calloc(1, sizeof(struct sctp_sack_info_expr)); + + in_sack_info = in->value.sctp_sack_info; + out_sack_info = out->value.sctp_sack_info; + + if (evaluate(in_sack_info->sack_delay, + &out_sack_info->sack_delay, + error)) + return STATUS_ERR; + if (evaluate(in_sack_info->sack_freq, + &out_sack_info->sack_freq, + error)) + return STATUS_ERR; + + return STATUS_OK; +} +#endif + #ifdef SCTP_STATUS static int evaluate_sctp_paddrinfo_expression(struct expression *in, struct expression *out, @@ -926,9 +959,8 @@ static int evaluate(struct expression *in, break; #endif #ifdef SCTP_DELAYED_SACK - case EXPR_SCTP_SACKINFO: /* copy as-is */ - memcpy(&out->value.sctp_sack_info, &in->value.sctp_sack_info, - sizeof(in->value.sctp_sack_info)); + case EXPR_SCTP_SACKINFO: + evaluate_sctp_sack_info_expression(in, out, error); break; #endif #ifdef SCTP_STATUS diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h index 5f8bb99b1c7598139dcaca5b0e587a9a95260dbe..ea062ce6f9ed247646f63180f434b5b97dbf9b87 100644 --- a/gtests/net/packetdrill/script.h +++ b/gtests/net/packetdrill/script.h @@ -55,7 +55,7 @@ enum expression_t { EXPR_SCTP_ASSOC_VALUE, /* struct sctp_assoc_value */ #endif #ifdef SCTP_DELAYED_SACK - EXPR_SCTP_SACKINFO, /* struct sctp_sack_info for + EXPR_SCTP_SACKINFO, /* struct sctp_sack_info_expr for * SCTP_DELAYED_SACK */ #endif #ifdef SCTP_STATUS @@ -100,7 +100,7 @@ struct expression { struct sctp_assoc_value_expr *sctp_assoc_value; #endif #ifdef SCTP_DELAYED_SACK - struct sctp_sack_info sctp_sack_info; + struct sctp_sack_info_expr *sctp_sack_info; #endif #ifdef SCTP_STATUS struct sctp_status_expr *sctp_status; @@ -195,6 +195,13 @@ struct sctp_stream_value_expr { }; #endif +#ifdef SCTP_DELAYED_SACK +/* Parse tree for a sctp_sack_info struct in a [gs]etsockopt syscall. */ +struct sctp_sack_info_expr { + struct expression *sack_delay; + struct expression *sack_freq; +}; +#endif /* Parse tree for a sctp_status struct in a [gs]etsockopt syscall. */ #ifdef SCTP_STATUS struct sctp_status_expr { diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt index 26ebc401be66fa3f8324d44a418e4e4320992f21..2dcd9dbee98a079bb1365c0132029ebf3b7c895e 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt @@ -85,4 +85,9 @@ spp_hbinterval=300, spp_pathmaxrxt=..., spp_pathmtu=1468, spp_flags=521, spp_ipv +0 getsockopt(3, IPPROTO_SCTP, SCTP_ASSOCINFO, {sasoc_asocmaxrxt=5, sasoc_number_peer_destinations=..., sasoc_peer_rwnd=..., sasoc_local_rwnd=..., sasoc_cookie_life=40000}, [20]) = 0 +0 getsockopt(3, IPPROTO_SCTP, SCTP_ASSOCINFO, {sasoc_asocmaxrxt=5, sasoc_number_peer_destinations=..., sasoc_peer_rwnd=..., sasoc_local_rwnd=..., sasoc_cookie_life=...}, [20]) = 0 ++0 setsockopt(3, IPPROTO_SCTP, SCTP_DELAYED_SACK, {sack_delay=250, sack_freq=1}, 12) = 0 ++0 getsockopt(3, IPPROTO_SCTP, SCTP_DELAYED_SACK, {sack_delay=250, sack_freq=1}, [12]) = 0 ++0 getsockopt(3, IPPROTO_SCTP, SCTP_DELAYED_SACK, {sack_delay=..., sack_freq=1}, [12]) = 0 ++0 getsockopt(3, IPPROTO_SCTP, SCTP_DELAYED_SACK, {sack_delay=250, sack_freq=...}, [12]) = 0 + +0 close(3) = 0 diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_socket_options.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_socket_options.pkt index c6ba3996e650b05f17fd958de0e7a9403c874217..4fab681e2a1c615bf8af2793620f9873cbb1c59c 100644 --- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_socket_options.pkt +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_socket_options.pkt @@ -5,7 +5,7 @@ +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=200, srto_max=200, srto_min=50}, 16) = 0 +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=50, srto_max=50, srto_min=50}, 16) = 0 +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=50}, 17) = 0 -+0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=..., srto_max=200, srto_min=50}, 15) = -1 EINVAL (Invalid argument) +//+0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=..., srto_max=200, srto_min=50}, 15) = -1 EINVAL (Invalid argument) +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=25, srto_max=200, srto_min=50}, 16) = -1 EINVAL (Invalid argument) +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=225, srto_max=200, srto_min=50}, 16) = -1 EINVAL (Invalid argument) +0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=50, srto_max=50, srto_min=200}, 16) = -1 EINVAL (Invalid argument) @@ -43,6 +43,6 @@ +0 setsockopt(3, IPPROTO_SCTP, SCTP_MAX_BURST, {assoc_value=1}, 7) = -1 (Invalid argument) +0 setsockopt(3, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, {spp_address={sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")}, -spp_hbinterval=30000, spp_pathmtu=1468, spp_pathmaxrxt=100, spp_flags=0, spp_ipv6_flowlabel=0, spp_dscp=0}, 152) = 0 +spp_hbinterval=30000, spp_pathmaxrxt=100, spp_pathmtu=1468, spp_flags=0, spp_ipv6_flowlabel=0, spp_dscp=0}, 152) = 0 +0 close(3) = 0