Skip to content
Snippets Groups Projects
Commit 2c752a9f authored by Michael Tüxen's avatar Michael Tüxen
Browse files

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.
parent 37dc3072
No related branches found
No related tags found
No related merge requests found
......@@ -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
......
......@@ -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) {
......
......@@ -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
......
......@@ -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) */
......
......@@ -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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment