diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index 5179907b893c25b9cac2f4b4614a5e57207cd101..5cebb2f7756b4b2a022ceaa3201d2958e1ef38b6 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -247,6 +247,14 @@ snd_flags return SND_FLAGS; snd_ppid return SND_PPID; snd_context return SND_CONTEXT; ssb_adaptation_ind return SSB_ADAPTATION_IND; +sinfo_stream return SINFO_STREAM; +sinfo_ssn return SINFO_SSN; +sinfo_flags return SINFO_FLAGS; +sinfo_ppid return SINFO_PPID; +sinfo_context return SINFO_CONTEXT; +sinfo_timetolive return SINFO_TIMETOLIVE; +sinfo_tsn return SINFO_TSN; +sinfo_cumtsn return SINFO_CUMTSN; CHUNK return CHUNK; DATA return DATA; INIT return INIT; @@ -319,6 +327,7 @@ staleness return STALENESS; param return PARAM; chk return CHK; bad_crc32c return BAD_CRC32C; +NULL return NULL_; --[a-zA-Z0-9_]+ yylval.string = option(yytext); return OPTION; [-]?[0-9]*[.][0-9]+ yylval.floating = atof(yytext); return FLOAT; [-]?[0-9]+ yylval.integer = atoll(yytext); return INTEGER; diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index bb2fb56b5a72dc63bcf7b54f14b2fa6e5b0f2e2b..6239ff2647b6a6627fbe4a3a4bcc3b6394a84fa5 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -538,7 +538,9 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> SASOC_ASOCMAXRXT SASOC_NUMBER_PEER_DESTINATIONS SASOC_PEER_RWND %token <reserved> SASOC_LOCAL_RWND SASOC_COOKIE_LIFE SE_TYPE SE_ON %token <reserved> SND_SID SND_FLAGS SND_PPID SND_CONTEXT SSB_ADAPTATION_IND -%token <reserved> BAD_CRC32C +%token <reserved> BAD_CRC32C NULL_ +%token <reserved> SINFO_STREAM SINFO_SSN SINFO_FLAGS SINFO_PPID SINFO_CONTEXT +%token <reserved> SINFO_TIMETOLIVE SINFO_TSN SINFO_CUMTSN %token <floating> FLOAT %token <integer> INTEGER HEX_INTEGER %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR @@ -588,7 +590,9 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <expression> sasoc_asocmaxrxt sasoc_number_peer_destinations sasoc_peer_rwnd %type <expression> sasoc_local_rwnd sasoc_cookie_life sctp_assocparams %type <expression> sctp_sndinfo snd_sid snd_flags snd_ppid snd_context -%type <expression> sctp_event se_type se_on sctp_setadaptation +%type <expression> sctp_event se_type se_on sctp_setadaptation null +%type <expression> sctp_sndrcvinfo sinfo_stream sinfo_ssn sinfo_flags sinfo_ppid sinfo_context +%type <expression> sinfo_timetolive sinfo_tsn sinfo_cumtsn %type <errno_info> opt_errno %type <chunk_list> sctp_chunk_list_spec %type <chunk_list_item> sctp_chunk_spec @@ -2398,6 +2402,12 @@ expression | sctp_setadaptation{ $$ = $1; } +| null { + $$ = $1; +} +| sctp_sndrcvinfo { + $$ = $1; +} ; decimal_integer @@ -3059,17 +3069,14 @@ snd_context sctp_sndinfo : '{' snd_sid ',' snd_flags ',' snd_ppid ',' snd_context '}' { -#ifdef SCTP_DEFAULT_SNDINFO $$ = new_expression(EXPR_SCTP_SNDINFO); - $$->value.sctp_sndinfo = calloc(1, sizeof(struct sctp_sndinfo)); + $$->value.sctp_sndinfo = calloc(1, sizeof(struct sctp_sndinfo_expr)); $$->value.sctp_sndinfo->snd_sid = $2; $$->value.sctp_sndinfo->snd_flags = $4; $$->value.sctp_sndinfo->snd_ppid = $6; $$->value.sctp_sndinfo->snd_context = $8; -#else - $$ = NULL; -#endif } +; sctp_setadaptation : '{' SSB_ADAPTATION_IND '=' INTEGER '}' { @@ -3082,6 +3089,99 @@ sctp_setadaptation } ; +sinfo_stream +: SINFO_STREAM '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("sinfo_stream out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SINFO_STREAM '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sinfo_ssn +: SINFO_SSN '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("sinfo_ssn out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SINFO_SSN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sinfo_flags +: SINFO_FLAGS '=' INTEGER { + if (!is_valid_u16($3)) { + semantic_error("sinfo_flags out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SINFO_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sinfo_ppid +: SINFO_PPID '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("sinfo_ppid out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SINFO_PPID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sinfo_context +: SINFO_CONTEXT '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("sinfo_context out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SINFO_CONTEXT '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sinfo_timetolive +: SINFO_TIMETOLIVE '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("snd_timetolive out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SINFO_TIMETOLIVE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sinfo_tsn +: SINFO_TSN '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("sinfo_tsn out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SINFO_TSN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sinfo_cumtsn +: SINFO_CUMTSN '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("sinfo_cumtsn out of range"); + } + $$ = new_integer_expression($3, "%u"); +} +| SINFO_CUMTSN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sctp_sndrcvinfo +: '{' sinfo_stream ',' sinfo_ssn ',' sinfo_flags ',' sinfo_ppid ',' sinfo_context ',' sinfo_timetolive ',' sinfo_tsn ',' sinfo_cumtsn '}' { + $$ = new_expression(EXPR_SCTP_SNDRCVINFO); + $$->value.sctp_sndrcvinfo = calloc(1, sizeof(struct sctp_sndrcvinfo)); + $$->value.sctp_sndrcvinfo->sinfo_stream = $2; + $$->value.sctp_sndrcvinfo->sinfo_ssn = $4; + $$->value.sctp_sndrcvinfo->sinfo_flags = $6; + $$->value.sctp_sndrcvinfo->sinfo_ppid = $8; + $$->value.sctp_sndrcvinfo->sinfo_context = $10; + $$->value.sctp_sndrcvinfo->sinfo_timetolive = $12; + $$->value.sctp_sndrcvinfo->sinfo_tsn = $14; + $$->value.sctp_sndrcvinfo->sinfo_cumtsn = $16; +}; opt_errno : { $$ = NULL; } | WORD note { @@ -3121,3 +3221,8 @@ code_spec } ; +null +: NULL_ { + $$ = new_expression(EXPR_NULL); +} +; diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index 626d692684adc5d3ed925cc2d5c440793ca1a82c..cf947c92d4d96da00c157ed536a9dd9558937c07 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -2971,6 +2971,329 @@ error_out: return status; } +static int syscall_sctp_sendmsg(struct state *state, struct syscall_spec *syscall, + struct expression_list *args, char **error) +{ +#if defined(__FreeBSD__) || defined(__Linux__) || defined(__NetBSD__) || defined(__OpenBSD__) + int result, script_fd, live_fd, len; + void *msg = NULL; + struct sockaddr_storage to; + struct sockaddr_storage *to_ptr = &to; + socklen_t tolen = 0; + u32 ppid, flags, timetolive, context; + u16 stream_no; + struct expression *sockaddr_expr, *tolen_expr, *ppid_expr, *flags_expr, *ttl_expr, *stream_no_expr, *context_expr; + + if (check_arg_count(args, 10, error)) + return STATUS_ERR; + if (s32_arg(args, 0, &script_fd, error)) + return STATUS_ERR; + if (to_live_fd(state, script_fd, &live_fd, error)) + return STATUS_ERR; + if (ellipsis_arg(args, 1, error)) + return STATUS_ERR; + if (s32_arg(args, 2, &len, error)) + return STATUS_ERR; + sockaddr_expr = get_arg(args, 3, error); + if (sockaddr_expr->type == EXPR_ELLIPSIS) { + socklen_t len = (socklen_t)sizeof(struct sockaddr_storage); + if (getpeername(live_fd, (struct sockaddr *)to_ptr, &len)) { + return STATUS_ERR; + } + tolen = len; + } else if (sockaddr_expr->type == EXPR_NULL) { + to_ptr = NULL; + tolen = 0; + } else { + if (sockaddr_expr->type == EXPR_SOCKET_ADDRESS_IPV4) { + memcpy(to_ptr, sockaddr_expr->value.socket_address_ipv4, sizeof(struct sockaddr_in)); + tolen = sizeof(struct sockaddr_in); + } else if (sockaddr_expr->type == EXPR_SOCKET_ADDRESS_IPV6) { + memcpy(to_ptr, sockaddr_expr->value.socket_address_ipv6, sizeof(struct sockaddr_in6)); + tolen = sizeof(struct sockaddr_in6); + } else { + asprintf(error, "Bad input for reciever in sctp_sentmsg"); + return STATUS_ERR; + } + } + tolen_expr = get_arg(args, 4, error); + if (tolen_expr->type != EXPR_ELLIPSIS) + if (get_u32(tolen_expr, &tolen, error)) + return STATUS_ERR; + ppid_expr = get_arg(args, 5, error); + if (get_u32(ppid_expr, &ppid, error)) + return STATUS_ERR; + flags_expr = get_arg(args, 6, error); + if (get_u32(flags_expr, &flags, error)) + return STATUS_ERR; + stream_no_expr =get_arg(args, 7, error); + if (get_u16(stream_no_expr, &stream_no, error)) + return STATUS_ERR; + ttl_expr = get_arg(args, 8, error); + if (get_u32(ttl_expr, &timetolive, error)) + return STATUS_ERR; + context_expr = get_arg(args, 9, error); + if (get_u32(context_expr, &context, error)) + return STATUS_ERR; + + msg = calloc(len, 1); + assert(msg != NULL); + + begin_syscall(state, syscall); + result = sctp_sendmsg(live_fd, msg, (size_t)len, (struct sockaddr*) to_ptr, + tolen, ppid, flags, stream_no, timetolive, context); + + if (end_syscall(state, syscall, CHECK_EXACT, result, error)) { + free(msg); + return STATUS_ERR; + } + free(msg); + return STATUS_OK; +#else + asprintf(error, "sctp_sendmsg is not supported"); + return STATUS_ERR; +#endif +} + +#if defined(__FreeBSD__) || defined(__Linux__) || defined(__NetBSD__) || defined(__OpenBSD__) +static int check_sctp_sndrcvinfo(struct sctp_sndrcvinfo_expr *expr, + struct sctp_sndrcvinfo *sctp_sndrcvinfo, + char** error) { + if (expr->sinfo_stream->type != EXPR_ELLIPSIS) { + u16 sinfo_stream; + + if (get_u16(expr->sinfo_stream, &sinfo_stream, error)) { + return STATUS_ERR; + } + if (sctp_sndrcvinfo->sinfo_stream != sinfo_stream) { + asprintf(error, "sctp_sndrcvinfo.sinfo_stream: expected: %hu actual: %hu", + sinfo_stream, sctp_sndrcvinfo->sinfo_stream); + return STATUS_ERR; + } + } + if (expr->sinfo_ssn->type != EXPR_ELLIPSIS) { + u16 sinfo_ssn; + + if (get_u16(expr->sinfo_ssn, &sinfo_ssn, error)) { + return STATUS_ERR; + } + if (sctp_sndrcvinfo->sinfo_ssn != sinfo_ssn) { + asprintf(error, "sctp_sndrcvinfo.sinfo_ssn: expected: %hu actual: %hu", + sinfo_ssn, sctp_sndrcvinfo->sinfo_ssn); + return STATUS_ERR; + } + } + if (expr->sinfo_flags->type != EXPR_ELLIPSIS) { + u16 sinfo_flags; + + if (get_u16(expr->sinfo_flags, &sinfo_flags, error)) { + return STATUS_ERR; + } + if (sctp_sndrcvinfo->sinfo_flags != sinfo_flags) { + asprintf(error, "sctp_sndrcvinfo.sinfo_flags: expected: %hu actual: %hu", + sinfo_flags, sctp_sndrcvinfo->sinfo_flags); + return STATUS_ERR; + } + } + if (expr->sinfo_ppid->type != EXPR_ELLIPSIS) { + u32 sinfo_ppid; + + if (get_u32(expr->sinfo_ppid, &sinfo_ppid, error)) { + return STATUS_ERR; + } + if (sctp_sndrcvinfo->sinfo_ppid != sinfo_ppid) { + asprintf(error, "sctp_sndrcvinfo.sinfo_ppid: expected: %u actual: %u", + sinfo_ppid, sctp_sndrcvinfo->sinfo_ppid); + return STATUS_ERR; + } + } + if (expr->sinfo_context->type != EXPR_ELLIPSIS) { + u32 sinfo_context; + + if (get_u32(expr->sinfo_context, &sinfo_context, error)) { + return STATUS_ERR; + } + if (sctp_sndrcvinfo->sinfo_context != sinfo_context) { + asprintf(error, "sctp_sndrcvinfo.sinfo_context: expected: %u actual: %u", + sinfo_context, sctp_sndrcvinfo->sinfo_context); + return STATUS_ERR; + } + } + if (expr->sinfo_timetolive->type != EXPR_ELLIPSIS) { + u32 sinfo_timetolive; + + if (get_u32(expr->sinfo_timetolive, &sinfo_timetolive, error)) { + return STATUS_ERR; + } + if (sctp_sndrcvinfo->sinfo_timetolive != sinfo_timetolive) { + asprintf(error, "sctp_sndrcvinfo.sinfo_timetolive: expected: %u actual: %u", + sinfo_timetolive, sctp_sndrcvinfo->sinfo_timetolive); + return STATUS_ERR; + } + } + if (expr->sinfo_tsn->type != EXPR_ELLIPSIS) { + u32 sinfo_tsn; + + if (get_u32(expr->sinfo_tsn, &sinfo_tsn, error)) { + return STATUS_ERR; + } + if (sctp_sndrcvinfo->sinfo_tsn != sinfo_tsn) { + asprintf(error, "sctp_sndrcvinfo.sinfo_tsn: expected: %u actual: %u", + sinfo_tsn, sctp_sndrcvinfo->sinfo_tsn); + return STATUS_ERR; + } + } + if (expr->sinfo_cumtsn->type != EXPR_ELLIPSIS) { + u32 sinfo_cumtsn; + + if (get_u32(expr->sinfo_cumtsn, &sinfo_cumtsn, error)) { + return STATUS_ERR; + } + if (sctp_sndrcvinfo->sinfo_cumtsn != sinfo_cumtsn) { + asprintf(error, "sctp_sndrcvinfo.sinfo_cumtsn: expected: %u actual: %u", + sinfo_cumtsn, sctp_sndrcvinfo->sinfo_cumtsn); + return STATUS_ERR; + } + } + return STATUS_OK; +} +#endif + +static int syscall_sctp_recvmsg(struct state *state, struct syscall_spec *syscall, + struct expression_list *args, + char **error) +{ +#if defined(__FreeBSD__) || defined(__Linux__) || defined(__NetBSD__) || defined(__OpenBSD__) + int script_fd, live_fd, live_msg_flags, result; + void *msg; + u32 len; + struct sockaddr live_from; + socklen_t live_fromlen; + struct sctp_sndrcvinfo live_sinfo; + struct expression *len_expr, *script_sinfo_expr, *script_msg_flags_expr; + struct expression *script_fromlen_expr, *script_from_expr; + + if (check_arg_count(args, 7, error)) + return STATUS_ERR; + if (s32_arg(args, 0, &script_fd, error)) + return STATUS_ERR; + if (to_live_fd(state, script_fd, &live_fd, error)) + return STATUS_ERR; + if (ellipsis_arg(args, 1, error)) + return STATUS_ERR; + len_expr = get_arg(args, 2, error); + if (get_u32(len_expr, &len, error)) + return STATUS_ERR; + + msg = calloc(len, 1); + assert(msg != NULL); + + begin_syscall(state, syscall); + result = sctp_recvmsg(live_fd, msg, len, (struct sockaddr*) &live_from, + &live_fromlen, &live_sinfo, &live_msg_flags); + free(msg); + + if (end_syscall(state, syscall, CHECK_EXACT, result, error)) { + return STATUS_ERR; + } + + script_from_expr = get_arg(args, 3, error); + if (script_from_expr->type != EXPR_ELLIPSIS) { + struct sockaddr *script_addr; + if (script_from_expr->type == EXPR_SOCKET_ADDRESS_IPV4) { + script_addr = (struct sockaddr*)script_from_expr->value.socket_address_ipv4; + } else if( script_from_expr->type == EXPR_SOCKET_ADDRESS_IPV6) { + script_addr = (struct sockaddr*)script_from_expr->value.socket_address_ipv6; + } else { + asprintf(error, "sctp_recvmsg fromlen: can't check sctp_recvmsg from"); + return STATUS_ERR; + } + if (script_addr->sa_family != live_from.sa_family) { + asprintf(error, "sctp_recvmsg from.sa_family: expected: %d actual: %d", + script_addr->sa_family, live_from.sa_family); + return STATUS_ERR; + } + switch(script_addr->sa_family) { + case AF_INET: + { + struct sockaddr_in *script_sockaddr = (struct sockaddr_in*)script_addr; + struct sockaddr_in *live_sockaddr = (struct sockaddr_in*)&live_from; + if (live_sockaddr->sin_port != script_sockaddr->sin_port) { + asprintf(error, "sctp_recvmsg from.sinport. expected: %d actual %d", + ntohs(script_sockaddr->sin_port), ntohs(live_sockaddr->sin_port)); + return STATUS_ERR; + } + if (live_sockaddr->sin_addr.s_addr != script_sockaddr->sin_addr.s_addr) { + int len = strnlen(inet_ntoa(script_sockaddr->sin_addr), 16); + char *expected_addr = malloc(sizeof(char) * len); + memcpy(expected_addr, inet_ntoa(script_sockaddr->sin_addr), len); + asprintf(error, "sctp_recvmsg from.sin_addr. expected: %s actual %s", + expected_addr, inet_ntoa(live_sockaddr->sin_addr)); + free(expected_addr); + return STATUS_ERR; + } + } + break; + case AF_INET6: + { + struct sockaddr_in6 *script_sockaddr = (struct sockaddr_in6*)script_addr; + struct sockaddr_in6 *live_sockaddr = (struct sockaddr_in6*)&live_from; + if (live_sockaddr->sin6_port != script_sockaddr->sin6_port) { + asprintf(error, "sctp_recvmsg from.sinport. expected: %d actual %d", + ntohs(script_sockaddr->sin6_port), ntohs(live_sockaddr->sin6_port)); + return STATUS_ERR; + } + if (live_sockaddr->sin6_addr.s6_addr != script_sockaddr->sin6_addr.s6_addr) { + char expected_addr[INET6_ADDRSTRLEN]; + char live_addr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &script_sockaddr->sin6_addr, expected_addr, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &live_sockaddr->sin6_addr, live_addr, INET6_ADDRSTRLEN); + asprintf(error, "sctp_recvmsg from.sin6_addr. expected: %s actual %s", + expected_addr, live_addr); + return STATUS_ERR; + } + } + break; + } + + } + + script_fromlen_expr = get_arg(args, 4, error); + if (script_fromlen_expr->type != EXPR_ELLIPSIS) { + int script_fromlen; + if (get_s32(script_fromlen_expr, &script_fromlen, error)) + return STATUS_ERR; + if (script_fromlen != live_fromlen) { + asprintf(error, "sctp_recvmsg fromlen: expected: %d actual: %d", + script_fromlen, live_fromlen); + return STATUS_ERR; + } + } + + script_sinfo_expr = get_arg(args, 5, error); + if (script_sinfo_expr->type != EXPR_ELLIPSIS) { + if (check_sctp_sndrcvinfo(script_sinfo_expr->value.sctp_sndrcvinfo, &live_sinfo, error)) { + return STATUS_ERR; + } + } + script_msg_flags_expr = get_arg(args, 6, error); + if (script_msg_flags_expr->type != EXPR_ELLIPSIS) { + int script_msg_flags; + if (get_s32(script_msg_flags_expr, &script_msg_flags, error)) + return STATUS_ERR; + if (script_msg_flags != live_msg_flags) { + asprintf(error, "sctp_recvmsg msg_flags: expected: %d actual: %d", + script_msg_flags, live_msg_flags); + return STATUS_ERR; + } + } + return STATUS_OK; +#else + asprintf(error, "sctp_sendmsg is not supported"); + return STATUS_ERR; +#endif +} + /* A dispatch table with all the system calls that we support... */ struct system_call_entry { const char *name; @@ -3002,6 +3325,8 @@ struct system_call_entry system_call_table[] = { {"getsockopt", syscall_getsockopt}, {"setsockopt", syscall_setsockopt}, {"poll", syscall_poll}, + {"sctp_sendmsg", syscall_sctp_sendmsg}, + {"sctp_recvmsg", syscall_sctp_recvmsg}, }; /* Evaluate the system call arguments and invoke the system call. */ diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c index 5c07f3ee5053bf66edcf3a688dba82a8c9bb82dd..1b766b8271d94046728e6806b95f304f37dcf008 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -53,6 +53,7 @@ struct expression_type_entry { }; struct expression_type_entry expression_type_table[] = { { EXPR_NONE, "none" }, + { EXPR_NULL, "null" }, { EXPR_ELLIPSIS, "ellipsis" }, { EXPR_INTEGER, "integer" }, { EXPR_WORD, "word" }, @@ -77,6 +78,7 @@ struct expression_type_entry expression_type_table[] = { { EXPR_SCTP_EVENT, "sctp_event" }, { EXPR_SCTP_SNDINFO, "sctp_sndinfo" }, { EXPR_SCTP_SETADAPTATION, "sctp_setadaptation"}, + { EXPR_SCTP_SNDRCVINFO, "sctp_sndrcvinfo" }, { NUM_EXPR_TYPES, NULL} }; @@ -280,6 +282,7 @@ void free_expression(struct expression *expression) (expression->type >= NUM_EXPR_TYPES)) assert(!"bad expression type"); switch (expression->type) { + case EXPR_NULL: case EXPR_ELLIPSIS: case EXPR_INTEGER: break; @@ -365,6 +368,16 @@ void free_expression(struct expression *expression) case EXPR_SCTP_SETADAPTATION: free_expression(expression->value.sctp_setadaptation->ssb_adaptation_ind); break; + case EXPR_SCTP_SNDRCVINFO: + free_expression(expression->value.sctp_sndrcvinfo->sinfo_stream); + free_expression(expression->value.sctp_sndrcvinfo->sinfo_ssn); + free_expression(expression->value.sctp_sndrcvinfo->sinfo_flags); + free_expression(expression->value.sctp_sndrcvinfo->sinfo_ppid); + free_expression(expression->value.sctp_sndrcvinfo->sinfo_context); + free_expression(expression->value.sctp_sndrcvinfo->sinfo_timetolive); + free_expression(expression->value.sctp_sndrcvinfo->sinfo_tsn); + free_expression(expression->value.sctp_sndrcvinfo->sinfo_cumtsn); + break; case EXPR_WORD: assert(expression->value.string); free(expression->value.string); @@ -966,6 +979,58 @@ static int evaluate_sctp_setadaptation_expression(struct expression *in, return STATUS_OK; } +static int evaluate_sctp_sndrcvinfo_expression(struct expression *in, + struct expression *out, + char **error) +{ + struct sctp_sndrcvinfo_expr *in_info; + struct sctp_sndrcvinfo_expr *out_info; + + assert(in->type == EXPR_SCTP_SNDRCVINFO); + assert(in->value.sctp_sndrcvinfo); + assert(out->type == EXPR_SCTP_SNDRCVINFO); + + out->value.sctp_sndrcvinfo = calloc(1, sizeof(struct sctp_sndrcvinfo_expr)); + + in_info = in->value.sctp_sndrcvinfo; + out_info = out->value.sctp_sndrcvinfo; + + if (evaluate(in_info->sinfo_stream, + &out_info->sinfo_stream, + error)) + return STATUS_ERR; + if (evaluate(in_info->sinfo_ssn, + &out_info->sinfo_ssn, + error)) + return STATUS_ERR; + if (evaluate(in_info->sinfo_flags, + &out_info->sinfo_flags, + error)) + return STATUS_ERR; + if (evaluate(in_info->sinfo_ppid, + &out_info->sinfo_ppid, + error)) + return STATUS_ERR; + if (evaluate(in_info->sinfo_context, + &out_info->sinfo_context, + error)) + return STATUS_ERR; + if (evaluate(in_info->sinfo_timetolive, + &out_info->sinfo_timetolive, + error)) + return STATUS_ERR; + if (evaluate(in_info->sinfo_tsn, + &out_info->sinfo_tsn, + error)) + return STATUS_ERR; + if (evaluate(in_info->sinfo_cumtsn, + &out_info->sinfo_cumtsn, + error)) + return STATUS_ERR; + + return STATUS_OK; +} + static int evaluate(struct expression *in, struct expression **out_ptr, char **error) { @@ -980,6 +1045,8 @@ static int evaluate(struct expression *in, return STATUS_ERR; } switch (in->type) { + case EXPR_NULL: + break; case EXPR_ELLIPSIS: break; case EXPR_INTEGER: /* copy as-is */ @@ -1025,6 +1092,9 @@ static int evaluate(struct expression *in, case EXPR_SCTP_SETADAPTATION: result = evaluate_sctp_setadaptation_expression(in, out, error); break; + case EXPR_SCTP_SNDRCVINFO: + result = evaluate_sctp_sndrcvinfo_expression(in, out, error); + break; case EXPR_WORD: out->type = EXPR_INTEGER; if (symbol_to_int(in->value.string, diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h index c614f9d7053d8e3363e8b3bbe254f2f84cc362fd..fbcf7fe705e49abb54e73dde4a944c3ec54e8e52 100644 --- a/gtests/net/packetdrill/script.h +++ b/gtests/net/packetdrill/script.h @@ -33,6 +33,7 @@ /* The types of expressions in a script */ enum expression_t { EXPR_NONE, + EXPR_NULL, /* Expression to handle NULL */ EXPR_ELLIPSIS, /* ... but no value */ EXPR_INTEGER, /* integer in 'num' */ EXPR_LINGER, /* struct linger for SO_LINGER */ @@ -56,7 +57,8 @@ enum expression_t { EXPR_SCTP_ASSOCPARAMS, /* struct sctp_assocparams for SCTP_ASSOCINFO */ EXPR_SCTP_EVENT, /* struct sctp_event for SCTP_EVENT */ EXPR_SCTP_SNDINFO, /* struct sctp_sndinfo for SCTP_DEFAULT_SNDINFO */ - EXPR_SCTP_SETADAPTATION, /* struct sctp_setadaptation for SCTP_ADATTATION_LAYER */ + EXPR_SCTP_SETADAPTATION, /* struct sctp_setadaptation for SCTP_ADATTATION_LAYER */ + EXPR_SCTP_SNDRCVINFO, /* struct sctp_sndrcvinfo for syscall sctp_recvmsg */ NUM_EXPR_TYPES, }; /* Convert an expression type to a human-readable string */ @@ -88,6 +90,7 @@ struct expression { struct sctp_event_expr *sctp_event; struct sctp_sndinfo_expr *sctp_sndinfo; struct sctp_setadaptation_expr *sctp_setadaptation; + struct sctp_sndrcvinfo_expr *sctp_sndrcvinfo; } value; const char *format; /* the printf format for printing the value */ }; @@ -227,6 +230,18 @@ struct sctp_setadaptation_expr { struct expression *ssb_adaptation_ind; }; +/* Parse tree for sctp_sndrcvinfo in sctp_recvmsg syscall. */ +struct sctp_sndrcvinfo_expr { + struct expression *sinfo_stream; + struct expression *sinfo_ssn; + struct expression *sinfo_flags; + struct expression *sinfo_ppid; + struct expression *sinfo_context; + struct expression *sinfo_timetolive; + struct expression *sinfo_tsn; + struct expression *sinfo_cumtsn; +}; + /* 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_recvmsg.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_recvmsg.pkt new file mode 100644 index 0000000000000000000000000000000000000000..c4df402369587dea4affade5c2f9b9af31b14d48 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_recvmsg.pkt @@ -0,0 +1,30 @@ ++0.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 +//sctp_recvmsg(int sd, void * msg, size_t len, struct sockaddr * from, socklen_t * fromlen, struct sctp_sndrcvinfo* sinfo, int * msg_flags); + ++0.0 < sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]] ++0.0 sctp_recvmsg(3, ..., 1000, ..., ..., ..., 8) = 1000 + ++0.0 < sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=..., gaps=[], dups=[]] ++0.0 sctp_recvmsg(3, ..., 1000, ..., ..., {sinfo_stream=0, sinfo_ssn=1, sinfo_flags=0, +sinfo_ppid=0, sinfo_context=0, sinfo_timetolive=0, sinfo_tsn=2, sinfo_cumtsn=2}, 8) = 1000 + ++0.0 < sctp: DATA[flgs=BE, len=1016, tsn=3, sid=0, ssn=2, ppid=0] +* > sctp: SACK[flgs=0, cum_tsn=3, a_rwnd=..., gaps=[], dups=[]] ++0.0 sctp_recvmsg(3, ..., 1000, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")}, 16, +{sinfo_stream=0, sinfo_ssn=2, sinfo_flags=0, sinfo_ppid=0, sinfo_context=0, sinfo_timetolive=0, sinfo_tsn=3, sinfo_cumtsn=3}, 8) = 1000 + ++0.0 close(3) = 0 ++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=3] ++0.1 < sctp: SHUTDOWN_ACK[flgs=0] ++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0] diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_sendmsg.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_sendmsg.pkt new file mode 100644 index 0000000000000000000000000000000000000000..e9d6ec47dddfe82400ecb61c1122c941fe843ec9 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_sendmsg.pkt @@ -0,0 +1,25 @@ ++0.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 +//sctp_sendmsg(int sd, const void * msg, size_t len, struct sockaddr *to, socklen_t tolen, +// uint32_t ppid, uint32_t flags, uint16_t stream_no, uint32_t timetolive, uint32_t context); ++0.0 sctp_sendmsg(3, ..., 1000, ..., ..., 0, 0, 0, 0, 0) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]] ++0.0 sctp_sendmsg(3, ..., 1000, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")}, 16, 0, 0, 0, 0, 0) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=1500, gaps=[], dups=[]] ++0.0 sctp_sendmsg(3, ..., 1000, NULL, 0, 0, 0, 0, 0, 0) = 1000 ++0.0 > sctp: DATA[flgs=BE, len=1016, tsn=3, sid=0, ssn=2, ppid=0] ++0.0 < sctp: SACK[flgs=0, cum_tsn=3, a_rwnd=1500, gaps=[], dups=[]] ++0.0 close(3) = 0 ++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=0] ++0.1 < sctp: SHUTDOWN_ACK[flgs=0] ++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0]