From 2c752a9f7b23157089755d1ce1ac5a719aa30183 Mon Sep 17 00:00:00 2001 From: Michael Tuexen <tuexen@fh-muenster.de> Date: Wed, 30 Sep 2015 17:10:08 +0200 Subject: [PATCH] Improve handling of sctp_assoc_value socket options. This patch allows to use sctp_assoc_value in getsockopt and also supports numeric constants as values. --- gtests/net/packetdrill/parser.y | 27 ++++---- gtests/net/packetdrill/run_system_call.c | 62 +++++++++++++++++-- gtests/net/packetdrill/script.c | 40 +++++++++--- gtests/net/packetdrill/script.h | 11 +++- .../bsd/sctp/sctp_get_socket_options.pkt | 2 +- 5 files changed, 112 insertions(+), 30 deletions(-) diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index a4438386..88deb4f9 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -565,9 +565,10 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <expression_list> expression_list function_arguments %type <expression> expression binary_expression array %type <expression> decimal_integer hex_integer -%type <expression> inaddr sockaddr msghdr iovec pollfd opt_revents +%type <expression> inaddr sockaddr msghdr iovec pollfd opt_revents %type <expression> linger l_onoff l_linger -%type <expression> sctp_status sctp_initmsg sctp_assocval sctp_sackinfo +%type <expression> sctp_status sctp_initmsg sctp_sackinfo +%type <expression> sctp_assoc_value %type <expression> sctp_rtoinfo srto_initial srto_max srto_min %type <errno_info> opt_errno %type <chunk_list> sctp_chunk_list_spec @@ -2333,7 +2334,7 @@ expression | sctp_initmsg { $$ = $1; } -| sctp_assocval { +| sctp_assoc_value { $$ = $1; } | sctp_sackinfo { @@ -2461,18 +2462,18 @@ opt_revents ; l_onoff -: ONOFF '=' INTEGER { +: ONOFF '=' INTEGER { if (!is_valid_s32($3)) { semantic_error("linger onoff out of range"); } else { - $$ = new_integer_expression($3, "%ld"); - } + $$ = new_integer_expression($3, "%ld"); + } } | ONOFF '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } ; l_linger -: LINGER '=' INTEGER { +: LINGER '=' INTEGER { if (!is_valid_s32($3)) { semantic_error("linger out of range"); } @@ -2560,14 +2561,12 @@ sctp_initmsg } ; -sctp_assocval -: '{' ASSOC_VALUE '=' INTEGER '}' { +sctp_assoc_value +: '{' ASSOC_VALUE '=' expression '}' { #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) - $$ = new_expression(EXPR_SCTP_ASSOCVAL); - if (!is_valid_u32($4)) { - semantic_error("assoc_value out of range"); - } - $$->value.sctp_assoc_value.assoc_value = $4; + $$ = new_expression(EXPR_SCTP_ASSOC_VALUE); + $$->value.sctp_assoc_value = calloc(1, sizeof(struct sctp_assoc_value_expr)); + $$->value.sctp_assoc_value->assoc_value = $4; #else $$ = NULL; #endif diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index bd09377e..a130404f 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -180,6 +180,26 @@ static int check_type(struct expression *expression, } } +/* Sets the value from the expression argument, checking that it is a + * valid u32, and matches the expected type. Returns STATUS_OK on + * success; on failure returns STATUS_ERR and sets error message. + */ +static int get_u32(struct expression *expression, + u32 *value, char **error) +{ + if (check_type(expression, EXPR_INTEGER, error)) + return STATUS_ERR; + if ((expression->value.num > UINT32_MAX) || + (expression->value.num < 0)) { + asprintf(error, + "Value out of range for 32-bit unsigned integer: %lld", + expression->value.num); + return STATUS_ERR; + } + *value = expression->value.num; + return STATUS_OK; +} + /* Sets the value from the expression argument, checking that it is a * valid s32 or u32, and matches the expected type. Returns STATUS_OK on * success; on failure returns STATUS_ERR and sets error message. @@ -1578,6 +1598,7 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, void *live_optval; socklen_t live_optlen; struct expression *val_expression; + if (check_arg_count(args, 5, error)) return STATUS_ERR; if (s32_arg(args, 0, &script_fd, error)) @@ -1609,6 +1630,12 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, live_optval = malloc(sizeof(val_expression->value.sctp_status)); live_optlen = (socklen_t)sizeof(val_expression->value.sctp_status); ((struct sctp_status*) live_optval)->sstat_assoc_id = val_expression->value.sctp_status.sstat_assoc_id; +#endif +#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) + } else if (val_expression->type == EXPR_SCTP_ASSOC_VALUE) { + live_optval = malloc(sizeof(struct sctp_assoc_value)); + live_optlen = (socklen_t)sizeof(struct sctp_assoc_value); + ((struct sctp_assoc_value *) live_optval)->assoc_id = 0; #endif } else { s32_bracketed_arg(args, 3, &script_optval, error); @@ -1633,7 +1660,7 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, struct expression *l_onoff = val_expression->value.linger->l_onoff; struct expression *l_linger = val_expression->value.linger->l_linger; struct linger *ling = live_optval; - int val_onoff = 0; + int val_onoff = 0; if (l_onoff->type == EXPR_INTEGER) { if (get_s32(l_onoff, &val_onoff, error)) { free(live_optval); @@ -1742,6 +1769,25 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, free(live_optval); return STATUS_ERR; } +#endif +#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) + } else if (val_expression->type == EXPR_SCTP_ASSOC_VALUE) { + struct expression *assoc_value = val_expression->value.sctp_assoc_value->assoc_value; + struct sctp_assoc_value *sctp_assoc_value = live_optval; + u32 value; + + if (assoc_value->type != EXPR_ELLIPSIS) { + if (get_u32(assoc_value, &value, error)) { + free(live_optval); + return STATUS_ERR; + } + if (sctp_assoc_value->assoc_value != value) { + asprintf(error, "Bad getsockopt sctp_assoc_value.assoc_value: expected: %u actual: %u", + value, sctp_assoc_value->assoc_value); + free(live_optval); + return STATUS_ERR; + } + } #endif } else { if (*(int*)live_optval != script_optval) { @@ -1761,6 +1807,7 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, int script_fd, live_fd, level, optname, optval_s32, optlen, result; void *optval = NULL; struct expression *val_expression; + struct sctp_assoc_value assoc_value; if (check_arg_count(args, 5, error)) return STATUS_ERR; @@ -1780,7 +1827,7 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, return STATUS_ERR; if (val_expression->type == EXPR_LINGER) { optval = malloc(sizeof(struct linger)); - get_s32(val_expression->value.linger->l_onoff, + get_s32(val_expression->value.linger->l_onoff, &(((struct linger*) optval)->l_onoff), error); get_s32(val_expression->value.linger->l_linger, &(((struct linger*) optval)->l_linger), error); @@ -1796,7 +1843,7 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, struct sctp_rtoinfo_expr *expr_rtoinfo = val_expression->value.sctp_rtoinfo; if (expr_rtoinfo->srto_initial->type != EXPR_INTEGER || expr_rtoinfo->srto_max->type != EXPR_INTEGER || - expr_rtoinfo->srto_min->type != EXPR_INTEGER) { + expr_rtoinfo->srto_min->type != EXPR_INTEGER) { asprintf(error, "Bad setsockopt, bad inputtype for rtoinfo"); return STATUS_ERR; } @@ -1812,8 +1859,13 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, optval = &val_expression->value.sctp_initmsg; #endif #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) - } else if (val_expression->type == EXPR_SCTP_ASSOCVAL) { - optval = &val_expression->value.sctp_assoc_value; + } else if (val_expression->type == 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)) { + return STATUS_ERR; + } + optval = &assoc_value; #endif #ifdef SCTP_DELAYED_SACK } else if (val_expression->type == EXPR_SCTP_SACKINFO) { diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c index d6d774ad..3592bd39 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -72,7 +72,7 @@ struct expression_type_entry expression_type_table[] = { { EXPR_SCTP_INITMSG, "sctp_initmsg"}, #endif #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) - { EXPR_SCTP_ASSOCVAL, "sctp_assocvalue"}, + { EXPR_SCTP_ASSOC_VALUE, "sctp_assoc_value"}, #endif #ifdef SCTP_DELAYED_SACK { EXPR_SCTP_SACKINFO, "sctp_sackinfo"}, @@ -297,12 +297,14 @@ void free_expression(struct expression *expression) free(expression->value.sctp_rtoinfo->srto_min); break; #endif +#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) + case EXPR_SCTP_ASSOC_VALUE: + free(expression->value.sctp_assoc_value->assoc_value); + break; +#endif #ifdef SCTP_INITMSG case EXPR_SCTP_INITMSG: #endif -#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) - case EXPR_SCTP_ASSOCVAL: -#endif #ifdef SCTP_DELAYED_SACK case EXPR_SCTP_SACKINFO: #endif @@ -495,6 +497,30 @@ static int evaluate_pollfd_expression(struct expression *in, return STATUS_OK; } +#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) +static int evaluate_sctp_assoc_value_expression(struct expression *in, + struct expression *out, + char **error) +{ + struct sctp_assoc_value_expr *in_value; + struct sctp_assoc_value_expr *out_value; + + assert(in->type == EXPR_SCTP_ASSOC_VALUE); + assert(in->value.sctp_assoc_value); + assert(out->type == EXPR_SCTP_ASSOC_VALUE); + + out->value.sctp_assoc_value = calloc(1, sizeof(struct sctp_assoc_value_expr)); + + in_value = in->value.sctp_assoc_value; + out_value = out->value.sctp_assoc_value; + + if (evaluate(in_value->assoc_value, &out_value->assoc_value, error)) + return STATUS_ERR; + + return STATUS_OK; +} +#endif + static int evaluate(struct expression *in, struct expression **out_ptr, char **error) { @@ -531,10 +557,8 @@ static int evaluate(struct expression *in, break; #endif #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) - case EXPR_SCTP_ASSOCVAL: /* copy as-is */ - memcpy(&out->value.sctp_assoc_value, - &in->value.sctp_assoc_value, - sizeof(in->value.sctp_assoc_value)); + case EXPR_SCTP_ASSOC_VALUE: /* copy as-is */ + evaluate_sctp_assoc_value_expression(in, out, error); break; #endif #ifdef SCTP_DELAYED_SACK diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h index aff29336..3fc9ca95 100644 --- a/gtests/net/packetdrill/script.h +++ b/gtests/net/packetdrill/script.h @@ -52,7 +52,7 @@ enum expression_t { EXPR_SCTP_INITMSG, /* struct sctp_initmsg for SCTP_INITMSG */ #endif #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) - EXPR_SCTP_ASSOCVAL, /* struct sctp_assoc_value */ + EXPR_SCTP_ASSOC_VALUE, /* struct sctp_assoc_value */ #endif #ifdef SCTP_DELAYED_SACK EXPR_SCTP_SACKINFO, /* struct sctp_sack_info for @@ -87,7 +87,7 @@ struct expression { struct sctp_initmsg sctp_initmsg; #endif #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) - struct sctp_assoc_value sctp_assoc_value; + struct sctp_assoc_value_expr *sctp_assoc_value; #endif #ifdef SCTP_DELAYED_SACK struct sctp_sack_info sctp_sack_info; @@ -150,6 +150,13 @@ struct sctp_rtoinfo_expr { }; #endif +#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) +/* Parse tree for a sctp_assoc_value struct in a [gs]etsockopt syscall. */ +struct sctp_assoc_value_expr { + struct expression *assoc_value; +}; +#endif + /* 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_get_socket_options.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt index 8374c2c9..c433529a 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 @@ -24,6 +24,6 @@ +0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=..., srto_max=200, srto_min=50}, [16]) = 0 +0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=..., srto_min=50}, [16]) = 0 +0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=...}, [16]) = 0 - ++0 getsockopt(3, IPPROTO_SCTP, SCTP_MAXSEG, {assoc_value=1452}, [8]) = 0 +0 close(3) = 0 -- GitLab