diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 14a3a50f246a98964b4a0f5940685329564552ae..88dd99e7ae55d88c721594d970e9a7a3f52166ca 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -574,7 +574,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 @@ -2629,18 +2630,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 aee26de078065370c20fe72ac3f66bc9e8182eb1..baa01b540cfa68881544da486ffcd5a47fffb573 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, @@ -2161,6 +2194,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)); @@ -2248,6 +2287,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)) { @@ -2304,6 +2350,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 @@ -2415,7 +2464,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 6088b01fc4ad757018e05891deff74d569044270..9b895398c7988c37970496139ab9b98b9241fc6c 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -323,8 +323,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); @@ -650,6 +653,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, @@ -867,9 +900,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 1410b7dd89e75fa4dae7ab6573164fa89d713e61..04bca7879a8b8e95161c4f75ca906f9993972d4a 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 @@ -97,7 +97,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; @@ -190,6 +190,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 a2ec201acded1bd0da5a27c7f3419a827ed6b4d6..a86b7af248d28a0862d9a9e3da0ee66f3733e066 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 @@ -78,4 +78,10 @@ spp_hbinterval=300, spp_pathmaxrxt=..., spp_pathmtu=1468, spp_flags=521, spp_ipv +0 getsockopt(3, IPPROTO_SCTP, SCTP_INITMSG, {sinit_num_ostreams=..., sinit_max_instreams=2, sinit_max_attempts=2, sinit_max_init_timeo=30}, [8]) = 0 +0 getsockopt(3, IPPROTO_SCTP, SCTP_INITMSG, {sinit_num_ostreams=2, sinit_max_instreams=..., sinit_max_attempts=2, sinit_max_init_timeo=30}, [8]) = 0 +0 getsockopt(3, IPPROTO_SCTP, SCTP_INITMSG, {sinit_num_ostreams=2, sinit_max_instreams=2, sinit_max_attempts=..., sinit_max_init_timeo=30}, [8]) = 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