diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index a8aa42363c5ab2ca6a32c6a55ecf3b73a1d177e7..8f353410b201060a80ebbcd1c7cfa2262974a2f4 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -564,9 +564,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 linger -%type <expression> sctp_rtoinfo sctp_initmsg sctp_assocval sctp_sackinfo -%type <expression> sctp_status +%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_rtoinfo srto_initial srto_max srto_min %type <errno_info> opt_errno %type <chunk_list> sctp_chunk_list_spec %type <chunk_list_item> sctp_chunk_spec @@ -2280,30 +2281,74 @@ opt_revents | ',' REVENTS '=' expression { $$ = $4; } ; +l_onoff +: ONOFF '=' INTEGER { + if (!is_valid_s32($3)) { + semantic_error("linger onoff out of range"); + } else { + $$ = new_integer_expression($3, "%ld"); + } +} +| ONOFF '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +l_linger +: LINGER '=' INTEGER { + if (!is_valid_s32($3)) { + semantic_error("linger out of range"); + } + $$ = new_integer_expression($3, "%ld"); +} +| LINGER '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + linger -: '{' ONOFF '=' INTEGER ',' LINGER '=' INTEGER '}' { +: '{' l_onoff ',' l_linger '}' { $$ = new_expression(EXPR_LINGER); - $$->value.linger.l_onoff = $4; - $$->value.linger.l_linger = $8; + $$->value.linger = (struct linger_expr*) calloc(1, sizeof(struct linger_expr)); + $$->value.linger->l_onoff = $2; + $$->value.linger->l_linger = $4; } ; -sctp_rtoinfo -: '{' SRTO_INITIAL '=' INTEGER ',' SRTO_MAX '=' INTEGER ',' SRTO_MIN '=' INTEGER '}' { -#ifdef SCTP_RTOINFO - $$ = new_expression(EXPR_SCTP_RTOINFO); - if (!is_valid_u32($4)) { +srto_initial +: SRTO_INITIAL '=' INTEGER { + if (!is_valid_u32($3)){ semantic_error("srto_initial out of range"); } - $$->value.sctp_rtoinfo.srto_initial = $4; - if (!is_valid_u32($8)) { + $$ = new_integer_expression($3, "%u"); +} +| SRTO_INITIAL '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +srto_max +: SRTO_MAX '=' INTEGER { + if (!is_valid_u32($3)) { semantic_error("srto_max out of range"); } - $$->value.sctp_rtoinfo.srto_max = $8; - if (!is_valid_u32($12)) { + $$ = new_integer_expression($3, "%u"); +} +| SRTO_MAX '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +srto_min +: SRTO_MIN '=' INTEGER { + if (!is_valid_u32($3)) { semantic_error("srto_min out of range"); } - $$->value.sctp_rtoinfo.srto_min = $12; + $$ = new_integer_expression($3, "%u"); +} +| SRTO_MIN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sctp_rtoinfo +: '{' srto_initial ',' srto_max ',' srto_min '}' { +#ifdef SCTP_RTOINFO + $$ = new_expression(EXPR_SCTP_RTOINFO); + $$->value.sctp_rtoinfo = (struct sctp_rtoinfo_expr*) calloc(1, sizeof(struct sctp_rtoinfo_expr)); + $$->value.sctp_rtoinfo->srto_initial = $2; + $$->value.sctp_rtoinfo->srto_max = $4; + $$->value.sctp_rtoinfo->srto_min = $6; #else $$ = NULL; #endif diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index aef5ef0e5f85824c00e4eb30c433190985d3b45c..339459ec2f72cf8f373d509b764e68245d8f132a 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -1560,8 +1560,10 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, struct expression_list *args, char **error) { int script_fd, live_fd, level, optname, result; - s32 script_optval, live_optval, script_optlen; - socklen_t live_optlen = sizeof(live_optval); + s32 script_optval, script_optlen, expected; + 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)) @@ -1572,37 +1574,170 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, return STATUS_ERR; if (s32_arg(args, 2, &optname, error)) return STATUS_ERR; - if (s32_bracketed_arg(args, 3, &script_optval, error)) - return STATUS_ERR; if (s32_bracketed_arg(args, 4, &script_optlen, error)) return STATUS_ERR; - if (script_optlen != 4) { - asprintf(error, "Unsupported getsockopt optlen: %d", - (int)script_optlen); + if (get_s32(syscall->result, &expected, error)) return STATUS_ERR; + val_expression = get_arg(args, 3, error); + if (val_expression == NULL) { + return STATUS_ERR; + } else if (val_expression->type == EXPR_LINGER) { + live_optval = malloc(sizeof(struct linger)); + live_optlen = (socklen_t)sizeof(struct linger); +#ifdef SCTP_RTOINFO + } else if (val_expression->type == EXPR_SCTP_RTOINFO) { + live_optval = malloc(sizeof(struct sctp_rtoinfo)); + live_optlen = (socklen_t)sizeof(struct sctp_rtoinfo); + ((struct sctp_rtoinfo*)live_optval)->srto_assoc_id = 0; +#endif +#ifdef SCTP_STATUS + } else if (val_expression->type == EXPR_SCTP_STATUS) { + 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 + } else { + s32_bracketed_arg(args, 3, &script_optval, error); + live_optval = malloc(sizeof(int)); + live_optlen = (socklen_t)sizeof(int); } begin_syscall(state, syscall); - result = getsockopt(live_fd, level, optname, - &live_optval, &live_optlen); - - if (end_syscall(state, syscall, CHECK_EXACT, result, error)) - return STATUS_ERR; - - if ((int)live_optlen != script_optlen) { - asprintf(error, - "Bad getsockopt optlen: expected: %d actual: %d", - (int)script_optlen, (int)live_optlen); + result = getsockopt(live_fd, level, optname, live_optval, &live_optlen); + if (end_syscall(state, syscall, CHECK_NON_NEGATIVE, result, error)) { return STATUS_ERR; } - if (live_optval != script_optval) { - asprintf(error, - "Bad getsockopt optval: expected: %d actual: %d", - (int)script_optval, (int)live_optval); + + if (live_optlen != script_optlen) { + asprintf(error, "Bad getsockopt optlen: expected: %d actual: %d", + (int)script_optlen, (int)live_optlen); + free(live_optval); return STATUS_ERR; } + if (val_expression->type == EXPR_LINGER) { + 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; + if (l_onoff->type == EXPR_INTEGER) { + if (get_s32(l_onoff, &val_onoff, error)) { + free(live_optval); + return STATUS_ERR; + } + if (val_onoff != ling->l_onoff) { + asprintf(error, "Bad getsockopt Linger onoff: expected: %d actual: %d", + (int) val_onoff, ling->l_onoff); + free(live_optval); + return STATUS_ERR; + } + } + int val_linger = 0; + if (l_linger->type == EXPR_INTEGER) { + if (get_s32(l_linger, &val_linger, error)) { + free(live_optval); + return STATUS_ERR; + } + if (ling->l_linger != val_linger) { + asprintf(error, "Bad getsockopt Linger Value: expected: %d actual: %d", + val_linger, ling->l_linger); + free(live_optval); + return STATUS_ERR; + } + } +#ifdef SCTP_RTOINFO + } else if (val_expression->type == EXPR_SCTP_RTOINFO) { + struct expression *srto_initial = val_expression->value.sctp_rtoinfo->srto_initial; + struct expression *srto_max = val_expression->value.sctp_rtoinfo->srto_max; + struct expression *srto_min = val_expression->value.sctp_rtoinfo->srto_min; + struct sctp_rtoinfo *rtoinfo = live_optval; + int initial=0, max=0, min=0; + if (srto_initial->type == EXPR_INTEGER) { + if (get_s32(srto_initial, &initial, error)) { + free(live_optval); + return STATUS_ERR; + } + if (rtoinfo->srto_initial != initial) { + asprintf(error, "Bad getsockopt SCTP_RTOINFO initial: expected: %u actual: %u", + initial, rtoinfo->srto_initial); + free(live_optval); + return STATUS_ERR; + } + } else if (srto_max->type == EXPR_INTEGER) { + if (get_s32(srto_max, &max, error)) { + free(live_optval); + return STATUS_ERR; + } + if (rtoinfo->srto_max != max) { + asprintf(error, "Bad getsockopt SCTP_RTOINFO SRTO_MAX: expected: %u actual: %u", + max, rtoinfo->srto_max); + free(live_optval); + return STATUS_ERR; + } + } else if (srto_min->type == EXPR_INTEGER) { + if (get_s32(srto_min, &min, error)) { + free(live_optval); + return STATUS_ERR; + } + if (rtoinfo->srto_min != min) { + asprintf(error, "Bad getsockopt SCTP_RTOINFO SRTO_MIN: expected: %u actual: %u", + min, rtoinfo->srto_min); + free(live_optval); + return STATUS_ERR; + } + } +#endif +#ifdef SCTP_STATUS + } else if (val_expression->type == EXPR_SCTP_STATUS) { + struct sctp_status *live_val = live_optval; + struct sctp_status *expected_val = &(val_expression->value.sctp_status); + if (live_val->sstat_state != expected_val->sstat_state) { + asprintf(error, "Bad getsockopt SCTP_STATUS state: expected: %d actual: %d ", + expected_val->sstat_state, live_val->sstat_state); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_rwnd != expected_val->sstat_rwnd) { + asprintf(error, "Bad getsockopt SCTP_STATUS rwnd: expected: %u actual: %u ", + expected_val->sstat_rwnd, live_val->sstat_rwnd); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_unackdata != expected_val->sstat_unackdata) { + asprintf(error, "Bad getsockopt SCTP_STATUS unackdata: expected: %u actual: %u", + expected_val->sstat_unackdata, live_val->sstat_unackdata); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_penddata != expected_val->sstat_penddata) { + asprintf(error, "Bad getsockopt SCTP_STATUS penddata: expected: %u actual: %u", + expected_val->sstat_penddata, live_val->sstat_penddata); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_instrms != expected_val->sstat_instrms) { + asprintf(error, "Bad getsockopt SCTP_STATUS instreams: expected: %u actual: %u", + expected_val->sstat_instrms, live_val->sstat_instrms); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_outstrms != expected_val->sstat_outstrms) { + asprintf(error, "Bad getsockopt SCTP_STATUS outstreams: expected: %u actual: %u", + expected_val->sstat_outstrms, live_val->sstat_outstrms); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_fragmentation_point != expected_val->sstat_fragmentation_point){ + asprintf(error, "Bad getsockopt SCTP_STATUS fragmentation point: expected: %u actual: %u", + expected_val->sstat_fragmentation_point, live_val->sstat_fragmentation_point); + free(live_optval); + return STATUS_ERR; + } +#endif + } else { + if (*(int*)live_optval != script_optval) { + asprintf(error, "Bad getsockopt optval: expected: %d actual: %d", + (int)script_optval, *(int*)live_optval); + free(live_optval); + return STATUS_ERR; + } + } + free(live_optval); return STATUS_OK; } @@ -1630,7 +1765,11 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, if (val_expression == NULL) return STATUS_ERR; if (val_expression->type == EXPR_LINGER) { - optval = &val_expression->value.linger; + optval = malloc(sizeof(struct linger)); + 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); } else if (val_expression->type == EXPR_STRING) { optval = val_expression->value.string; } else if (val_expression->type == EXPR_LIST) { @@ -1639,7 +1778,20 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, optval = &optval_s32; #ifdef SCTP_RTOINFO } else if (val_expression->type == EXPR_SCTP_RTOINFO) { - optval = &val_expression->value.sctp_rtoinfo; + struct sctp_rtoinfo *rtoinfo; + 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) { + asprintf(error, "Bad setsockopt, bad inputtype for rtoinfo"); + return STATUS_ERR; + } + rtoinfo = malloc(sizeof(struct sctp_rtoinfo)); + rtoinfo->srto_initial = expr_rtoinfo->srto_initial->value.num; + rtoinfo->srto_max = expr_rtoinfo->srto_max->value.num; + rtoinfo->srto_min = expr_rtoinfo->srto_min->value.num; + rtoinfo->srto_assoc_id = 0; + optval = rtoinfo; #endif #ifdef SCTP_INITMSG } else if (val_expression->type == EXPR_SCTP_INITMSG) { @@ -1669,6 +1821,7 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, result = setsockopt(live_fd, level, optname, optval, optlen); return end_syscall(state, syscall, CHECK_EXACT, result, error); + free(optval); } static int syscall_poll(struct state *state, struct syscall_spec *syscall, diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c index c4fdb4b2aedff29ebc5592f6bb95651b6cdd9b35..7b7d656577e63322f865f600d38a354e1280bd73 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -285,9 +285,17 @@ void free_expression(struct expression *expression) switch (expression->type) { case EXPR_ELLIPSIS: case EXPR_INTEGER: + break; case EXPR_LINGER: + free(expression->value.linger->l_onoff); + free(expression->value.linger->l_linger); + break; #ifdef SCTP_RTOINFO case EXPR_SCTP_RTOINFO: + free(expression->value.sctp_rtoinfo->srto_initial); + free(expression->value.sctp_rtoinfo->srto_max); + free(expression->value.sctp_rtoinfo->srto_min); + break; #endif #ifdef SCTP_INITMSG case EXPR_SCTP_INITMSG: diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h index a2b2e46b118718d717504bb56fc35586d0c9e21b..cba02337b50e441dd038f2b8a4e5f6fcc50a81cc 100644 --- a/gtests/net/packetdrill/script.h +++ b/gtests/net/packetdrill/script.h @@ -72,7 +72,7 @@ struct expression { union { s64 num; char *string; - struct linger linger; + struct linger_expr *linger; struct sockaddr_in *socket_address_ipv4; struct sockaddr_in6 *socket_address_ipv6; struct binary_expression *binary; @@ -81,7 +81,7 @@ struct expression { struct msghdr_expr *msghdr; struct pollfd_expr *pollfd; #ifdef SCTP_RTOINFO - struct sctp_rtoinfo sctp_rtoinfo; + struct sctp_rtoinfo_expr *sctp_rtoinfo; #endif #ifdef SCTP_INITMSG struct sctp_initmsg sctp_initmsg; @@ -136,6 +136,20 @@ struct pollfd_expr { struct expression *revents; /* returned events */ }; +/* Handle values for socketoption SO_Linger with inputtypes and values*/ +struct linger_expr { + struct expression *l_onoff; + struct expression *l_linger; +}; +/* Parse tree for syscall get/setsockopt for sctp_rtoinfo*/ +#ifdef SCTP_RTOINFO +struct sctp_rtoinfo_expr { + struct expression *srto_initial; + struct expression *srto_max; + struct expression *srto_min; +}; +#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/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c index 40b44dba9bac9d862e7995a027806920068c6d2e..ac26f2082a8d57ecdf84a538dfe0c32c52c8b2f1 100644 --- a/gtests/net/packetdrill/sctp_packet.c +++ b/gtests/net/packetdrill/sctp_packet.c @@ -421,10 +421,10 @@ sctp_data_chunk_new(s64 flgs, s64 len, s64 tsn, s64 sid, s64 ssn, s64 ppid) chunk->ssn = htons((u16)ssn); } if (ppid == -1) { - chunk->ppid = htons(0); + chunk->ppid = htonl(0); flags |= FLAG_DATA_CHUNK_PPID_NOCHECK; } else { - chunk->ppid = htons((u32)ppid); + chunk->ppid = htonl((u32)ppid); } memset(chunk->data, 0, length + padding_length - sizeof(struct sctp_data_chunk)); 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 new file mode 100644 index 0000000000000000000000000000000000000000..8374c2c9fb78140ccaaeeeefef61792e53cb6ef0 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt @@ -0,0 +1,29 @@ +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 > 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 getsockopt(3, IPPROTO_SCTP, SCTP_STATUS, {sstat_state=8, sstat_rwnd=1500, sstat_unackdata=0, sstat_penddata=0, sstat_instrms=1, sstat_outstrms=1, + sstat_fragmentation_point=1452, sstat_primary=...}, [176])= 0 + ++0 setsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=1, linger=30}, 8) = 0 ++0 getsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=128, linger=30}, [8]) = 0 ++0 getsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=128, linger=...}, [8]) = 0 ++0 getsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=..., linger=30}, [8]) = 0 ++0 getsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=..., linger=...}, [8]) = 0 + ++0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=50}, 16) = 0 ++0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=50}, [16]) = 0 ++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 close(3) = 0 +