%{
/*
 * Copyright 2013 Google Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */
/*
 * Author: Author: ncardwell@google.com (Neal Cardwell)
 *
 * This is the parser for the packetdrill script language. It is
 * processed by the bison parser generator.
 *
 * For full documentation see: http://www.gnu.org/software/bison/manual/
 *
 * Here is a quick and dirty tutorial on bison:
 *
 * A bison parser specification is basically a BNF grammar for the
 * language you are parsing. Each rule specifies a nonterminal symbol
 * on the left-hand side and a sequence of terminal symbols (lexical
 * tokens) and or nonterminal symbols on the right-hand side that can
 * "reduce" to the symbol on the left hand side. When the parser sees
 * the sequence of symbols on the right where it "wants" to see a
 * nonterminal on the left, the rule fires, executing the semantic
 * action code in curly {} braces as it reduces the right hand side to
 * the left hand side.
 *
 * The semantic action code for a rule produces an output, which it
 * can reference using the $$ token. The set of possible types
 * returned in output expressions is given in the %union section of
 * the .y file. The specific type of the output for a terminal or
 * nonterminal symbol (corresponding to a field in the %union) is
 * given by the %type directive in the .y file. The action code can
 * access the outputs of the symbols on the right hand side by using
 * the notation $1 for the first symbol, $2 for the second symbol, and
 * so on.
 *
 * The lexer (generated by flex from lexer.l) feeds a stream of
 * terminal symbols up to this parser. Parser semantic actions can
 * access the lexer output for a terminal symbol with the same
 * notation they use for nonterminals.
 *
 * Here's an example rule with its semantic action in {} braces:
 *
 *     tcp_option
 *     ...
 *      | MSS INTEGER   {
 *        $$ = tcp_option_new(...);
 *        ...
 *        $$->data.mss.bytes = htons($2);
 *      }
 *
 * This rule basically says:
 *
 *   When the parser wants to see a tcp_option, if it sees an MSS from
 *   the lexer followed by an INTEGER from the lexer then run the
 *   action code that (a) stores in the output $$ a pointer to a
 *   struct tcp_option object, and then (b) stores in that object the
 *   value of the INTEGER token (accessed with $2).
 *
 */

/* The first part of the .y file consists of C code that bison copies
 * directly into the top of the .c file it generates.
 */

#include "types.h"

#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "gre_packet.h"
#include "ip.h"
#include "ip_packet.h"
#include "icmp_packet.h"
#include "logging.h"
#include "mpls.h"
#include "mpls_packet.h"
#include "sctp_packet.h"
#include "tcp_packet.h"
#include "udp_packet.h"
#include "udplite_packet.h"
#include "parse.h"
#include "script.h"
#include "tcp.h"
#include "tcp_options.h"

/* This include of the bison-generated .h file must go last so that we
 * can first include all of the declarations on which it depends.
 */
#include "parser.h"

/* Change this YYDEBUG to 1 to get verbose debug output for parsing: */
#define YYDEBUG 0
#if YYDEBUG
extern int yydebug;
#endif

extern FILE *yyin;
extern int yylineno;
extern char *yytext;
extern int yylex(void);
extern int yyparse(void);
extern int yywrap(void);

/* This mutex guards all parser global variables declared in this file. */
pthread_mutex_t parser_mutex = PTHREAD_MUTEX_INITIALIZER;

/* The input to the parser: the path name of the script file to parse. */
static const char* current_script_path = NULL;

/* The starting line number of the input script statement that we're
 * currently parsing. This may be different than yylineno if bison had
 * to look ahead and lexically scan a token on the following line to
 * decide that the current statement is done.
 */
static int current_script_line = -1;

/*
 * We uses this object to look up configuration info needed during
 * parsing (such as whether packets are IPv4 or IPv6).
 */
static const struct config *in_config = NULL;

/* The output of the parser: an output script containing
 * 1) a linked list of options
 * 2) a linked list of events
 */
static struct script *out_script = NULL;

/* The test invocation to pass back to parse_and_finalize_config(). */
struct invocation *invocation;

/* Temporary variables to allow passing absolute or ignore timestamp flags to
 * the tcp_options struct from the timestamp options. Adding fields
 * to struct tcp_option, which might be cleaner, affects the on-wire format.
 */
bool ignore_ts_val = false;
bool absolute_ts_ecr = false;

/* Copy the script contents into our single linear buffer. */
void copy_script(const char *script_buffer, struct script *script)
{
	DEBUGP("copy_script\n");

	free(script->buffer);
	script->length = strlen(script_buffer);
	script->buffer = strdup(script_buffer);
	assert(script->buffer != NULL);

	DEBUGP("copy_script: %d bytes\n", script->length);
}

/* Read the script file into a single linear buffer. */
void read_script(const char *script_path, struct script *script)
{
	int size = 0;

	DEBUGP("read_script(%s)\n", script_path);

	while (script->buffer == NULL) {
		struct stat script_info;
		int fd = -1;

		/* Allocate a buffer big enough for the whole file. */
		if (stat(script_path, &script_info) != 0)
			die("parse error: stat() of script file '%s': %s\n",
			    script_path, strerror(errno));

		/* Pick a buffer size larger than the file, so we'll
		 * know if the file grew.
		 */
		size = max((int)script_info.st_size, size) + 1;

		script->buffer = malloc(size);
		assert(script->buffer != NULL);

		/* Read the file into our buffer. */
		fd = open(script_path, O_RDONLY);
		if (fd < 0)
			die("parse error opening script file '%s': %s\n",
			    script_path, strerror(errno));

		script->length = read(fd, script->buffer, size);
		if (script->length < 0)
			die("parse error reading script file '%s': %s\n",
			    script_path, strerror(errno));

		/* If we filled the buffer, then probably another
		 * process wrote more to the file since our stat call,
		 * so we should try again.
		 */
		if (script->length == size) {
			free(script->buffer);
			script->buffer = NULL;
			script->length = 0;
		}

		if (close(fd))
			die_perror("close");
	}
	DEBUGP("read_script: %d bytes\n", script->length);
}


/* The public entry point for the script parser. Parses the
 * text script file with the given path name and fills in the script
 * object with the parsed representation.
 */
int parse_script(const struct config *config,
			 struct script *script,
			 struct invocation *callback_invocation)
{
	/* This bison-generated parser is not multi-thread safe, so we
	 * have a lock to prevent more than one thread using the
	 * parser at the same time. This is useful in the wire server
	 * context, where in general we may have more than one test
	 * thread running at the same time.
	 */
	if (pthread_mutex_lock(&parser_mutex) != 0)
		die_perror("pthread_mutex_lock");

#if YYDEBUG
	yydebug = 1;
#endif

	/* Now parse the script from our buffer. */
	yyin = fmemopen(script->buffer, script->length, "r");
	if (yyin == NULL)
		die_perror("fmemopen: parse error opening script buffer");

	current_script_path = config->script_path;
	in_config = config;
	out_script = script;
	invocation = callback_invocation;

	/* We have to reset the line number here since the wire server
	 * can do more than one yyparse().
	 */
	yylineno = 1;

	int result = yyparse();		/* invoke bison-generated parser */
	current_script_path = NULL;

	if (fclose(yyin))
		die_perror("fclose: error closing script buffer");

	/* Unlock parser. */
	if (pthread_mutex_unlock(&parser_mutex) != 0)
		die_perror("pthread_mutex_unlock");

	return result ? STATUS_ERR : STATUS_OK;
}

/* Bison emits code to call this method when there's a parse-time error.
 * We print the line number and the error message.
 */
static void yyerror(const char *message)
{
	fprintf(stderr, "%s:%d: parse error at '%s': %s\n",
		current_script_path, yylineno, yytext, message);
}

/* After we finish parsing each line of a script, we analyze the
 * semantics of the line. If we encounter an error then we print the
 * error message to stderr and exit with an error.
 */
static void semantic_error(const char* message)
{
	assert(current_script_line >= 0);
	die("%s:%d: semantic error: %s\n",
	    current_script_path, current_script_line, message);
}

/* This standard callback is invoked by flex when it encounters
 * the end of a file. We return 1 to tell flex to return EOF.
 */
int yywrap(void)
{
	return 1;
}

/* Create and initalize a new expression. */
static struct expression *new_expression(enum expression_t type)
{
	struct expression *expression = calloc(1, sizeof(struct expression));
	expression->type = type;
	return expression;
}

/* Create and initalize a new integer expression with the given
 * literal value and format string.
 */
static struct expression *new_integer_expression(s64 num, const char *format)
{
	struct expression *expression = new_expression(EXPR_INTEGER);
	expression->value.num = num;
	expression->format = format;
	return expression;
}

/* Create and initalize a new one-element expression_list. */
static struct expression_list *new_expression_list(
	struct expression *expression)
{
	struct expression_list *list;
	list = calloc(1, sizeof(struct expression_list));
	list->expression = expression;
	list->next = NULL;
	return list;
}

/* Add the expression to the end of the list. */
static void expression_list_append(struct expression_list *list,
				   struct expression *expression)
{
	while (list->next != NULL) {
		list = list->next;
	}
	list->next = new_expression_list(expression);
}

/* Create and initialize a new option. */
static struct option_list *new_option(char *name, char *value)
{
	struct option_list *opt = calloc(1, sizeof(struct option_list));
	opt->name = name;
	opt->value = value;
	return opt;
}

/* Create and initialize a new event. */
static struct event *new_event(enum event_t type)
{
	struct event *e = calloc(1, sizeof(struct event));
	e->type = type;
	e->time_usecs_end = NO_TIME_RANGE;
	e->offset_usecs = NO_TIME_RANGE;
	return e;
}

static int parse_hex_byte(const char *hex, u8 *byte)
{
	if (!isxdigit((int)hex[0]) || !isxdigit((int)hex[1])) {
		return STATUS_ERR;	/* need two hex digits per byte */
	}
	char buf[] = { hex[0], hex[1], '\0' };
	char* buf_end = NULL;
	u32 byte_value = strtoul(buf, &buf_end, 16);
	assert(byte_value <= 0xff);
	assert(buf_end == buf + 2);
	*byte = byte_value;
	return STATUS_OK;
}

/* Converts a hex string in 'hex' into bytes and stores them in a
 * buffer 'buf' of length 'buf_len' bytes; returns number of bytes in
 * out_len. Works for hex strings of arbitrary size, such as very long
 * TCP Fast Open cookies.
 */
static int parse_hex_string(const char *hex, u8 *buf, int buf_len,
			    int *out_len)
{
	u8 *out = buf;
	u8 *buf_end = buf + buf_len;
	while (hex[0] != '\0') {
		if (out >= buf_end) {
			return STATUS_ERR;	/* ran out of output space */
		}
		if (parse_hex_byte(hex, out))
			return STATUS_ERR;	/* bad character */
		hex += 2;
		out += 1;
	}
	*out_len = out - buf;
	assert(*out_len <= buf_len);
	return STATUS_OK;
}

static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
						    char **error)
{
	int cookie_string_len = strlen(cookie_string);
	if (cookie_string_len & 1) {
		asprintf(error,
			 "TCP fast open cookie has an odd number of digits");
		return NULL;
	}
	int cookie_bytes = cookie_string_len / 2;  /* 2 hex chars per byte */
	if (cookie_bytes > MAX_TCP_FAST_OPEN_COOKIE_BYTES) {
		asprintf(error, "TCP fast open cookie too long");
		asprintf(error, "TCP fast open cookie of %d bytes "
			 "exceeds maximum cookie length of %d bytes",
			 cookie_bytes, MAX_TCP_FAST_OPEN_COOKIE_BYTES);
		return NULL;
	}
	u8 option_bytes = TCPOLEN_EXP_FASTOPEN_BASE + cookie_bytes;
	struct tcp_option *option;
	option = tcp_option_new(TCPOPT_EXP, option_bytes);
	option->data.fast_open.magic = htons(TCPOPT_FASTOPEN_MAGIC);
	int parsed_bytes = 0;
	/* Parse cookie. This should be an ASCII hex string
	 * representing an even number of bytes (4-16 bytes). But we
	 * do not enforce this, since we want to allow test cases that
	 * supply invalid cookies.
	 */
	if (parse_hex_string(cookie_string, option->data.fast_open.cookie,
			     sizeof(option->data.fast_open.cookie),
			     &parsed_bytes)) {
		free(option);
		asprintf(error,
			 "TCP fast open cookie is not a valid hex string");
		return NULL;
	}
	assert(parsed_bytes == cookie_bytes);
	return option;
}

%}

%locations
%expect 1  /* we expect a shift/reduce conflict for the | binary expression */
/* The %union section specifies the set of possible types for values
 * for all nonterminal and terminal symbols in the grammar.
 */
%union {
	s64 integer;
	struct abs_integer abs_integer;
	struct ignore_integer ignore_integer;
	double floating;
	char *string;
	char *reserved;
	s64 time_usecs;
	enum direction_t direction;
	enum ip_ecn_t ip_ecn;
	struct mpls_stack *mpls_stack;
	struct mpls mpls_stack_entry;
	u16 port;
	s32 window;
	u32 sequence_number;
	struct {
		u32 start_sequence;
		u16 payload_bytes;
		bool absolute;
		bool ignore;
	} tcp_sequence_info;
	struct {
		int protocol;
		u16 payload_bytes;
		u32 verification_tag;	/* used for SCTP */
		u32 start_sequence;	/* used for TCP */
		u16 checksum_coverage;	/* used for UDPLite */
		u16 udp_src_port;
		u16 udp_dst_port;
	} transport_info;
	struct {
		u16 udp_src_port;
		u16 udp_dst_port;
	} udp_encaps_info;
	struct {
		bool bad_crc32c;
		s64 tag;
	} sctp_header_spec;
	struct option_list *option;
	struct event *event;
	struct packet *packet;
	struct sctp_chunk_list_item *chunk_list_item;
	struct sctp_chunk_list *chunk_list;
	struct sctp_byte_list_item *byte_list_item;
	struct sctp_byte_list *byte_list;
	struct sctp_u16_list *u16_list;
	struct sctp_u16_list_item *u16_item;
	struct sctp_sack_block_list_item *sack_block_list_item;
	struct sctp_sack_block_list *sack_block_list;
	struct sctp_forward_tsn_ids_list *forward_tsn_ids_list;
	struct sctp_forward_tsn_ids_list_item  *forward_tsn_ids_list_item;
	struct sctp_i_forward_tsn_ids_list *i_forward_tsn_ids_list;
	struct sctp_i_forward_tsn_ids_list_item  *i_forward_tsn_ids_list_item;
	struct sctp_address_type_list_item *address_type_list_item;
	struct sctp_address_type_list *address_type_list;
	struct sctp_parameter_type_list_item *parameter_type_list_item;
	struct sctp_parameter_type_list *parameter_type_list;
	struct sctp_parameter_list_item *parameter_list_item;
	struct sctp_parameter_list *parameter_list;
	struct sctp_cause_list_item *cause_list_item;
	struct sctp_cause_list *cause_list;
	struct syscall_spec *syscall;
	struct command_spec *command;
	struct code_spec *code;
	struct tcp_option *tcp_option;
	struct tcp_options *tcp_options;
	struct expression *expression;
	struct expression_list *expression_list;
	struct errno_spec *errno_info;
}

/* The specific type of the output for a symbol is given by the %type
 * directive. By convention terminal symbols returned from the lexer
 * have ALL_CAPS names, and nonterminal symbols have lower_case names.
 */
%token ELLIPSIS
%token <reserved> SA_FAMILY SIN_PORT SIN_ADDR _HTONS_ _HTONL_ INET_ADDR
%token <reserved> MSG_NAME MSG_IOV MSG_FLAGS MSG_CONTROL CMSG_LEN CMSG_LEVEL CMSG_TYPE CMSG_DATA
%token <reserved> SF_HDTR_HEADERS SF_HDTR_TRAILERS
%token <reserved> FD EVENTS REVENTS ONOFF LINGER
%token <reserved> ACK ECR EOL MSS NOP SACK NR_SACK SACKOK TIMESTAMP VAL WIN WSCALE PRO
%token <reserved> FAST_OPEN
%token <reserved> IOV_BASE IOV_LEN
%token <reserved> ECT0 ECT1 CE ECT01 NO_ECN
%token <reserved> IPV4 IPV6 ICMP SCTP UDP UDPLITE GRE MTU
%token <reserved> MPLS LABEL TC TTL
%token <reserved> OPTION
%token <reserved> AF_NAME AF_ARG
%token <reserved> FUNCTION_SET_NAME PCBCNT
%token <reserved> SRTO_ASSOC_ID SRTO_INITIAL SRTO_MAX SRTO_MIN
%token <reserved> SINIT_NUM_OSTREAMS SINIT_MAX_INSTREAMS SINIT_MAX_ATTEMPTS
%token <reserved> SINIT_MAX_INIT_TIMEO
%token <reserved> ASSOC_ID ASSOC_VALUE SHMAC_NUMBER_OF_IDENTS SHMAC_IDENTS
%token <reserved> STREAM_ID STREAM_VALUE
%token <reserved> SCACT_ASSOC_ID SCACT_KEYNUMBER SACK_ASSOC_ID SACK_DELAY SACK_FREQ
%token <reserved> SSTAT_ASSOC_ID SSTAT_STATE SSTAT_RWND SSTAT_UNACKDATA SSTAT_PENDDATA
%token <reserved> SSTAT_INSTRMS SSTAT_OUTSTRMS SSTAT_FRAGMENTATION_POINT
%token <reserved> SSTAT_PRIMARY
%token <reserved> SPINFO_ASSOC_ID SPINFO_ADDRESS SPINFO_STATE SPINFO_CWND SPINFO_SRTT SPINFO_RTO
%token <reserved> SPINFO_MTU GAUTH_ASSOC_ID GAUTH_NUMBER_OF_CHUNKS GAUTH_CHUNKS
%token <reserved> CHUNK DATA INIT INIT_ACK HEARTBEAT HEARTBEAT_ACK ABORT
%token <reserved> SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECNE CWR
%token <reserved> SHUTDOWN_COMPLETE I_DATA PAD RECONFIG FORWARD_TSN I_FORWARD_TSN
%token <reserved> TYPE FLAGS LEN
%token <reserved> TAG A_RWND OS IS TSN SID SSN MID PPID FSN CUM_TSN GAPS NR_GAPS DUPS
%token <reserved> PARAMETER HEARTBEAT_INFORMATION IPV4_ADDRESS IPV6_ADDRESS
%token <reserved> STATE_COOKIE UNRECOGNIZED_PARAMETER COOKIE_PRESERVATIVE
%token <reserved> HOSTNAME_ADDRESS SUPPORTED_ADDRESS_TYPES ECN_CAPABLE FORWARD_TSN_SUPPORTED
%token <reserved> SUPPORTED_EXTENSIONS ADAPTATION_CODE_POINT ADAPTATION_INDICATION
%token <reserved> OUTGOING_SSN_RESET REQ_SN RESP_SN LAST_TSN IDS SIDS INCOMING_SSN_RESET
%token <reserved> RECONFIG_RESPONSE RESULT SENDER_NEXT_TSN RECEIVER_NEXT_TSN
%token <reserved> SSN_TSN_RESET ADD_INCOMING_STREAMS NUMBER_OF_NEW_STREAMS
%token <reserved> ADD_OUTGOING_STREAMS RECONFIG_REQUEST_GENERIC
%token <reserved> ADDR INCR TYPES PARAMS
%token <reserved> IPV4_TYPE IPV6_TYPE HOSTNAME_TYPE
%token <reserved> CAUSE
%token <reserved> CAUSE_CODE CAUSE_INFO
%token <reserved> INVALID_STREAM_IDENTIFIER MISSING_MANDATORY_PARAMETER
%token <reserved> STALE_COOKIE_ERROR OUT_OF_RESOURCE
%token <reserved> UNRESOLVABLE_ADDRESS UNRECOGNIZED_CHUNK_TYPE
%token <reserved> INVALID_MANDATORY_PARAMETER NO_USER_DATA
%token <reserved> COOKIE_RECEIVED_WHILE_SHUTDOWN RESTART_WITH_NEW_ADDRESSES
%token <reserved> USER_INITIATED_ABORT PROTOCOL_VIOLATION
%token <reserved> STALENESS CHK PARAM UNRECOGNIZED_PARAMETERS
%token <reserved> SPP_ASSOC_ID SPP_ADDRESS SPP_HBINTERVAL SPP_PATHMAXRXT SPP_PATHMTU
%token <reserved> SPP_FLAGS SPP_IPV6_FLOWLABEL_ SPP_DSCP_
%token <reserved> SASOC_ASOCMAXRXT SASOC_ASSOC_ID SASOC_NUMBER_PEER_DESTINATIONS SASOC_PEER_RWND
%token <reserved> SASOC_LOCAL_RWND SASOC_COOKIE_LIFE SE_ASSOC_ID SE_TYPE SE_ON
%token <reserved> SSP_ASSOC_ID SSP_ADDR
%token <reserved> SND_SID SND_FLAGS SND_PPID SND_CONTEXT SND_ASSOC_ID SSB_ADAPTATION_IND
%token <reserved> BAD_CRC32C NULL_
%token <reserved> SINFO_STREAM SINFO_SSN SINFO_FLAGS SINFO_PPID SINFO_CONTEXT SINFO_ASSOC_ID
%token <reserved> SINFO_TIMETOLIVE SINFO_TSN SINFO_CUMTSN SINFO_PR_VALUE SERINFO_NEXT_FLAGS
%token <reserved> SERINFO_NEXT_STREAM SERINFO_NEXT_AID SERINFO_NEXT_LENGTH SERINFO_NEXT_PPID
%token <reserved> PR_POLICY PR_VALUE PR_ASSOC_ID AUTH_KEYNUMBER SENDV_FLAGS SENDV_SNDINFO
%token <reserved> SENDV_PRINFO SENDV_AUTHINFO
%token <reserved> RCV_SID RCV_SSN RCV_FLAGS RCV_PPID RCV_TSN RCV_CUMTSN RCV_CONTEXT RCV_ASSOC_ID
%token <reserved> NXT_SID NXT_FLAGS NXT_PPID NXT_LENGTH NXT_ASSOC_ID
%token <reserved> RECVV_RCVINFO RECVV_NXTINFO
%token <reserved> SSE_TYPE SSE_FLAGS SSE_LENGTH SSE_ASSOC_ID
%token <reserved> SENDER_DRY_TYPE SENDER_DRY_FLAGS SENDER_DRY_LENGTH SENDER_DRY_ASSOC_ID
%token <reserved> _SCTP_DATA_IO_EVENT_ _SCTP_ASSOCIATION_EVENT_ _SCTP_ADDRESS_EVENT_
%token <reserved> _SCTP_SEND_FAILURE_EVENT_ _SCTP_PEER_ERROR_EVENT_ _SCTP_SHUTDOWN_EVENT_
%token <reserved> _SCTP_PARTIAL_DELIVERY_EVENT_ _SCTP_ADAPTATION_LAYER_EVENT_
%token <reserved> _SCTP_AUTHENTICATION_EVENT_ _SCTP_SENDER_DRY_EVENT_
%token <reserved> SAC_TYPE SAC_FLAGS SAC_LENGTH SAC_STATE SAC_ERROR SAC_OUTBOUND_STREAMS
%token <reserved> SAC_INBOUND_STREAMS SAC_ASSOC_ID SAC_INFO
%token <reserved> SSFE_TYPE SSFE_FLAGS SSFE_LENGTH SSFE_ERROR SSFE_INFO SSFE_ASSOC_ID SSFE_DATA
%token <reserved> AUTH_TYPE AUTH_FLAGS AUTH_LENGTH AUTH_INDICATION AUTH_ASSOC_ID
%token <reserved> SRE_TYPE SRE_FLAGS SRE_LENGTH SRE_ERROR SRE_ASSOC_ID SRE_DATA PDAPI_ASSOC_ID
%token <reserved> PDAPI_TYPE PDAPI_FLAGS PDAPI_LENGTH PDAPI_INDICATION PDAPI_STREAM PDAPI_SEQ
%token <reserved> SPC_TYPE SPC_FLAGS SPC_LENGTH SPC_AADDR SPC_STATE SPC_ERROR SPC_ASSOC_ID
%token <reserved> SSF_TYPE SSF_LENGTH SSF_FLAGS SSF_ERROR SSF_INFO SSF_ASSOC_ID SSF_DATA
%token <reserved> SAI_TYPE SAI_FLAGS SAI_LENGTH SAI_ADAPTATION_IND SAI_ASSOC_ID
%token <reserved> GAIDS_NUMBER_OF_IDS GAIDS_ASSOC_ID SSPP_ASSOC_ID SSPP_ADDR
%token <reserved> SN_TYPE SN_FLAGS SN_LENGTH SAUTH_CHUNK
%token <reserved> SCA_ASSOC_ID SCA_KEYNUMBER SCA_KEYLENGTH SCA_KEY
%token <reserved> SRS_ASSOC_ID SRS_FLAGS SRS_NUMBER_STREAMS SRS_STREAM_LIST
%token <reserved> SAS_ASSOC_ID SAS_INSTRMS SAS_OUTSTRMS
%token <reserved> STRRESET_TYPE STRRESET_FLAGS STRRESET_LENGTH STRRESET_ASSOC_ID STRRESET_STREAM_LIST
%token <reserved> ASSOCRESET_TYPE ASSOCRESET_FLAGS ASSOCRESET_LENGTH ASSOCRESET_ASSOC_ID ASSOCRESET_LOCAL_TSN ASSOCRESET_REMOTE_TSN
%token <reserved> STRCHANGE_TYPE STRCHANGE_FLAGS STRCHANGE_LENGTH STRCHANGE_ASSOC_ID STRCHANGE_INSTRMS STRCHANGE_OUTSTRMS
%token <reserved> SUE_ASSOC_ID SUE_ADDRESS SUE_PORT
%token <floating> FLOAT
%token <integer> INTEGER HEX_INTEGER
%token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR
%type <abs_integer> abs_integer
%type <ignore_integer> ignore_integer
%type <direction> direction
%type <ip_ecn> opt_ip_info
%type <ip_ecn> ip_ecn
%type <option> option options opt_options
%type <event> event events event_time action
%type <time_usecs> time opt_end_time
%type <packet> packet_spec
%type <packet> sctp_packet_spec tcp_packet_spec
%type <packet> udp_packet_spec udplite_packet_spec
%type <packet> icmp_packet_spec
%type <packet> packet_prefix
%type <syscall> syscall_spec
%type <command> command_spec
%type <code> code_spec
%type <mpls_stack> mpls_stack
%type <mpls_stack_entry> mpls_stack_entry
%type <integer> opt_mpls_stack_bottom
%type <integer> opt_icmp_mtu
%type <string> icmp_type opt_icmp_code flags
%type <string> opt_tcp_fast_open_cookie tcp_fast_open_cookie
%type <string> opt_note note word_list
%type <string> option_flag option_value script
%type <window> opt_window
%type <sequence_number> opt_ack
%type <tcp_sequence_info> seq
%type <transport_info> opt_icmp_echoed
%type <tcp_options> opt_tcp_options tcp_option_list
%type <tcp_option> tcp_option sack_block_list sack_block
%type <string> function_name
%type <expression_list> expression_list function_arguments
%type <expression> expression binary_expression array
%type <expression> decimal_integer hex_integer data
%type <expression> inaddr sockaddr msghdr cmsghdr cmsg_level cmsg_type cmsg_data
%type <expression> sf_hdtr iovec pollfd opt_revents
%type <expression> linger l_onoff l_linger
%type <expression> accept_filter_arg af_name af_arg
%type <expression> tcp_function_set function_set_name pcbcnt
%type <udp_encaps_info> opt_udp_encaps_info
%type <sctp_header_spec> sctp_header_spec
%type <expression> sctp_assoc_id
%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_hmacalgo
%type <expression> shmac_number_of_idents
%type <expression> sctp_authkeyid scact_keynumber 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 ssp_addr
%type <expression> spinfo_address spinfo_state spinfo_cwnd spinfo_srtt spinfo_rto spinfo_mtu
%type <expression> sctp_authchunks gauth_number_of_chunks
%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 sctp_setprim null
%type <expression> sctp_sndrcvinfo sinfo_stream sinfo_ssn sinfo_flags sinfo_ppid sinfo_context
%type <expression> sinfo_timetolive sinfo_tsn sinfo_cumtsn sinfo_pr_value serinfo_next_flags
%type <expression> serinfo_next_stream serinfo_next_aid serinfo_next_length serinfo_next_ppid sctp_extrcvinfo
%type <expression> sctp_prinfo sctp_authinfo pr_policy sctp_sendv_spa sctp_default_prinfo
%type <expression> sctp_rcvinfo rcv_sid rcv_ssn rcv_flags rcv_ppid rcv_tsn rcv_cumtsn rcv_context
%type <expression> sctp_nxtinfo nxt_sid nxt_flags nxt_ppid nxt_length sctp_recvv_rn
%type <expression> sctp_shutdown_event sse_type sse_flags sse_length
%type <expression> sctp_sender_dry_event sender_dry_type sender_dry_flags sender_dry_length
%type <expression> sctp_event_subscribe
%type <expression> sctp_assoc_change sac_type sac_flags sac_length sac_state sac_error sac_outbound_streams
%type <expression> sac_inbound_streams sac_info
%type <expression> sctp_send_failed_event ssfe_type ssfe_flags ssfe_length ssfe_error ssfe_data
%type <expression> sctp_authkey_event auth_type auth_flags auth_length auth_keynumber auth_indication
%type <expression> sctp_remote_error sre_type sre_flags sre_length sre_error sre_data
%type <expression> sctp_pdapi_event pdapi_type pdapi_flags pdapi_length pdapi_indication pdapi_stream pdapi_seq
%type <expression> sctp_paddr_change spc_type spc_flags spc_length spc_aaddr spc_error spc_state
%type <expression> sctp_send_failed ssf_type ssf_length ssf_flags ssf_error ssf_info ssf_data
%type <expression> sctp_adaptation_event sai_type sai_flags sai_length sai_adaptation_ind
%type <expression> sctp_tlv sn_type sn_flags sn_length sctp_assoc_ids gaids_number_of_ids
%type <expression> sctp_setpeerprim sctp_authchunk sctp_authkey
%type <expression> sctp_reset_streams srs_flags
%type <expression> sctp_stream_reset_event strreset_type strreset_flags strreset_length
%type <expression> sctp_assoc_reset_event assocreset_type assocreset_flags assocreset_length
%type <expression> assocreset_local_tsn assocreset_remote_tsn
%type <expression> sctp_stream_change_event strchange_type strchange_flags strchange_length strchange_instrms strchange_outstrms
%type <expression> sctp_add_streams
%type <expression> sctp_udpencaps sue_address sue_port
%type <errno_info> opt_errno
%type <chunk_list> sctp_chunk_list_spec
%type <chunk_list_item> sctp_chunk_spec
%type <chunk_list_item> sctp_generic_chunk_spec
%type <chunk_list_item> sctp_data_chunk_spec
%type <chunk_list_item> sctp_init_chunk_spec sctp_init_ack_chunk_spec
%type <chunk_list_item> sctp_sack_chunk_spec sctp_nr_sack_chunk_spec
%type <chunk_list_item> sctp_heartbeat_chunk_spec sctp_heartbeat_ack_chunk_spec
%type <chunk_list_item> sctp_abort_chunk_spec
%type <chunk_list_item> sctp_shutdown_chunk_spec
%type <chunk_list_item> sctp_shutdown_ack_chunk_spec
%type <chunk_list_item> sctp_error_chunk_spec
%type <chunk_list_item> sctp_cookie_echo_chunk_spec sctp_cookie_ack_chunk_spec
%type <chunk_list_item> sctp_ecne_chunk_spec sctp_cwr_chunk_spec
%type <chunk_list_item> sctp_shutdown_complete_chunk_spec
%type <chunk_list_item> sctp_i_data_chunk_spec
%type <chunk_list_item> sctp_pad_chunk_spec sctp_reconfig_chunk_spec
%type <chunk_list_item> sctp_forward_tsn_spec sctp_i_forward_tsn_spec
%type <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec
%type <parameter_list_item> sctp_parameter_spec
%type <parameter_list_item> sctp_generic_parameter_spec
%type <parameter_list_item> sctp_heartbeat_information_parameter_spec
%type <parameter_list_item> sctp_ipv4_address_parameter_spec
%type <parameter_list_item> sctp_ipv6_address_parameter_spec
%type <parameter_list_item> sctp_state_cookie_parameter_spec
%type <parameter_list_item> sctp_unrecognized_parameter_parameter_spec
%type <parameter_list_item> sctp_cookie_preservative_parameter_spec
%type <parameter_list_item> sctp_hostname_address_parameter_spec
%type <parameter_list_item> sctp_supported_address_types_parameter_spec
%type <parameter_list_item> sctp_ecn_capable_parameter_spec
%type <parameter_list_item> sctp_fornward_tsn_supported_spec
%type <parameter_list_item> sctp_supported_extensions_parameter_spec
%type <parameter_list_item> sctp_adaptation_indication_parameter_spec
%type <parameter_list_item> sctp_pad_parameter_spec
%type <parameter_list_item> outgoing_ssn_reset_request incoming_ssn_reset_request
%type <parameter_list_item> reconfig_response ssn_tsn_reset_request generic_reconfig_request
%type <parameter_list_item> add_outgoing_streams_request add_incoming_streams_request
%type <cause_list> opt_cause_list_spec sctp_cause_list_spec
%type <cause_list_item> sctp_cause_spec
%type <cause_list_item> sctp_generic_cause_spec
%type <cause_list_item> sctp_invalid_stream_identifier_cause_spec
%type <cause_list_item> sctp_missing_mandatory_parameter_cause_spec
%type <cause_list_item> sctp_stale_cookie_error_cause_spec
%type <cause_list_item> sctp_out_of_resources_cause_spec
%type <cause_list_item> sctp_unresolvable_address_cause_spec
%type <cause_list_item> sctp_unrecognized_chunk_type_cause_spec
%type <cause_list_item> sctp_invalid_mandatory_parameter_cause_spec
%type <cause_list_item> sctp_unrecognized_parameters_cause_spec
%type <cause_list_item> sctp_no_user_data_cause_spec
%type <cause_list_item> sctp_cookie_received_while_shutdown_cause_spec
%type <cause_list_item> sctp_restart_with_new_addresses_cause_spec
%type <cause_list_item> sctp_user_initiated_abort_cause_spec
%type <cause_list_item> sctp_protocol_violation_cause_spec
%type <integer> chunk_type opt_chunk_type opt_parameter_type opt_cause_code
%type <integer> opt_flags opt_data_flags opt_abort_flags
%type <integer> opt_shutdown_complete_flags opt_i_data_flags opt_len
%type <integer> opt_tag opt_a_rwnd opt_os opt_is opt_tsn opt_sid opt_ssn
%type <integer> opt_mid opt_fsn
%type <integer> opt_cum_tsn opt_ppid opt_sender_next_tsn opt_receiver_next_tsn
%type <integer> opt_req_sn opt_resp_sn opt_last_tsn opt_result opt_number_of_new_streams
%type <byte_list> opt_val opt_info byte_list chunk_types_list
%type <byte_list_item> byte
%type <u16_list> u16_list
%type <u16_item> u16_item
%type <sack_block_list> opt_gaps opt_nr_gaps gap_list opt_dups dup_list
%type <sack_block_list_item> gap dup
%type <forward_tsn_ids_list> opt_stream_identifier  ids_list
%type <forward_tsn_ids_list_item> id
%type <i_forward_tsn_ids_list> opt_i_forward_tsn_stream_identifier i_forward_tsn_ids_list
%type <i_forward_tsn_ids_list_item> i_forward_tsn_id
%type <address_type_list> address_types_list
%type <address_type_list_item> address_type
%type <parameter_type_list> parameter_types_list
%type <parameter_type_list_item> parameter_type

%%  /* The grammar follows. */

script
: opt_options opt_init_command events {
	$$ = NULL;		/* The parser output is in out_script */
}
;

opt_options
:		{
	$$ = NULL;
	parse_and_finalize_config(invocation);
}
| options	{
	$$ = $1;
	parse_and_finalize_config(invocation);
}
;

options
: option		{
	out_script->option_list = $1;
	$$ = $1;		/* return the tail so we can append to it */
}
| options option	{
	$1->next = $2;
	$$ = $2;		/* return the tail so we can append to it */
}
;

option
: option_flag '=' option_value {
	$$ = new_option($1, $3);
}

option_flag
: OPTION	{ $$ = $1; }
;

option_value
: INTEGER	{ $$ = strdup(yytext); }
| WORD		{ $$ = $1; }
| STRING	{ $$ = $1; }
| IPV4_ADDR	{ $$ = $1; }
| IPV6_ADDR	{ $$ = $1; }
| IPV4		{ $$ = strdup("ipv4"); }
| IPV6		{ $$ = strdup("ipv6"); }
;

opt_init_command
:               { }
| init_command  { }
;

init_command
: command_spec  { out_script->init_command = $1; }
;

events
: event        {
	out_script->event_list = $1;  /* save pointer to event list as output
				       * of parser */
	$$ = $1;          /* return the tail so that we can append to it */
}
| events event {
	$1->next = $2;    /* link new event to the end of the existing list */
	$$ = $2;          /* return the tail so that we can append to it */
}
;

event
: event_time action  {
	$$ = $2;
	$$->line_number = $1->line_number;   /* use timestamp's line */
	$$->time_usecs  = $1->time_usecs;
	$$->time_usecs_end  = $1->time_usecs_end;
	$$->time_type = $1->time_type;

	if ($$->time_usecs_end != NO_TIME_RANGE) {
		if ($$->time_usecs_end < $$->time_usecs)
			semantic_error("time range is backwards");
	}
	if ($$->time_type == ANY_TIME &&  ($$->type != PACKET_EVENT ||
	    packet_direction($$->event.packet) != DIRECTION_OUTBOUND)) {
		yylineno = $$->line_number;
		semantic_error("event time <star> can only be used with "
			       "outbound packets");
	} else if (($$->time_type == ABSOLUTE_RANGE_TIME ||
		    $$->time_type == RELATIVE_RANGE_TIME) &&
	           ($$->type != PACKET_EVENT ||
		    packet_direction($$->event.packet) != DIRECTION_OUTBOUND)) {
		yylineno = $$->line_number;
		semantic_error("event time range can only be used with "
			       "outbound packets");
	}
	free($1);
}
;

event_time
: '+' time	{
	$$ = new_event(INVALID_EVENT);
	$$->line_number = @2.first_line;
	$$->time_usecs = $2;
	$$->time_type = RELATIVE_TIME;
}
| time         {
	$$ = new_event(INVALID_EVENT);
	$$->line_number = @1.first_line;
	$$->time_usecs = $1;
	$$->time_type = ABSOLUTE_TIME;
}
| '*'		{
	$$ = new_event(INVALID_EVENT);
	$$->line_number = @1.first_line;
	$$->time_type = ANY_TIME;
}
| time '~' time	{
	$$ = new_event(INVALID_EVENT);
	$$->line_number = @1.first_line;
	$$->time_type = ABSOLUTE_RANGE_TIME;
	$$->time_usecs = $1;
	$$->time_usecs_end = $3;
}
| '+' time '~' '+' time {
	$$ = new_event(INVALID_EVENT);
	$$->line_number = @1.first_line;
	$$->time_type = RELATIVE_RANGE_TIME;
	$$->time_usecs = $2;
	$$->time_usecs_end = $5;
}
;

time
: FLOAT        {
	if ($1 < 0) {
		semantic_error("negative time");
	}
	$$ = (s64)($1 * 1.0e6); /* convert float secs to s64 microseconds */
}
| INTEGER	{
	if ($1 < 0) {
		semantic_error("negative time");
	}
	$$ = (s64)($1 * 1000000); /* convert int secs to s64 microseconds */
}
;

action
: packet_spec  { $$ = new_event(PACKET_EVENT);  $$->event.packet  = $1; }
| syscall_spec { $$ = new_event(SYSCALL_EVENT); $$->event.syscall = $1; }
| command_spec { $$ = new_event(COMMAND_EVENT); $$->event.command = $1; }
| code_spec    { $$ = new_event(CODE_EVENT);    $$->event.code    = $1; }
;

packet_spec
: sctp_packet_spec    { $$ = $1; }
| tcp_packet_spec     { $$ = $1; }
| udp_packet_spec     { $$ = $1; }
| udplite_packet_spec { $$ = $1; }
| icmp_packet_spec    { $$ = $1; }
;

opt_udp_encaps_info
:	{
	$$.udp_src_port = 0;
	$$.udp_dst_port = 0;
}
| '/' UDP '(' INTEGER '>' INTEGER ')' {
	if (!is_valid_u16($4)) {
		semantic_error("UDP source port out of range");
	}
	if (!is_valid_u16($6)) {
		semantic_error("UDP destination port out of range");
	}
	$$.udp_src_port = $4;
	$$.udp_dst_port = $6;
}
;

sctp_header_spec
: SCTP {
	$$.bad_crc32c = false;
	$$.tag = -1;
}
| SCTP '(' BAD_CRC32C ')' {
	$$.bad_crc32c = true;
	$$.tag = -1;
}
| SCTP '(' TAG '=' INTEGER ')' {
	if (!is_valid_u32($5)) {
		semantic_error("tag value out of range");
	}
	$$.bad_crc32c = false;
	$$.tag = $5;
}
| SCTP '(' BAD_CRC32C ',' TAG '=' INTEGER ')' {
	if (!is_valid_u32($7)) {
		semantic_error("tag value out of range");
	}
	$$.bad_crc32c = true;
	$$.tag = $7;
}
;

sctp_packet_spec
: packet_prefix opt_ip_info sctp_header_spec opt_udp_encaps_info ':' sctp_chunk_list_spec {
	char *error = NULL;
	struct packet *outer = $1, *inner = NULL;
	enum direction_t direction = outer->direction;

	inner = new_sctp_packet(in_config->wire_protocol, direction, $2,
	                        $3.tag, $3.bad_crc32c, $6,
	                        $4.udp_src_port, $4.udp_dst_port,
	                        &error);
	if (inner == NULL) {
		assert(error != NULL);
		semantic_error(error);
		free(error);
	}

	$$ = packet_encapsulate_and_free(outer, inner);
}
| packet_prefix opt_ip_info sctp_header_spec opt_udp_encaps_info ':' '[' byte_list ']' {
	char *error = NULL;
	struct packet *outer = $1, *inner = NULL;
	enum direction_t direction = outer->direction;

	inner = new_sctp_generic_packet(in_config->wire_protocol, direction, $2,
	                                $3.tag, $3.bad_crc32c, $7,
	                                $4.udp_src_port, $4.udp_dst_port,
	                                &error);
	if (inner == NULL) {
		assert(error != NULL);
		semantic_error(error);
		free(error);
	}

	$$ = packet_encapsulate_and_free(outer, inner);
}
;

sctp_chunk_list_spec
:                                          { $$ = sctp_chunk_list_new(); }
| sctp_chunk_spec                          { $$ = sctp_chunk_list_new();
                                             sctp_chunk_list_append($$, $1); }
| sctp_chunk_list_spec ';' sctp_chunk_spec { $$ = $1;
                                             sctp_chunk_list_append($1, $3); }
;

sctp_chunk_spec
: sctp_generic_chunk_spec           { $$ = $1; }
| sctp_data_chunk_spec              { $$ = $1; }
| sctp_init_chunk_spec              { $$ = $1; }
| sctp_init_ack_chunk_spec          { $$ = $1; }
| sctp_sack_chunk_spec              { $$ = $1; }
| sctp_nr_sack_chunk_spec           { $$ = $1; }
| sctp_heartbeat_chunk_spec         { $$ = $1; }
| sctp_heartbeat_ack_chunk_spec     { $$ = $1; }
| sctp_abort_chunk_spec             { $$ = $1; }
| sctp_shutdown_chunk_spec          { $$ = $1; }
| sctp_shutdown_ack_chunk_spec      { $$ = $1; }
| sctp_error_chunk_spec             { $$ = $1; }
| sctp_cookie_echo_chunk_spec       { $$ = $1; }
| sctp_cookie_ack_chunk_spec        { $$ = $1; }
| sctp_ecne_chunk_spec              { $$ = $1; }
| sctp_cwr_chunk_spec               { $$ = $1; }
| sctp_shutdown_complete_chunk_spec { $$ = $1; }
| sctp_i_data_chunk_spec            { $$ = $1; }
| sctp_pad_chunk_spec               { $$ = $1; }
| sctp_reconfig_chunk_spec          { $$ = $1; }
| sctp_forward_tsn_spec             { $$ = $1; }
| sctp_i_forward_tsn_spec           { $$ = $1; }
;

chunk_type
: HEX_INTEGER {
	if (!is_valid_u8($1)) {
		semantic_error("type value out of range");
	}
	$$ = $1;
}
| INTEGER {
	if (!is_valid_u8($1)) {
		semantic_error("type value out of range");
	}
	$$ = $1;
}
| DATA {
	$$ = SCTP_DATA_CHUNK_TYPE;
}
| INIT {
	$$ = SCTP_INIT_CHUNK_TYPE;
}
| INIT_ACK {
	$$ = SCTP_INIT_ACK_CHUNK_TYPE;
}
| SACK {
	$$ = SCTP_SACK_CHUNK_TYPE;
}
| NR_SACK {
	$$ = SCTP_NR_SACK_CHUNK_TYPE;
}
| HEARTBEAT {
	$$ = SCTP_HEARTBEAT_CHUNK_TYPE;
}
| HEARTBEAT_ACK {
	$$ = SCTP_HEARTBEAT_ACK_CHUNK_TYPE;
}
| ABORT {
	$$ = SCTP_ABORT_CHUNK_TYPE;
}
| SHUTDOWN {
	$$ = SCTP_SHUTDOWN_CHUNK_TYPE;
}
| SHUTDOWN_ACK {
	$$ = SCTP_SHUTDOWN_ACK_CHUNK_TYPE;
}
| ERROR {
	$$ = SCTP_ERROR_CHUNK_TYPE;
}
| COOKIE_ECHO {
	$$ = SCTP_COOKIE_ECHO_CHUNK_TYPE;
}
| COOKIE_ACK {
	$$ = SCTP_COOKIE_ACK_CHUNK_TYPE;
}
| ECNE {
	$$ = SCTP_ECNE_CHUNK_TYPE;
}
| CWR {
	$$ = SCTP_CWR_CHUNK_TYPE;
}
| SHUTDOWN_COMPLETE{
	$$ = SCTP_SHUTDOWN_COMPLETE_CHUNK_TYPE;
}
| I_DATA {
	$$ = SCTP_I_DATA_CHUNK_TYPE;
}
| PAD {
	$$ = SCTP_PAD_CHUNK_TYPE;
} 
| RECONFIG {
	$$ = SCTP_RECONFIG_CHUNK_TYPE;
}
| FORWARD_TSN {
	$$ = SCTP_FORWARD_TSN_CHUNK_TYPE;
}
| I_FORWARD_TSN {
	$$ = SCTP_I_FORWARD_TSN_CHUNK_TYPE;
}
;

opt_chunk_type
: TYPE '=' ELLIPSIS    { $$ = -1; }
| TYPE '=' chunk_type {
	$$ = $3;
}
;

opt_flags
: FLAGS '=' ELLIPSIS    { $$ = -1; }
| FLAGS '=' HEX_INTEGER {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
| FLAGS '=' INTEGER     {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
;

opt_len
: LEN '=' ELLIPSIS { $$ = -1; }
| LEN '=' INTEGER  {
	if (!is_valid_u16($3)) {
		semantic_error("length value out of range");
	}
	$$ = $3;
}
;

opt_val
: VAL '=' ELLIPSIS          { $$ = NULL; }
| VAL '=' '[' ELLIPSIS ']'  { $$ = NULL; }
| VAL '=' '[' byte_list ']' { $$ = $4; }
;

opt_info
: CAUSE_INFO '=' ELLIPSIS          { $$ = NULL; }
| CAUSE_INFO '=' '[' ELLIPSIS ']'  { $$ = NULL; }
| CAUSE_INFO '=' '[' byte_list ']' { $$ = $4; }
;

byte_list
:                    { $$ = sctp_byte_list_new(); }
| byte               { $$ = sctp_byte_list_new();
                       sctp_byte_list_append($$, $1); }
| byte_list ',' byte { $$ = $1;
                       sctp_byte_list_append($1, $3); }
;

byte
: HEX_INTEGER {
	if (!is_valid_u8($1)) {
		semantic_error("byte value out of range");
	}
	$$ = sctp_byte_list_item_new($1);
}
| INTEGER {
	if (!is_valid_u8($1)) {
		semantic_error("byte value out of range");
	}
	$$ = sctp_byte_list_item_new($1);
}
;

u16_list
:                       { $$ = sctp_u16_list_new(); }
| u16_item              { $$ = sctp_u16_list_new();
                          sctp_u16_list_append($$, $1); }
| u16_list ',' u16_item { $$ = $1;
                          sctp_u16_list_append($1, $3); }
;

u16_item
: INTEGER {
	if (!is_valid_u16($1)) {
		semantic_error("Integer value out of range");
	}
	$$ = sctp_u16_list_item_new($1);
}
;

opt_data_flags
: FLAGS '=' ELLIPSIS    { $$ = -1; }
| FLAGS '=' HEX_INTEGER {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
| FLAGS '=' INTEGER     {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
| FLAGS '=' WORD        {
	u64 flags;
	char *c;

	flags = 0;
	for (c = $3; *c != '\0'; c++) {
		switch (*c) {
		case 'I':
			if (flags & SCTP_DATA_CHUNK_I_BIT) {
				semantic_error("I-bit specified multiple times");
			} else {
				flags |= SCTP_DATA_CHUNK_I_BIT;
			}
			break;
		case 'U':
			if (flags & SCTP_DATA_CHUNK_U_BIT) {
				semantic_error("U-bit specified multiple times");
			} else {
				flags |= SCTP_DATA_CHUNK_U_BIT;
			}
			break;
		case 'B':
			if (flags & SCTP_DATA_CHUNK_B_BIT) {
				semantic_error("B-bit specified multiple times");
			} else {
				flags |= SCTP_DATA_CHUNK_B_BIT;
			}
			break;
		case 'E':
			if (flags & SCTP_DATA_CHUNK_E_BIT) {
				semantic_error("E-bit specified multiple times");
			} else {
				flags |= SCTP_DATA_CHUNK_E_BIT;
			}
			break;
		default:
			semantic_error("Only expecting IUBE as flags");
			break;
		}
	}
	$$ = flags;
}
;

opt_abort_flags
: FLAGS '=' ELLIPSIS    { $$ = -1; }
| FLAGS '=' HEX_INTEGER {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
| FLAGS '=' INTEGER     {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
| FLAGS '=' WORD        {
	u64 flags;
	char *c;

	flags = 0;
	for (c = $3; *c != '\0'; c++) {
		switch (*c) {
		case 'T':
			if (flags & SCTP_ABORT_CHUNK_T_BIT) {
				semantic_error("T-bit specified multiple times");
			} else {
				flags |= SCTP_ABORT_CHUNK_T_BIT;
			}
			break;
		default:
			semantic_error("Only expecting T as flags");
			break;
		}
	}
	$$ = flags;
}
;

opt_shutdown_complete_flags
: FLAGS '=' ELLIPSIS    { $$ = -1; }
| FLAGS '=' HEX_INTEGER {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
| FLAGS '=' INTEGER     {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
| FLAGS '=' WORD        {
	u64 flags;
	char *c;

	flags = 0;
	for (c = $3; *c != '\0'; c++) {
		switch (*c) {
		case 'T':
			if (flags & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) {
				semantic_error("T-bit specified multiple times");
			} else {
				flags |= SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT;
			}
			break;
		default:
			semantic_error("Only expecting T as flags");
			break;
		}
	}
	$$ = flags;
}
;

opt_i_data_flags
: FLAGS '=' ELLIPSIS    { $$ = -1; }
| FLAGS '=' HEX_INTEGER {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
| FLAGS '=' INTEGER     {
	if (!is_valid_u8($3)) {
		semantic_error("flags value out of range");
	}
	$$ = $3;
}
| FLAGS '=' WORD        {
	u64 flags;
	char *c;

	flags = 0;
	for (c = $3; *c != '\0'; c++) {
		switch (*c) {
		case 'I':
			if (flags & SCTP_I_DATA_CHUNK_I_BIT) {
				semantic_error("I-bit specified multiple times");
			} else {
				flags |= SCTP_I_DATA_CHUNK_I_BIT;
			}
			break;
		case 'U':
			if (flags & SCTP_I_DATA_CHUNK_U_BIT) {
				semantic_error("U-bit specified multiple times");
			} else {
				flags |= SCTP_I_DATA_CHUNK_U_BIT;
			}
			break;
		case 'B':
			if (flags & SCTP_I_DATA_CHUNK_B_BIT) {
				semantic_error("B-bit specified multiple times");
			} else {
				flags |= SCTP_I_DATA_CHUNK_B_BIT;
			}
			break;
		case 'E':
			if (flags & SCTP_I_DATA_CHUNK_E_BIT) {
				semantic_error("E-bit specified multiple times");
			} else {
				flags |= SCTP_I_DATA_CHUNK_E_BIT;
			}
			break;
		default:
			semantic_error("Only expecting IUBE as flags");
			break;
		}
	}
	$$ = flags;
}
;

opt_tag
: TAG '=' ELLIPSIS { $$ = -1; }
| TAG '=' INTEGER  {
	if (!is_valid_u32($3)) {
		semantic_error("tag value out of range");
	}
	$$ = $3;
}
;

opt_a_rwnd
: A_RWND '=' ELLIPSIS   { $$ = -1; }
| A_RWND '=' INTEGER    {
	if (!is_valid_u32($3)) {
		semantic_error("a_rwnd value out of range");
	}
	$$ = $3;
}
;

opt_os
: OS '=' ELLIPSIS { $$ = -1; }
| OS '=' INTEGER  {
	if (!is_valid_u16($3)) {
		semantic_error("os value out of range");
	}
	$$ = $3;
}
;

opt_is
: IS '=' ELLIPSIS { $$ = -1; }
| IS '=' INTEGER  {
	if (!is_valid_u16($3)) {
		semantic_error("is value out of range");
	}
	$$ = $3;
}
;

opt_tsn
: TSN '=' ELLIPSIS { $$ = -1; }
| TSN '=' INTEGER  {
	if (!is_valid_u32($3)) {
		semantic_error("tsn value out of range");
	}
	$$ = $3;
}
;

opt_sid
: SID '=' ELLIPSIS { $$ = -1; }
| SID '=' INTEGER  {
	if (!is_valid_u16($3)) {
		semantic_error("sid value out of range");
	}
	$$ = $3;
}
;

opt_ssn
: SSN '=' ELLIPSIS { $$ = -1; }
| SSN '=' INTEGER  {
	if (!is_valid_u16($3)) {
		semantic_error("ssn value out of range");
	}
	$$ = $3;
}
;

opt_mid
: MID '=' ELLIPSIS { $$ = -1; }
| MID '=' INTEGER  {
	if (!is_valid_u32($3)) {
		semantic_error("mid value out of range");
	}
	$$ = $3;
}
;

opt_ppid
: PPID '=' ELLIPSIS { $$ = -1; }
| PPID '=' INTEGER  {
	if (!is_valid_u32($3)) {
		semantic_error("ppid value out of range");
	}
	$$ = $3;
}
| PPID '=' HEX_INTEGER  {
	if (!is_valid_u32($3)) {
		semantic_error("ppid value out of range");
	}
	$$ = $3;
}
;

opt_fsn
: FSN '=' ELLIPSIS { $$ = -1; }
| FSN '=' INTEGER  {
	if (!is_valid_u32($3)) {
		semantic_error("fsn value out of range");
	}
	$$ = $3;
}
;

opt_cum_tsn
: CUM_TSN '=' ELLIPSIS { $$ = -1; }
| CUM_TSN '=' INTEGER  {
	if (!is_valid_u32($3)) {
		semantic_error("cum_tsn value out of range");
	}
	$$ = $3;
}
;

opt_gaps
: GAPS '=' ELLIPSIS         { $$ = NULL; }
| GAPS '=' '[' ELLIPSIS ']' { $$ = NULL; }
| GAPS '=' '[' gap_list ']' { $$ = $4; }
;

opt_nr_gaps
: NR_GAPS '=' ELLIPSIS         { $$ = NULL; }
| NR_GAPS '=' '[' ELLIPSIS ']' { $$ = NULL; }
| NR_GAPS '=' '[' gap_list ']' { $$ = $4; }
;

gap_list
:                  { $$ = sctp_sack_block_list_new(); }
| gap              { $$ = sctp_sack_block_list_new();
                     sctp_sack_block_list_append($$, $1); }
| gap_list ',' gap { $$ = $1;
                     sctp_sack_block_list_append($1, $3); }
;

gap
: INTEGER ':' INTEGER {
	if (!is_valid_u16($1)) {
		semantic_error("start value out of range");
	}
	if (!is_valid_u16($3)) {
		semantic_error("end value out of range");
	}
	$$ = sctp_sack_block_list_item_gap_new($1, $3);
}
;

opt_dups
: DUPS '=' ELLIPSIS         { $$ = NULL; }
| DUPS '=' '[' ELLIPSIS ']' { $$ = NULL; }
| DUPS '=' '[' dup_list ']' { $$ = $4; }
;

dup_list
:                  { $$ = sctp_sack_block_list_new(); }
| dup              { $$ = sctp_sack_block_list_new();
                     sctp_sack_block_list_append($$, $1); }
| dup_list ',' dup { $$ = $1;
                     sctp_sack_block_list_append($1, $3); }
;

dup
: INTEGER {
	if (!is_valid_u32($1)) {
		semantic_error("tsn value out of range");
	}
	$$ = sctp_sack_block_list_item_dup_new($1);
}
;

opt_stream_identifier
: IDS '=' ELLIPSIS         { $$ = NULL; }
| IDS '=' '[' ELLIPSIS ']' { $$ = NULL; }
| IDS '=' '[' ids_list ']' { $$ = $4; }
;

ids_list
:                  { $$ = sctp_forward_tsn_ids_list_new(); }
| id              { $$ =sctp_forward_tsn_ids_list_new();
                     sctp_forward_tsn_ids_list_append($$, $1); }
| ids_list ',' id { $$ = $1;
                     sctp_forward_tsn_ids_list_append($1, $3); }
;

id
: '{' INTEGER ',' INTEGER '}' {
	if (!is_valid_u16($2)) {
		semantic_error("stream identifier out of range");
	}
	if (!is_valid_u16($4)) {
		semantic_error("stream sequence number out of range");
	}
	$$ = sctp_forward_tsn_ids_list_item_new($2, $4);
}
;

opt_i_forward_tsn_stream_identifier
: IDS '=' ELLIPSIS         { $$ = NULL; }
| IDS '=' '[' ELLIPSIS ']' { $$ = NULL; }
| IDS '=' '[' i_forward_tsn_ids_list ']' { $$ = $4; }
;

i_forward_tsn_ids_list
:                  { $$ = sctp_i_forward_tsn_ids_list_new(); }
| i_forward_tsn_id { $$ =sctp_i_forward_tsn_ids_list_new();
                     sctp_i_forward_tsn_ids_list_append($$, $1); }
| i_forward_tsn_ids_list ',' i_forward_tsn_id { $$ = $1;
                     sctp_i_forward_tsn_ids_list_append($1, $3); }
;

i_forward_tsn_id
: '{' INTEGER ',' INTEGER ',' INTEGER '}' {
	if (!is_valid_u16($2)) {
		semantic_error("stream identifier out of range");
	}
	if (!is_valid_u16($4)) {
		semantic_error("reserved out of range");
	}
	if (!is_valid_u32($6)) {
		semantic_error("message identifier number out of range");
	}
	$$ = sctp_i_forward_tsn_ids_list_item_new($2, $4, $6);
}
;

sctp_generic_chunk_spec
: CHUNK '[' opt_chunk_type ',' opt_flags ',' opt_len ',' opt_val ']' {
	if (($7 != -1) &&
	    (!is_valid_u16($7) || ($7 < sizeof(struct sctp_chunk)))) {
		semantic_error("length value out of range");
	}
	if (($7 != -1) && ($9 != NULL) &&
	    ($7 < sizeof(struct sctp_chunk) + $9->nr_entries)) {
		semantic_error("length value incompatible with val");
	}
	if (($7 == -1) && ($9 != NULL)) {
		semantic_error("length needs to be specified");
	}
	$$ = sctp_generic_chunk_new($3, $5, $7, $9);
}

sctp_data_chunk_spec
: DATA '[' opt_data_flags ',' opt_len ',' opt_tsn ',' opt_sid ',' opt_ssn ',' opt_ppid ']' {
	if (($5 != -1) &&
	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_data_chunk)))) {
		semantic_error("length value out of range");
	}
	$$ = sctp_data_chunk_new($3, $5, $7, $9, $11, $13);
}

sctp_init_chunk_spec
: INIT '[' opt_flags ',' opt_tag ',' opt_a_rwnd ',' opt_os ',' opt_is ',' opt_tsn opt_parameter_list_spec ']' {
	$$ = sctp_init_chunk_new($3, $5, $7, $9, $11, $13, $14);
}

sctp_init_ack_chunk_spec
: INIT_ACK '[' opt_flags ',' opt_tag ',' opt_a_rwnd ',' opt_os ',' opt_is ',' opt_tsn opt_parameter_list_spec ']' {
	$$ = sctp_init_ack_chunk_new($3, $5, $7, $9, $11, $13, $14);
}

sctp_sack_chunk_spec
: SACK '[' opt_flags ',' opt_cum_tsn ',' opt_a_rwnd ',' opt_gaps ',' opt_dups']' {
	$$ = sctp_sack_chunk_new($3, $5, $7, $9, $11);
}

sctp_nr_sack_chunk_spec
: NR_SACK '[' opt_flags ',' opt_cum_tsn ',' opt_a_rwnd ',' opt_gaps ',' opt_nr_gaps ',' opt_dups']' {
	$$ = sctp_nr_sack_chunk_new($3, $5, $7, $9, $11, $13);
}


sctp_heartbeat_chunk_spec
: HEARTBEAT '[' opt_flags ',' sctp_heartbeat_information_parameter_spec ']' {
	$$ = sctp_heartbeat_chunk_new($3, $5);
}

sctp_heartbeat_ack_chunk_spec
: HEARTBEAT_ACK '[' opt_flags ',' sctp_heartbeat_information_parameter_spec ']' {
	$$ = sctp_heartbeat_ack_chunk_new($3, $5);
}

sctp_abort_chunk_spec
: ABORT '[' opt_abort_flags opt_cause_list_spec ']' {
	$$ = sctp_abort_chunk_new($3, $4);
}

sctp_shutdown_chunk_spec
: SHUTDOWN '[' opt_flags ',' opt_cum_tsn ']' {
	$$ = sctp_shutdown_chunk_new($3, $5);
}

sctp_shutdown_ack_chunk_spec
: SHUTDOWN_ACK '[' opt_flags ']' {
	$$ = sctp_shutdown_ack_chunk_new($3);
}

sctp_error_chunk_spec
: ERROR '[' opt_flags opt_cause_list_spec ']' {
	$$ = sctp_error_chunk_new($3, $4);
}

sctp_cookie_echo_chunk_spec
: COOKIE_ECHO '[' opt_flags ',' opt_len ',' opt_val ']' {
	if (($5 != -1) &&
	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_cookie_echo_chunk)))) {
		semantic_error("length value out of range");
	}
	if (($5 != -1) && ($7 != NULL) &&
	    ($5 != sizeof(struct sctp_cookie_echo_chunk) + $7->nr_entries)) {
		semantic_error("length value incompatible with val");
	}
	if (($5 == -1) && ($7 != NULL)) {
		semantic_error("length needs to be specified");
	}
	$$ = sctp_cookie_echo_chunk_new($3, $5, $7);
}

sctp_cookie_ack_chunk_spec
: COOKIE_ACK '[' opt_flags ']' {
	$$ = sctp_cookie_ack_chunk_new($3);
}

sctp_ecne_chunk_spec
: ECNE '[' opt_flags ',' opt_tsn ']' {
	$$ = sctp_ecne_chunk_new($3, $5);
}

sctp_cwr_chunk_spec
: CWR '[' opt_flags ',' opt_tsn ']' {
	$$ = sctp_cwr_chunk_new($3, $5);
}

sctp_shutdown_complete_chunk_spec
: SHUTDOWN_COMPLETE '[' opt_shutdown_complete_flags ']' {
	$$ = sctp_shutdown_complete_chunk_new($3);
}

sctp_i_data_chunk_spec
: I_DATA '[' opt_i_data_flags ',' opt_len ',' opt_tsn ',' opt_sid ',' opt_mid ',' opt_ppid ']' {
	if (($5 != -1) &&
	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_i_data_chunk)))) {
		semantic_error("length value out of range");
	}
	$$ = sctp_i_data_chunk_new($3, $5, $7, $9, 0, $11, $13, -1);
}
| I_DATA '[' opt_i_data_flags ',' opt_len ',' opt_tsn ',' opt_sid ',' opt_mid ',' opt_fsn ']' {
	if (($5 != -1) &&
	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_i_data_chunk)))) {
		semantic_error("length value out of range");
	}
	$$ = sctp_i_data_chunk_new($3, $5, $7, $9, 0, $11, -1, $13);
}

sctp_pad_chunk_spec
: PAD '[' opt_flags ',' opt_len ',' VAL '=' ELLIPSIS ']' {
	if (($5 != -1) &&
	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_pad_chunk)))) {
		semantic_error("length value out of range");
	}
	$$ = sctp_pad_chunk_new($3, $5, NULL);
}

sctp_forward_tsn_spec
: FORWARD_TSN '[' opt_cum_tsn ',' opt_stream_identifier']' {
    $$ = sctp_forward_tsn_chunk_new($3, $5);
}

sctp_i_forward_tsn_spec
: I_FORWARD_TSN '[' opt_cum_tsn ',' opt_i_forward_tsn_stream_identifier']' {
    $$ = sctp_i_forward_tsn_chunk_new($3, $5);
}

opt_req_sn
: REQ_SN '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("req_sn out of range");
	}
	$$ = $3;
}
| REQ_SN '=' ELLIPSIS { $$ = -1; }
;

opt_resp_sn
: RESP_SN '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("resp_sn out of range");
	}
	$$ = $3;
}
| RESP_SN '=' ELLIPSIS { $$ = -1; }
;

opt_last_tsn
: LAST_TSN '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("last_tsn out of range");
	}
	$$ = $3;
}
| LAST_TSN '=' ELLIPSIS { $$ = -1; }
;

opt_result
: RESULT '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("result out of range");
	}
	$$ = $3;
}
| RESULT '=' ELLIPSIS { $$ = -1; }
;

opt_sender_next_tsn
: SENDER_NEXT_TSN '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sender_next_tsn out of range");
	}
	$$ = $3;
}
| SENDER_NEXT_TSN '=' HEX_INTEGER { 
	if (!is_valid_u32($3)) {
		semantic_error("sender_next_tsn out of range");
	}
	$$ = $3;
}
| SENDER_NEXT_TSN '=' ELLIPSIS { $$ = -1; }
;

opt_receiver_next_tsn
: RECEIVER_NEXT_TSN '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("receiver_next_tsn out of range");
	}
	$$ = $3;
}
| RECEIVER_NEXT_TSN '=' HEX_INTEGER { 
	if (!is_valid_u32($3)) {
		semantic_error("receiver_next_tsn out of range");
	}
	$$ = $3;
}
| RECEIVER_NEXT_TSN '=' ELLIPSIS { $$ = -1; }
;

opt_number_of_new_streams
: NUMBER_OF_NEW_STREAMS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("number_of_new_streams out of range");
	}
	$$ = $3;
}
| NUMBER_OF_NEW_STREAMS '=' ELLIPSIS { $$ = -1; }
;

outgoing_ssn_reset_request
: OUTGOING_SSN_RESET '[' opt_req_sn ',' opt_resp_sn ',' opt_last_tsn ']' {
	$$ = sctp_outgoing_ssn_reset_request_parameter_new($3, $5, $7, NULL);
}
| OUTGOING_SSN_RESET '[' opt_req_sn ',' opt_resp_sn ',' opt_last_tsn ',' SIDS '=' '[' u16_list ']' ']' {
	$$ = sctp_outgoing_ssn_reset_request_parameter_new($3, $5, $7, $12);
}
;

incoming_ssn_reset_request
: INCOMING_SSN_RESET '[' opt_req_sn ']' {
	$$ = sctp_incoming_ssn_reset_request_parameter_new($3, NULL);
}
| INCOMING_SSN_RESET '[' opt_req_sn ',' SIDS '=' '[' u16_list ']' ']' {
	$$ = sctp_incoming_ssn_reset_request_parameter_new($3, $8);
}
;

ssn_tsn_reset_request
: SSN_TSN_RESET '[' opt_req_sn ']' {
	$$ = sctp_ssn_tsn_reset_request_parameter_new($3);
}
;

reconfig_response
: RECONFIG_RESPONSE '[' opt_resp_sn ',' opt_result ']' {
	$$ = sctp_reconfig_response_parameter_new($3, $5, -2, -2);
}
| RECONFIG_RESPONSE '[' opt_resp_sn ',' opt_result ',' opt_sender_next_tsn ',' opt_receiver_next_tsn']' {
	$$ = sctp_reconfig_response_parameter_new($3, $5, $7, $9);
}
;

add_outgoing_streams_request
: ADD_OUTGOING_STREAMS '[' opt_req_sn ',' opt_number_of_new_streams ']' {
	$$ = sctp_add_outgoing_streams_request_parameter_new($3, $5);
}
;

add_incoming_streams_request
: ADD_INCOMING_STREAMS '[' opt_req_sn ',' opt_number_of_new_streams ']' {
	$$ = sctp_add_incoming_streams_request_parameter_new($3, $5);
}
;

generic_reconfig_request
: RECONFIG_REQUEST_GENERIC '[' opt_parameter_type ',' opt_len ',' opt_req_sn ',' opt_val ']' {
	$$ = sctp_generic_reconfig_request_parameter_new($3, $5, $7, $9);
}
;

sctp_reconfig_chunk_spec
: RECONFIG '[' opt_flags  opt_parameter_list_spec ']' {
	$$ = sctp_reconfig_chunk_new($3, $4);
}
;

opt_parameter_list_spec
: ',' ELLIPSIS                 { $$ = NULL; }
|                              { $$ = sctp_parameter_list_new(); }
| ',' sctp_parameter_list_spec { $$ = $2; }
;

sctp_parameter_list_spec
: sctp_parameter_spec                              { $$ = sctp_parameter_list_new();
                                                     sctp_parameter_list_append($$, $1); }
| sctp_parameter_list_spec ',' sctp_parameter_spec { $$ = $1;
                                                     sctp_parameter_list_append($1, $3); }
;

sctp_parameter_spec
: sctp_generic_parameter_spec                 { $$ = $1; }
| sctp_heartbeat_information_parameter_spec   { $$ = $1; }
| sctp_ipv4_address_parameter_spec            { $$ = $1; }
| sctp_ipv6_address_parameter_spec            { $$ = $1; }
| sctp_state_cookie_parameter_spec            { $$ = $1; }
| sctp_unrecognized_parameter_parameter_spec  { $$ = $1; }
| sctp_cookie_preservative_parameter_spec     { $$ = $1; }
| sctp_hostname_address_parameter_spec        { $$ = $1; }
| sctp_supported_address_types_parameter_spec { $$ = $1; }
| sctp_ecn_capable_parameter_spec             { $$ = $1; }
| sctp_fornward_tsn_supported_spec            { $$ = $1; }
| sctp_supported_extensions_parameter_spec    { $$ = $1; }
| sctp_adaptation_indication_parameter_spec   { $$ = $1; }
| sctp_pad_parameter_spec                     { $$ = $1; }
| outgoing_ssn_reset_request                  { $$ = $1; }
| incoming_ssn_reset_request                  { $$ = $1; }
| ssn_tsn_reset_request                       { $$ = $1; }
| reconfig_response                           { $$ = $1; }
| add_outgoing_streams_request                { $$ = $1; }
| add_incoming_streams_request                { $$ = $1; }
| generic_reconfig_request                    { $$ = $1; }
;

opt_parameter_type
: TYPE '=' ELLIPSIS    { $$ = -1; }
| TYPE '=' HEX_INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("type value out of range");
	}
	$$ = $3;
}
| TYPE '=' INTEGER     {
	if (!is_valid_u16($3)) {
		semantic_error("type value out of range");
	}
	$$ = $3;
}
;

sctp_generic_parameter_spec
: PARAMETER '[' opt_parameter_type ',' opt_len ',' opt_val ']' {
	if (($5 != -1) &&
	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_parameter)))) {
		semantic_error("length value out of range");
	}
	if (($5 != -1) && ($7 != NULL) &&
	    ($5 != sizeof(struct sctp_parameter) + $7->nr_entries)) {
		semantic_error("length value incompatible with val");
	}
	if (($5 == -1) && ($7 != NULL)) {
		semantic_error("length needs to be specified");
	}
	$$ = sctp_generic_parameter_new($3, $5, $7);
}

sctp_heartbeat_information_parameter_spec
: HEARTBEAT_INFORMATION '[' ELLIPSIS ']' {
	$$ = sctp_heartbeat_information_parameter_new(-1, NULL);
}
| HEARTBEAT_INFORMATION '[' opt_len ',' opt_val ']' {
	if (($3 != -1) &&
	    (!is_valid_u16($3) || ($3 < sizeof(struct sctp_heartbeat_information_parameter)))) {
		semantic_error("length value out of range");
	}
	if (($3 != -1) && ($5 != NULL) &&
	    ($3 != sizeof(struct sctp_heartbeat_information_parameter) + $5->nr_entries)) {
		semantic_error("length value incompatible with val");
	}
	if (($3 == -1) && ($5 != NULL)) {
		semantic_error("length needs to be specified");
	}
	$$ = sctp_heartbeat_information_parameter_new($3, $5);
}

sctp_ipv4_address_parameter_spec
: IPV4_ADDRESS '[' ADDR '=' IPV4_ADDR ']' {
	struct in_addr addr;

	if (inet_pton(AF_INET, $5, &addr) != 1) {
		semantic_error("Invalid address");
	}
	$$ = sctp_ipv4_address_parameter_new(&addr);
}
| IPV4_ADDRESS '[' ADDR '=' ELLIPSIS ']' {
	$$ = sctp_ipv4_address_parameter_new(NULL);
}

sctp_ipv6_address_parameter_spec
: IPV6_ADDRESS '[' ADDR '=' IPV6_ADDR ']' {
	struct in6_addr addr;

	if (inet_pton(AF_INET6, $5, &addr) != 1) {
		semantic_error("Invalid address");
	}
	$$ = sctp_ipv6_address_parameter_new(&addr);
}
| IPV6_ADDRESS '[' ADDR '=' ELLIPSIS ']' {
	$$ = sctp_ipv6_address_parameter_new(NULL);
}

sctp_state_cookie_parameter_spec
: STATE_COOKIE '[' ELLIPSIS ']' {
	$$ = sctp_state_cookie_parameter_new(-1, NULL);
}
| STATE_COOKIE '[' LEN '=' ELLIPSIS ',' VAL '=' ELLIPSIS ']' {
	$$ = sctp_state_cookie_parameter_new(-1, NULL);
}
| STATE_COOKIE '[' LEN '=' INTEGER ',' VAL '=' ELLIPSIS ']' {
	if (($5 < sizeof(struct sctp_state_cookie_parameter)) ||
	    !is_valid_u32($5)) {
		semantic_error("len value out of range");
	}
	$$ = sctp_state_cookie_parameter_new($5, NULL);
}

sctp_unrecognized_parameter_parameter_spec
: UNRECOGNIZED_PARAMETER '[' PARAMS '=' ELLIPSIS ']' {
	$$ = sctp_unrecognized_parameters_parameter_new(NULL);
}
| UNRECOGNIZED_PARAMETER '[' PARAMS '=' '[' sctp_parameter_list_spec ']' ']' {
	$$ = sctp_unrecognized_parameters_parameter_new($6);
}

sctp_cookie_preservative_parameter_spec
: COOKIE_PRESERVATIVE '[' INCR '=' INTEGER ']' {
	if (!is_valid_u32($5)) {
		semantic_error("increment value out of range");
	}
	$$ = sctp_cookie_preservative_parameter_new($5);
}
| COOKIE_PRESERVATIVE '[' INCR '=' ELLIPSIS ']' {
	$$ = sctp_cookie_preservative_parameter_new(-1);
}

sctp_hostname_address_parameter_spec
: HOSTNAME_ADDRESS '[' ADDR '=' STRING ']' {
	$$ = sctp_hostname_address_parameter_new($5);
}
| HOSTNAME_ADDRESS '[' ADDR '=' ELLIPSIS ']' {
	$$ = sctp_hostname_address_parameter_new(NULL);
}

address_types_list
:                                     { $$ = sctp_address_type_list_new(); }
| address_type                        { $$ = sctp_address_type_list_new();
                                        sctp_address_type_list_append($$, $1); }
| address_types_list ',' address_type { $$ = $1;
                                        sctp_address_type_list_append($1, $3); }
;

address_type
: INTEGER       { if (!is_valid_u16($1)) {
                  semantic_error("address type value out of range");
                  }
                  $$ = sctp_address_type_list_item_new($1); }
| IPV4_TYPE     { $$ = sctp_address_type_list_item_new(SCTP_IPV4_ADDRESS_PARAMETER_TYPE); }
| IPV6_TYPE     { $$ = sctp_address_type_list_item_new(SCTP_IPV6_ADDRESS_PARAMETER_TYPE); }
| HOSTNAME_TYPE { $$ = sctp_address_type_list_item_new(SCTP_HOSTNAME_ADDRESS_PARAMETER_TYPE); }
;

sctp_supported_address_types_parameter_spec
: SUPPORTED_ADDRESS_TYPES '[' TYPES '=' ELLIPSIS ']' {
	$$ = sctp_supported_address_types_parameter_new(NULL);
}
| SUPPORTED_ADDRESS_TYPES '[' TYPES '=' '[' address_types_list ']' ']' {
	$$ = sctp_supported_address_types_parameter_new($6);
}


sctp_ecn_capable_parameter_spec
: ECN_CAPABLE '[' ']' {
	$$ = sctp_ecn_capable_parameter_new();
}

sctp_fornward_tsn_supported_spec
: FORWARD_TSN_SUPPORTED '[' ']' {
	$$ = sctp_forward_tsn_supported_parameter_new();
}

chunk_types_list
: {
	$$ = sctp_byte_list_new();
}
| chunk_type {
	$$ = sctp_byte_list_new();
	sctp_byte_list_append($$, sctp_byte_list_item_new($1));
}
| chunk_types_list ',' chunk_type {
	$$ = $1;
	sctp_byte_list_append($1, sctp_byte_list_item_new($3));
}
;

sctp_adaptation_indication_parameter_spec
: ADAPTATION_INDICATION '[' ADAPTATION_CODE_POINT '=' INTEGER ']' {
	if (!is_valid_u32($5))
		semantic_error("adaptation_indication_code ot of range");
	$$ = sctp_adaptation_indication_parameter_new($5);
};

sctp_supported_extensions_parameter_spec
: SUPPORTED_EXTENSIONS '[' TYPES '=' ELLIPSIS ']' {
	$$ = sctp_supported_extensions_parameter_new(NULL);
}
| SUPPORTED_EXTENSIONS '[' TYPES '=' '[' chunk_types_list ']' ']' {
	$$ = sctp_supported_extensions_parameter_new($6);
}

sctp_pad_parameter_spec
: PAD '[' ELLIPSIS ']' {
	$$ = sctp_pad_parameter_new(-1, NULL);
}
| PAD '[' LEN '=' ELLIPSIS ',' VAL '=' ELLIPSIS ']' {
	$$ = sctp_pad_parameter_new(-1, NULL);
}
| PAD '[' LEN '=' INTEGER ',' VAL '=' ELLIPSIS ']' {
	if (($5 < sizeof(struct sctp_pad_parameter)) ||
	    !is_valid_u32($5)) {
		semantic_error("len value out of range");
	}
	$$ = sctp_pad_parameter_new($5, NULL);
}

opt_cause_list_spec
: ',' ELLIPSIS             { $$ = NULL; }
|                          { $$ = sctp_cause_list_new(); }
| ',' sctp_cause_list_spec { $$ = $2; }
;

sctp_cause_list_spec
: sctp_cause_spec                          { $$ = sctp_cause_list_new();
                                             sctp_cause_list_append($$, $1); }
| sctp_cause_list_spec ',' sctp_cause_spec { $$ = $1;
                                             sctp_cause_list_append($1, $3); }
;

sctp_cause_spec
: sctp_generic_cause_spec                        { $$ = $1; }
| sctp_invalid_stream_identifier_cause_spec      { $$ = $1; }
| sctp_missing_mandatory_parameter_cause_spec    { $$ = $1; }
| sctp_stale_cookie_error_cause_spec             { $$ = $1; }
| sctp_out_of_resources_cause_spec               { $$ = $1; }
| sctp_unresolvable_address_cause_spec           { $$ = $1; }
| sctp_unrecognized_chunk_type_cause_spec        { $$ = $1; }
| sctp_invalid_mandatory_parameter_cause_spec    { $$ = $1; }
| sctp_unrecognized_parameters_cause_spec        { $$ = $1; }
| sctp_no_user_data_cause_spec                   { $$ = $1; }
| sctp_cookie_received_while_shutdown_cause_spec { $$ = $1; }
| sctp_restart_with_new_addresses_cause_spec     { $$ = $1; }
| sctp_user_initiated_abort_cause_spec           { $$ = $1; }
| sctp_protocol_violation_cause_spec             { $$ = $1; }
;

opt_cause_code
: CAUSE_CODE '=' ELLIPSIS    { $$ = -1; }
| CAUSE_CODE '=' HEX_INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("cause value out of range");
	}
	$$ = $3;
}
| CAUSE_CODE '=' INTEGER     {
	if (!is_valid_u16($3)) {
		semantic_error("cause value out of range");
	}
	$$ = $3;
}
;

sctp_generic_cause_spec
: CAUSE '[' opt_cause_code ',' opt_len ',' opt_info ']' {
	if (($5 != -1) &&
	    (!is_valid_u16($5) || ($5 < sizeof(struct sctp_cause)))) {
		semantic_error("length value out of range");
	}
	if (($5 != -1) && ($7 != NULL) &&
	    ($5 != sizeof(struct sctp_cause) + $7->nr_entries)) {
		semantic_error("length value incompatible with val");
	}
	if (($5 == -1) && ($7 != NULL)) {
		semantic_error("length needs to be specified");
	}
	$$ = sctp_generic_cause_new($3, $5, $7);
}

sctp_invalid_stream_identifier_cause_spec
: INVALID_STREAM_IDENTIFIER '[' SID '=' INTEGER ']' {
	if (!is_valid_u16($5)) {
		semantic_error("stream identifier out of range");
	}
	$$ = sctp_invalid_stream_identifier_cause_new($5);
}
| INVALID_STREAM_IDENTIFIER '[' SID '=' ELLIPSIS ']' {
	$$ = sctp_invalid_stream_identifier_cause_new(-1);
}

parameter_types_list
:                                         { $$ = sctp_parameter_type_list_new(); }
| parameter_type                          { $$ = sctp_parameter_type_list_new();
                                            sctp_parameter_type_list_append($$, $1); }
| parameter_types_list ',' parameter_type { $$ = $1;
                                            sctp_parameter_type_list_append($1, $3); }
;

parameter_type
: INTEGER       { if (!is_valid_u16($1)) {
                  semantic_error("parameter type value out of range");
                  }
                  $$ = sctp_parameter_type_list_item_new($1); }
;

sctp_missing_mandatory_parameter_cause_spec
: MISSING_MANDATORY_PARAMETER '[' TYPES '=' ELLIPSIS ']' {
	$$ = sctp_missing_mandatory_parameter_cause_new(NULL);
}
| MISSING_MANDATORY_PARAMETER '[' TYPES '=' '[' parameter_types_list ']' ']' {
	$$ = sctp_missing_mandatory_parameter_cause_new($6);
}

sctp_stale_cookie_error_cause_spec
: STALE_COOKIE_ERROR '[' STALENESS '=' INTEGER ']' {
	if (!is_valid_u32($5)) {
		semantic_error("staleness out of range");
	}
	$$ = sctp_stale_cookie_error_cause_new($5);
}
| STALE_COOKIE_ERROR '[' STALENESS '=' ELLIPSIS ']' {
	$$ = sctp_stale_cookie_error_cause_new(-1);
}

sctp_out_of_resources_cause_spec
: OUT_OF_RESOURCE '[' ']' {
	$$ = sctp_out_of_resources_cause_new();
}

sctp_unresolvable_address_cause_spec
: UNRESOLVABLE_ADDRESS '[' PARAM '=' sctp_parameter_spec ']' {
	$$ = sctp_unresolvable_address_cause_new($5);
}
| UNRESOLVABLE_ADDRESS '[' PARAM '=' ELLIPSIS ']' {
	$$ = sctp_unresolvable_address_cause_new(NULL);
}

sctp_unrecognized_chunk_type_cause_spec
: UNRECOGNIZED_CHUNK_TYPE '[' CHK '=' sctp_chunk_spec ']' {
	$$ = sctp_unrecognized_chunk_type_cause_new($5);
}
| UNRECOGNIZED_CHUNK_TYPE '[' CHK '=' ELLIPSIS ']' {
	$$ = sctp_unrecognized_chunk_type_cause_new(NULL);
}

sctp_invalid_mandatory_parameter_cause_spec
: INVALID_MANDATORY_PARAMETER '[' ']' {
	$$ = sctp_invalid_mandatory_parameter_cause_new();
}

sctp_unrecognized_parameters_cause_spec
: UNRECOGNIZED_PARAMETERS '[' PARAMS '=' '[' sctp_parameter_list_spec ']' ']' {
	$$ = sctp_unrecognized_parameters_cause_new($6);
}
| UNRECOGNIZED_PARAMETERS '[' PARAMS '=' ELLIPSIS ']' {
	$$ = sctp_unrecognized_parameters_cause_new(NULL);
}

sctp_no_user_data_cause_spec
: NO_USER_DATA '[' TSN '=' INTEGER ']' {
	if (!is_valid_u32($5)) {
		semantic_error("tsn out of range");
	}
	$$ = sctp_no_user_data_cause_new($5);
}
| NO_USER_DATA '[' TSN '=' ELLIPSIS ']' {
	$$ = sctp_no_user_data_cause_new(-1);
}

sctp_cookie_received_while_shutdown_cause_spec
: COOKIE_RECEIVED_WHILE_SHUTDOWN '[' ']' {
	$$ = sctp_cookie_received_while_shutdown_cause_new();
}

sctp_restart_with_new_addresses_cause_spec
: RESTART_WITH_NEW_ADDRESSES '[' PARAMS '=' '[' sctp_parameter_list_spec ']' ']' {
	$$ = sctp_restart_with_new_addresses_cause_new($6);
}
| RESTART_WITH_NEW_ADDRESSES '[' PARAMS '=' ELLIPSIS ']' {
	$$ = sctp_restart_with_new_addresses_cause_new(NULL);
}

sctp_user_initiated_abort_cause_spec
: USER_INITIATED_ABORT '[' CAUSE_INFO '=' STRING ']' {
	$$ = sctp_user_initiated_abort_cause_new($5);
}
| USER_INITIATED_ABORT '[' CAUSE_INFO '=' ELLIPSIS ']' {
	$$ = sctp_user_initiated_abort_cause_new(NULL);
}

sctp_protocol_violation_cause_spec
: PROTOCOL_VIOLATION '[' CAUSE_INFO '=' STRING ']' {
	$$ = sctp_protocol_violation_cause_new($5);
}
| PROTOCOL_VIOLATION '[' CAUSE_INFO '=' ELLIPSIS ']' {
	$$ = sctp_protocol_violation_cause_new(NULL);
}

tcp_packet_spec
: packet_prefix opt_ip_info flags seq opt_ack opt_window opt_tcp_options opt_udp_encaps_info {
	char *error = NULL;
	struct packet *outer = $1, *inner = NULL;
	enum direction_t direction = outer->direction;

	if (($7 == NULL) && (direction != DIRECTION_OUTBOUND)) {
		yylineno = @7.first_line;
		semantic_error("<...> for TCP options can only be used with "
			       "outbound packets");
	}

	inner = new_tcp_packet(in_config->wire_protocol,
			       direction, $2, $3,
			       $4.start_sequence, $4.payload_bytes,
			       $5, $6, $7,
			       ignore_ts_val,
			       absolute_ts_ecr,
			       $4.absolute,
			       $4.ignore,
			       $8.udp_src_port, $8.udp_dst_port,
			       &error);
	ignore_ts_val = false;
	absolute_ts_ecr = false;
	free($3);
	free($7);
	if (inner == NULL) {
		assert(error != NULL);
		semantic_error(error);
		free(error);
	}

	$$ = packet_encapsulate_and_free(outer, inner);
}
;

udp_packet_spec
: packet_prefix UDP '(' INTEGER ')' {
	char *error = NULL;
	struct packet *outer = $1, *inner = NULL;
	enum direction_t direction = outer->direction;

	if (!is_valid_u16($4)) {
		semantic_error("UDP payload size out of range");
	}

	inner = new_udp_packet(in_config->wire_protocol, direction, $4, &error);
	if (inner == NULL) {
		assert(error != NULL);
		semantic_error(error);
		free(error);
	}

	$$ = packet_encapsulate_and_free(outer, inner);
}
;

udplite_packet_spec
: packet_prefix UDPLITE '(' INTEGER ',' INTEGER ')' {
	char *error = NULL;
	struct packet *outer = $1, *inner = NULL;
	enum direction_t direction = outer->direction;

	if (!is_valid_u16($4)) {
		semantic_error("UDPLite payload size out of range");
	}
	if (!is_valid_u16($6)) {
		semantic_error("UDPLite checksum coverage out of range");
	}

	inner = new_udplite_packet(in_config->wire_protocol, direction, $4, $6,
				   &error);
	if (inner == NULL) {
		assert(error != NULL);
		semantic_error(error);
		free(error);
	}

	$$ = packet_encapsulate_and_free(outer, inner);
}
;

icmp_packet_spec
: packet_prefix opt_icmp_echoed ICMP icmp_type opt_icmp_code opt_icmp_mtu {
	char *error = NULL;
	struct packet *outer = $1, *inner = NULL;
	enum direction_t direction = outer->direction;

	inner = new_icmp_packet(in_config->wire_protocol, direction, $4, $5,
				$2.protocol, $2.payload_bytes,
				$2.start_sequence, $2.checksum_coverage,
				$2.verification_tag, $6,
				$2.udp_src_port, $2.udp_dst_port, &error);
	free($4);
	free($5);
	if (inner == NULL) {
		semantic_error(error);
		free(error);
	}

	$$ = packet_encapsulate_and_free(outer, inner);
}
;


packet_prefix
: direction {
	$$ = packet_new(PACKET_MAX_HEADER_BYTES);
	$$->direction = $1;
}
| packet_prefix IPV4 IPV4_ADDR '>' IPV4_ADDR ':' {
	char *error = NULL;
	struct packet *packet = $1;
	char *ip_src = $3;
	char *ip_dst = $5;
	if (ipv4_header_append(packet, ip_src, ip_dst, &error))
		semantic_error(error);
	free(ip_src);
	free(ip_dst);
	$$ = packet;
}
| packet_prefix IPV6 IPV6_ADDR '>' IPV6_ADDR ':' {
	char *error = NULL;
	struct packet *packet = $1;
	char *ip_src = $3;
	char *ip_dst = $5;
	if (ipv6_header_append(packet, ip_src, ip_dst, &error))
		semantic_error(error);
	free(ip_src);
	free(ip_dst);
	$$ = packet;
}
| packet_prefix GRE ':' {
	char *error = NULL;
	struct packet *packet = $1;
	if (gre_header_append(packet, &error))
		semantic_error(error);
	$$ = packet;
}
| packet_prefix MPLS mpls_stack ':' {
	char *error = NULL;
	struct packet *packet = $1;
	struct mpls_stack *mpls_stack = $3;

	if (mpls_header_append(packet, mpls_stack, &error))
		semantic_error(error);
	free(mpls_stack);
	$$ = packet;
}
;

mpls_stack
:				{
	$$ = mpls_stack_new();
}
| mpls_stack mpls_stack_entry	{
	if (mpls_stack_append($1, $2))
		semantic_error("too many MPLS labels");
	$$ = $1;
}
;

mpls_stack_entry
:
'(' LABEL INTEGER ',' TC INTEGER ',' opt_mpls_stack_bottom TTL INTEGER ')' {
	char *error = NULL;
	s64 label = $3;
	s64 traffic_class = $6;
	bool is_stack_bottom = $8;
	s64 ttl = $10;
	struct mpls mpls;

	if (new_mpls_stack_entry(label, traffic_class, is_stack_bottom, ttl,
				 &mpls, &error))
		semantic_error(error);
	$$ = mpls;
}
;

opt_mpls_stack_bottom
:			{ $$ = 0; }
| '[' WORD ']' ','	{
	if (strcmp($2, "S") != 0)
		semantic_error("expected [S] for MPLS label stack bottom");
	free($2);
	$$ = 1;
}
;

icmp_type
: WORD		{ $$ = $1; }
;

opt_icmp_code
:		{ $$ = NULL; }
| WORD		{ $$ = $1; }
;

/* This specifies the relevant details about the packet echoed by ICMP. */
opt_icmp_echoed
:			{
	$$.protocol		= IPPROTO_TCP;
	$$.payload_bytes	= 0;
	$$.start_sequence	= 0;
	$$.udp_src_port		= 0;
	$$.udp_dst_port		= 0;
}
| '[' SCTP '(' INTEGER ')' opt_udp_encaps_info ']'	{
	$$.protocol		= IPPROTO_SCTP;
	$$.payload_bytes	= 0;
	$$.verification_tag	= $4;
	$$.udp_src_port		= $6.udp_src_port;
	$$.udp_dst_port		= $6.udp_dst_port;
}
| '[' UDP '(' INTEGER ')' ']'	{
	$$.protocol		= IPPROTO_UDP;
	$$.payload_bytes	= $4;
	$$.start_sequence	= 0;
	$$.udp_src_port		= 0;
	$$.udp_dst_port		= 0;
}
| '[' UDPLITE '(' INTEGER ',' INTEGER ')' ']'	{
	$$.protocol		= IPPROTO_UDPLITE;
	$$.payload_bytes	= $4;
	$$.checksum_coverage	= $6;
	$$.udp_src_port		= 0;
	$$.udp_dst_port		= 0;
}
| '[' seq opt_udp_encaps_info ']'	{
	$$.protocol		= IPPROTO_TCP;
	$$.payload_bytes	= $2.payload_bytes;
	$$.start_sequence	= $2.start_sequence;
	$$.udp_src_port		= $3.udp_src_port;
	$$.udp_dst_port		= $3.udp_dst_port;
}
;

opt_icmp_mtu
:		{ $$ = -1; }
| MTU INTEGER	{ $$ = $2; }
;

direction
: '<'          { $$ = DIRECTION_INBOUND;  current_script_line = yylineno; }
| '>'          { $$ = DIRECTION_OUTBOUND; current_script_line = yylineno; }
;

opt_ip_info
:			{ $$ = ECN_NOCHECK; }
| '[' ip_ecn ']'	{ $$ = $2; }
;

ip_ecn
: NO_ECN	{ $$ = ECN_NONE; }
| ECT0		{ $$ = ECN_ECT0; }
| ECT1		{ $$ = ECN_ECT1; }
| ECT01		{ $$ = ECN_ECT01; }
| CE		{ $$ = ECN_CE; }
;

flags
: WORD         { $$ = $1; }
| '.'          { $$ = strdup("."); }
| WORD '.'     { asprintf(&($$), "%s.", $1); free($1); }
| '-'          { $$ = strdup(""); }  /* no TCP flags set in segment */
;

seq
: INTEGER ':' INTEGER '(' INTEGER ')' {
	if (!is_valid_u32($1)) {
		semantic_error("TCP start sequence number out of range");
	}
	if (!is_valid_u32($3)) {
		semantic_error("TCP end sequence number out of range");
	}
	if (!is_valid_u16($5)) {
		semantic_error("TCP payload size out of range");
	}
	if ($3 != ($1 +$5)) {
		semantic_error("inconsistent TCP sequence numbers and "
			       "payload size");
	}
	$$.start_sequence = $1;
	$$.payload_bytes = $5;
	$$.absolute = false;
}
| INTEGER ':' INTEGER '(' INTEGER ')' '!' {
	if (!is_valid_u32($1)) {
		semantic_error("TCP start sequence number out of range");
	}
	if (!is_valid_u32($3)) {
		semantic_error("TCP end sequence number out of range");
	}
	if (!is_valid_u16($5)) {
		semantic_error("TCP payload size out of range");
	}
	if ($3 != ($1 +$5)) {
		semantic_error("inconsistent TCP sequence numbers and "
			       "payload size");
	}
	$$.start_sequence = $1;
	$$.payload_bytes = $5;
	$$.absolute = true;
}
| ELLIPSIS '(' INTEGER ')' {
	if (!is_valid_u16($3)) {
		semantic_error("TCP payload size out of range");
	}
	$$.start_sequence = 0;
	$$.payload_bytes = $3;
	$$.ignore = true;
}
;

opt_ack
:              { $$ = 0; }
| ACK INTEGER  {
	if (!is_valid_u32($2)) {
		semantic_error("TCP ack sequence number out of range");
	}
	$$ = $2;
}
;

opt_window
:		{ $$ = -1; }
| WIN INTEGER	{
	if (!is_valid_u16($2)) {
		semantic_error("TCP window value out of range");
	}
	$$ = $2;
}
;

opt_tcp_options
:                             { $$ = tcp_options_new(); }
| '<' tcp_option_list '>'     { $$ = $2; }
| '<' ELLIPSIS '>'            { $$ = NULL; /* FLAG_OPTIONS_NOCHECK */ }
;

tcp_option_list
: tcp_option                       {
	$$ = tcp_options_new();
	if (tcp_options_append($$, $1)) {
		semantic_error("TCP option list too long");
	}
}
| tcp_option_list ',' tcp_option   {
	$$ = $1;
	if (tcp_options_append($$, $3)) {
		semantic_error("TCP option list too long");
	}
}
;

opt_tcp_fast_open_cookie
:			{ $$ = strdup(""); }
| tcp_fast_open_cookie	{ $$ = $1; }
;

tcp_fast_open_cookie
: WORD    { $$ = strdup(yytext); }
| INTEGER { $$ = strdup(yytext); }
;

tcp_option
: NOP              { $$ = tcp_option_new(TCPOPT_NOP, 1); }
| EOL              { $$ = tcp_option_new(TCPOPT_EOL, 1); }
| MSS INTEGER      {
	$$ = tcp_option_new(TCPOPT_MAXSEG, TCPOLEN_MAXSEG);
	if (!is_valid_u16($2)) {
		semantic_error("mss value out of range");
	}
	$$->data.mss.bytes = htons($2);
}
| WSCALE INTEGER   {
	$$ = tcp_option_new(TCPOPT_WINDOW, TCPOLEN_WINDOW);
	if (!is_valid_u8($2)) {
		semantic_error("window scale shift count out of range");
	}
	$$->data.window_scale.shift_count = $2;
}
| SACKOK           {
	$$ = tcp_option_new(TCPOPT_SACK_PERMITTED,
				    TCPOLEN_SACK_PERMITTED);
}
| SACK sack_block_list {
	$$ = $2;
}
| TIMESTAMP VAL ignore_integer ECR abs_integer  {
	u32 val, ecr;
	ignore_ts_val = $3.ignore;
	absolute_ts_ecr = $5.absolute;
	$$ = tcp_option_new(TCPOPT_TIMESTAMP, TCPOLEN_TIMESTAMP);
	val = $3.integer;
	ecr = $5.integer;
	if (!is_valid_u32(val)) {
		semantic_error("ts val out of range");
	}
	if (!is_valid_u32(ecr)) {
		semantic_error("ecr val out of range");
	}
	$$->data.time_stamp.val = htonl(val);
	$$->data.time_stamp.ecr = htonl(ecr);
}
| FAST_OPEN opt_tcp_fast_open_cookie  {
	char *error = NULL;
	$$ = new_tcp_fast_open_option($2, &error);
	free($2);
	if ($$ == NULL) {
		assert(error != NULL);
		semantic_error(error);
		free(error);
	}
}
;

abs_integer
: INTEGER     { $$.integer = $1; $$.absolute = false; }
| INTEGER '!' { $$.integer = $1; $$.absolute = true; }
;

ignore_integer
: INTEGER     { $$.integer = $1; $$.ignore = false; }
| ELLIPSIS     { $$.integer = 0; $$.ignore = true; }
;

sack_block_list
: sack_block                 { $$ = $1; }
| sack_block_list sack_block {
	const int list_block_bytes =  $1->length - 2;
	assert(list_block_bytes > 0);
	assert((list_block_bytes % sizeof(struct sack_block)) == 0);
	const int num_blocks = list_block_bytes / sizeof(struct sack_block);
	/* Append this SACK block to the end of the array of blocks. */
	memcpy($1->data.sack.block + num_blocks, $2->data.sack.block,
		sizeof(struct sack_block));
	$1->length += sizeof(struct sack_block);
	free($2);
	$$ = $1;
}
;

sack_block
: INTEGER ':' INTEGER {
	$$ = tcp_option_new(TCPOPT_SACK, 2 + sizeof(struct sack_block));
	if (!is_valid_u32($1)) {
		semantic_error("TCP SACK left sequence number out of range");
	}
	if (!is_valid_u32($3)) {
		semantic_error("TCP SACK right sequence number out of range");
	}
	$$->data.sack.block[0].left = htonl($1);
	$$->data.sack.block[0].right = htonl($3);
}
;

syscall_spec
: opt_end_time function_name function_arguments '='
  expression opt_errno opt_note  {
	$$ = calloc(1, sizeof(struct syscall_spec));
	$$->end_usecs	= $1;
	$$->name	= $2;
	$$->arguments	= $3;
	$$->result	= $5;
	$$->error	= $6;
	$$->note	= $7;
}
;

opt_end_time
:                         { $$ = SYSCALL_NON_BLOCKING; }
| ELLIPSIS time           { $$ = $2; }
;

function_name
: WORD                    { $$ = $1; current_script_line = yylineno; }
;

function_arguments
: '(' ')'                 { $$ = NULL; }
| '(' expression_list ')' { $$ = $2; }
;

expression_list
: expression                     { $$ = new_expression_list($1); }
| expression_list ',' expression { $$ = $1; expression_list_append($1, $3); }
;

expression
: ELLIPSIS          {
	$$ = new_expression(EXPR_ELLIPSIS);
}
| decimal_integer   { $$ = $1; }
| hex_integer       { $$ = $1; }
| _HTONL_ '(' INTEGER ')' {
	if (!is_valid_u32($3)) {
		semantic_error("number out of range");
	}
	$$ = new_integer_expression(htonl((u32)$3), "%lu");
}
| _HTONL_ '(' HEX_INTEGER ')' {
	if (!is_valid_u32($3)) {
		semantic_error("number out of range");
	}
	$$ = new_integer_expression(htonl((u32)$3), "%#lx");
}
| WORD              {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $1;
}
| STRING            {
	$$ = new_expression(EXPR_STRING);
	$$->value.string = $1;
	$$->format = "\"%s\"";
}
| STRING ELLIPSIS   {
	$$ = new_expression(EXPR_STRING);
	$$->value.string = $1;
	$$->format = "\"%s\"...";
}
| binary_expression {
	$$ = $1;
}
| array             {
	$$ = $1;
}
| inaddr          {
	$$ = $1;
}
| sockaddr          {
	$$ = $1;
}
| msghdr            {
	$$ = $1;
}
| cmsghdr           {
	$$ = $1;
}
| iovec             {
	$$ = $1;
}
| pollfd            {
	$$ = $1;
}
| linger            {
	$$ = $1;
}
| accept_filter_arg {
	$$ = $1;
}
| tcp_function_set  {
	$$ = $1;
}
| sf_hdtr           {
	$$ = $1;
}
| sctp_rtoinfo      {
	$$ = $1;
}
| sctp_initmsg      {
	$$ = $1;
}
| sctp_assoc_value  {
	$$ = $1;
}
| sctp_hmacalgo     {
	$$ = $1;
}
| sctp_stream_value {
	$$ = $1;
}
| sctp_authkeyid    {
	$$ = $1;
}
| sctp_sackinfo     {
	$$ = $1;
}
| sctp_status       {
	$$ = $1;
}
| sctp_paddrinfo    {
	$$ = $1;
}
| sctp_paddrparams  {
	$$ = $1;
}
| sctp_assocparams  {
	$$ = $1;
}
| sctp_event        {
	$$ = $1;
}
| sctp_event_subscribe {
	$$ = $1;
}
| sctp_sndinfo      {
	$$ = $1;
}
| sctp_setprim      {
	$$ = $1;
}
| sctp_setadaptation{
	$$ = $1;
}
| sctp_sndrcvinfo   {
	$$ = $1;
}
| sctp_prinfo       {
	$$ = $1;
}
|sctp_default_prinfo{
	$$ = $1;
}
| sctp_authinfo     {
	$$ = $1;
}
| sctp_sendv_spa    {
	$$ = $1;
}
| sctp_rcvinfo      {
	$$ = $1;
}
| sctp_nxtinfo      {
	$$ = $1;
}
| sctp_recvv_rn     {
	$$ = $1;
}
| sctp_assoc_ids    {
	$$ = $1;
}
| sctp_authchunks   {
	$$ = $1;
}
| sctp_setpeerprim  {
	$$ = $1;
}
| sctp_authchunk    {
	$$ = $1;
}
| sctp_authkey      {
	$$ = $1;
}
| sctp_reset_streams{
	$$ = $1;
}
| sctp_add_streams  {
	$$ = $1;
}
| sctp_udpencaps  {
	$$ = $1;
}
| null              {
	$$ = $1;
}
;

decimal_integer
: INTEGER           {
	$$ = new_integer_expression($1, "%ld");
}
;

hex_integer
: HEX_INTEGER       {
	$$ = new_integer_expression($1, "%#lx");
}
;

binary_expression
: expression '|' expression {       /* bitwise OR */
	$$ = new_expression(EXPR_BINARY);
	struct binary_expression *binary =
			  malloc(sizeof(struct binary_expression));
	binary->op = strdup("|");
	binary->lhs = $1;
	binary->rhs = $3;
	$$->value.binary = binary;
}
;

array
: '[' ']'                 {
	$$ = new_expression(EXPR_LIST);
	$$->value.list = NULL;
}
| '[' expression_list ']' {
	$$ = new_expression(EXPR_LIST);
	$$->value.list = $2;
}
;

inaddr
: INET_ADDR '(' STRING ')' {
	__be32 ip_address = inet_addr($3);
	$$ = new_integer_expression(ip_address, "%#lx");
}
;

sockaddr
:   '{' SA_FAMILY '=' WORD ','
	SIN_PORT '=' _HTONS_ '(' INTEGER ')' ','
	SIN_ADDR '=' INET_ADDR '(' STRING ')' '}' {
	if (strcmp($4, "AF_INET") == 0) {
		struct sockaddr_in *ipv4 = malloc(sizeof(struct sockaddr_in));
		memset(ipv4, 0, sizeof(*ipv4));
		ipv4->sin_family = AF_INET;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
		ipv4->sin_len = sizeof(*ipv4);
#endif
		ipv4->sin_port = htons($10);
		if (inet_pton(AF_INET, $17, &ipv4->sin_addr) == 1) {
			$$ = new_expression(EXPR_SOCKET_ADDRESS_IPV4);
			$$->value.socket_address_ipv4 = ipv4;
		} else {
			free(ipv4);
			semantic_error("invalid IPv4 address");
		}
	} else if (strcmp($4, "AF_INET6") == 0) {
		struct sockaddr_in6 *ipv6 = malloc(sizeof(struct sockaddr_in6));
		memset(ipv6, 0, sizeof(*ipv6));
		ipv6->sin6_family = AF_INET6;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
		ipv6->sin6_len = sizeof(*ipv6);
#endif
		ipv6->sin6_port = htons($10);
		if (inet_pton(AF_INET6, $17, &ipv6->sin6_addr) == 1) {
			$$ = new_expression(EXPR_SOCKET_ADDRESS_IPV6);
			$$->value.socket_address_ipv6 = ipv6;
		} else {
			free(ipv6);
			semantic_error("invalid IPv6 address");
		}
	}
}
;

data
: ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| sctp_assoc_change         { $$ = $1; }
| sctp_paddr_change         { $$ = $1; }
| sctp_remote_error         { $$ = $1; }
| sctp_send_failed          { $$ = $1; }
| sctp_shutdown_event       { $$ = $1; }
| sctp_adaptation_event     { $$ = $1; }
| sctp_pdapi_event          { $$ = $1; }
| sctp_sender_dry_event     { $$ = $1; }
| sctp_send_failed_event    { $$ = $1; }
| sctp_authkey_event        { $$ = $1; }
| sctp_tlv                  { $$ = $1; }
| sctp_stream_reset_event   { $$ = $1; }
| sctp_assoc_reset_event    { $$ = $1; }
| sctp_stream_change_event  { $$ = $1; }
;

msghdr
: '{' MSG_NAME '(' ELLIPSIS ')' '=' ELLIPSIS ','
      MSG_IOV '(' decimal_integer ')' '=' array ','
      MSG_CONTROL '('decimal_integer ')' '=' array ','
      MSG_FLAGS '=' expression '}' {
	struct msghdr_expr *msg_expr = calloc(1, sizeof(struct msghdr_expr));
	$$ = new_expression(EXPR_MSGHDR);
	$$->value.msghdr = msg_expr;
	msg_expr->msg_name	= new_expression(EXPR_ELLIPSIS);
	msg_expr->msg_namelen	= new_expression(EXPR_ELLIPSIS);
	msg_expr->msg_iov	= $14;
	msg_expr->msg_iovlen	= $11;
	msg_expr->msg_controllen= $18;
	msg_expr->msg_control   = $21;
	msg_expr->msg_flags	= $25;
}
;

cmsg_level
: CMSG_LEVEL '=' INTEGER {
	if (!is_valid_s32($3)) {
		semantic_error("cmsg_level out of range");
	}
	$$ = new_integer_expression($3, "%d");
}
| CMSG_LEVEL '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| CMSG_LEVEL '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

cmsg_type
: CMSG_TYPE '=' INTEGER {
	if (!is_valid_s32($3)) {
		semantic_error("cmsg_level out of range");
	}
	$$ = new_integer_expression($3, "%d");
}
| CMSG_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| CMSG_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

cmsg_data
: CMSG_DATA '=' sctp_initmsg     { $$ = $3; }
| CMSG_DATA '=' sctp_sndrcvinfo  { $$ = $3; }
| CMSG_DATA '=' sctp_extrcvinfo  { $$ = $3; }
| CMSG_DATA '=' sctp_sndinfo     { $$ = $3; }
| CMSG_DATA '=' sctp_rcvinfo     { $$ = $3; }
| CMSG_DATA '=' sctp_nxtinfo     { $$ = $3; }
| CMSG_DATA '=' sctp_prinfo      { $$ = $3; }
| CMSG_DATA '=' sctp_authinfo    { $$ = $3; }
| CMSG_DATA '=' sockaddr         { $$ = $3; }
;

cmsghdr
: '{' CMSG_LEN '=' INTEGER ',' cmsg_level ',' cmsg_type ',' cmsg_data '}' {
	$$ = new_expression(EXPR_CMSGHDR);
	$$->value.cmsghdr = calloc(1, sizeof(struct cmsghdr_expr));
	if (!is_valid_s32($4)) {
		semantic_error("cmsg_len out of range");
	}
	$$->value.cmsghdr->cmsg_len = new_integer_expression($4, "%u");
	$$->value.cmsghdr->cmsg_level = $6;
	$$->value.cmsghdr->cmsg_type = $8;
	$$->value.cmsghdr->cmsg_data = $10;
};

iovec
: '{' data ',' decimal_integer '}' {
	struct iovec_expr *iov_expr = calloc(1, sizeof(struct iovec_expr));
	$$ = new_expression(EXPR_IOVEC);
	$$->value.iovec = iov_expr;
	iov_expr->iov_base = $2;
	iov_expr->iov_len = $4;
}
| '{' IOV_BASE '=' data ',' IOV_LEN '=' decimal_integer '}' {
	struct iovec_expr *iov_expr = calloc(1, sizeof(struct iovec_expr));
	$$ = new_expression(EXPR_IOVEC);
	$$->value.iovec = iov_expr;
	iov_expr->iov_base = $4;
	iov_expr->iov_len = $8;
}
;

pollfd
: '{' FD '=' expression ',' EVENTS '=' expression opt_revents '}' {
	struct pollfd_expr *pollfd_expr = calloc(1, sizeof(struct pollfd_expr));
	$$ = new_expression(EXPR_POLLFD);
	$$->value.pollfd = pollfd_expr;
	pollfd_expr->fd = $4;
	pollfd_expr->events = $8;
	pollfd_expr->revents = $9;
}
;

opt_revents
:                                { $$ = new_integer_expression(0, "%ld"); }
| ',' REVENTS '=' expression     { $$ = $4; }
;

l_onoff
: ONOFF '=' INTEGER {
	if (!is_valid_s32($3)) {
		semantic_error("linger onoff out of range");
	}
	$$ = 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
: '{' l_onoff ',' l_linger '}' {
	$$ = new_expression(EXPR_LINGER);
	$$->value.linger = calloc(1, sizeof(struct linger_expr));
	$$->value.linger->l_onoff  = $2;
	$$->value.linger->l_linger = $4;
}
;

af_name
: AF_NAME '=' STRING {
	$$ = new_expression(EXPR_STRING);
	$$->value.string = $3;
	$$->format = "\"%s\"";
}
| AF_NAME '=' ELLIPSIS {
	$$ = new_expression(EXPR_ELLIPSIS);
}
;

af_arg
: AF_ARG '=' STRING {
	$$ = new_expression(EXPR_STRING);
	$$->value.string = $3;
	$$->format = "\"%s\"";
}
| AF_ARG '=' ELLIPSIS {
	$$ = new_expression(EXPR_ELLIPSIS);
}
;

accept_filter_arg
: '{' af_name '}' {
#if defined(__FreeBSD__) || defined(__NetBSD__)
	$$ = new_expression(EXPR_ACCEPT_FILTER_ARG);
	$$->value.accept_filter_arg = calloc(1, sizeof(struct accept_filter_arg_expr));
	$$->value.accept_filter_arg->af_name = $2;
	$$->value.accept_filter_arg->af_arg = NULL;
#else
	$$ = NULL;
#endif
}
| '{' af_name ',' af_arg '}' {
#if defined(__FreeBSD__) || defined(__NetBSD__)
	$$ = new_expression(EXPR_ACCEPT_FILTER_ARG);
	$$->value.accept_filter_arg = calloc(1, sizeof(struct accept_filter_arg_expr));
	$$->value.accept_filter_arg->af_name = $2;
	$$->value.accept_filter_arg->af_arg = $4;
#else
	$$ = NULL;
#endif
}

function_set_name
: FUNCTION_SET_NAME '=' STRING {
	$$ = new_expression(EXPR_STRING);
	$$->value.string = $3;
	$$->format = "\"%s\"";
}
| FUNCTION_SET_NAME '=' ELLIPSIS {
	$$ = new_expression(EXPR_ELLIPSIS);
}
;

pcbcnt
: PCBCNT '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("linger out of range");
	}
	$$ = new_integer_expression($3, "%lu");
}
| PCBCNT '=' ELLIPSIS {
	$$ = new_expression(EXPR_ELLIPSIS);
}
;

tcp_function_set
: '{' function_set_name ',' pcbcnt '}' {
#if defined(__FreeBSD__)
	$$ = new_expression(EXPR_TCP_FUNCTION_SET);
	$$->value.tcp_function_set = calloc(1, sizeof(struct tcp_function_set_expr));
	$$->value.tcp_function_set->function_set_name = $2;
	$$->value.tcp_function_set->pcbcnt = $4;
#else
	$$ = NULL;
#endif
}
;

sf_hdtr
: '{' SF_HDTR_HEADERS '(' decimal_integer ')' '=' array ','
      SF_HDTR_TRAILERS '('decimal_integer ')' '=' array '}' {
#if defined(__FreeBSD__)
	struct sf_hdtr_expr *sf_hdtr_expr = calloc(1, sizeof(struct sf_hdtr_expr));
	$$ = new_expression(EXPR_SF_HDTR);
	$$->value.sf_hdtr = sf_hdtr_expr;
	sf_hdtr_expr->headers	= $7;
	sf_hdtr_expr->hdr_cnt	= $4;
	sf_hdtr_expr->trailers	= $14;
	sf_hdtr_expr->trl_cnt	= $11;
#else
	$$ = NULL;
#endif
}
;

srto_initial
: SRTO_INITIAL '=' INTEGER {
	if (!is_valid_u32($3)){
		semantic_error("srto_initial out of range");
	}
        $$ = 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");
	}
	$$ = 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");
	}
	$$ = new_integer_expression($3, "%u");
}
| SRTO_MIN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_assoc_id
: INTEGER {
	if (!is_valid_u32($1)) {
		semantic_error("value for sctp_assoc_t out of range");
	}
	$$ = new_integer_expression($1, "%u");
}
| WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $1;
}
| ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_rtoinfo
: '{' SRTO_ASSOC_ID '=' sctp_assoc_id ',' srto_initial ',' srto_max ',' srto_min '}' {
	$$ = new_expression(EXPR_SCTP_RTOINFO);
	$$->value.sctp_rtoinfo = calloc(1, sizeof(struct sctp_rtoinfo_expr));
	$$->value.sctp_rtoinfo->srto_assoc_id = $4;
	$$->value.sctp_rtoinfo->srto_initial = $6;
	$$->value.sctp_rtoinfo->srto_max = $8;
	$$->value.sctp_rtoinfo->srto_min = $10;
}
| '{' srto_initial ',' srto_max ',' srto_min '}' {
	$$ = new_expression(EXPR_SCTP_RTOINFO);
	$$->value.sctp_rtoinfo = calloc(1, sizeof(struct sctp_rtoinfo_expr));
	$$->value.sctp_rtoinfo->srto_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_rtoinfo->srto_initial = $2;
	$$->value.sctp_rtoinfo->srto_max = $4;
	$$->value.sctp_rtoinfo->srto_min = $6;
}
;

sinit_num_ostreams
: SINIT_NUM_OSTREAMS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sinit_num_ostreams out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SINIT_NUM_OSTREAMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sinit_max_instreams
: SINIT_MAX_INSTREAMS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sinit_max_instreams out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SINIT_MAX_INSTREAMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sinit_max_attempts
: SINIT_MAX_ATTEMPTS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sinit_max_attempts out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SINIT_MAX_ATTEMPTS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sinit_max_init_timeo
: SINIT_MAX_INIT_TIMEO '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sinit_max_init_timeo out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SINIT_MAX_INIT_TIMEO '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_initmsg
: '{' sinit_num_ostreams ',' sinit_max_instreams ',' sinit_max_attempts ',' sinit_max_init_timeo '}'
{
	$$ = new_expression(EXPR_SCTP_INITMSG);
	$$->value.sctp_initmsg = calloc(1, sizeof(struct sctp_initmsg_expr));
	$$->value.sctp_initmsg->sinit_num_ostreams = $2;
	$$->value.sctp_initmsg->sinit_max_instreams = $4;
	$$->value.sctp_initmsg->sinit_max_attempts = $6;
	$$->value.sctp_initmsg->sinit_max_init_timeo = $8;
}
;

sctp_stream_value
: '{' STREAM_ID '=' expression ',' STREAM_VALUE '=' expression '}' {
	$$ = new_expression(EXPR_SCTP_STREAM_VALUE);
	$$->value.sctp_stream_value = calloc(1, sizeof(struct sctp_stream_value_expr));
	$$->value.sctp_stream_value->stream_id = $4;
	$$->value.sctp_stream_value->stream_value = $8;
}
;

sctp_assoc_value
: '{' ASSOC_ID '=' sctp_assoc_id ',' ASSOC_VALUE '=' expression '}' {
	$$ = new_expression(EXPR_SCTP_ASSOC_VALUE);
	$$->value.sctp_assoc_value = calloc(1, sizeof(struct sctp_assoc_value_expr));
	$$->value.sctp_assoc_value->assoc_id = $4;
	$$->value.sctp_assoc_value->assoc_value = $8;
}
| '{' ASSOC_VALUE '=' expression '}' {
	$$ = new_expression(EXPR_SCTP_ASSOC_VALUE);
	$$->value.sctp_assoc_value = calloc(1, sizeof(struct sctp_assoc_value_expr));
	$$->value.sctp_assoc_value->assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_assoc_value->assoc_value = $4;
}
;

shmac_number_of_idents
: SHMAC_NUMBER_OF_IDENTS '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("shmac_number_of_idents out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SHMAC_NUMBER_OF_IDENTS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_hmacalgo
: '{' shmac_number_of_idents ',' SHMAC_IDENTS '=' array '}' {
	$$ = new_expression(EXPR_SCTP_HMACALGO);
	$$->value.sctp_hmacalgo = calloc(1, sizeof(struct sctp_assoc_value_expr));
	$$->value.sctp_hmacalgo->shmac_number_of_idents = $2;
	$$->value.sctp_hmacalgo->shmac_idents = $6;
}

scact_keynumber
: SCACT_KEYNUMBER '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("scact_keynumber out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SCACT_KEYNUMBER '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }

sctp_authkeyid
: '{' SCACT_ASSOC_ID '=' sctp_assoc_id ',' scact_keynumber '}' {
	$$ = new_expression(EXPR_SCTP_AUTHKEYID);
	$$->value.sctp_authkeyid = calloc(1, sizeof(struct sctp_authkeyid_expr));
	$$->value.sctp_authkeyid->scact_assoc_id = $4;
	$$->value.sctp_authkeyid->scact_keynumber = $6;
}
| '{' scact_keynumber '}'{ 
	$$ = new_expression(EXPR_SCTP_AUTHKEYID);
	$$->value.sctp_authkeyid = calloc(1, sizeof(struct sctp_authkeyid_expr));
	$$->value.sctp_authkeyid->scact_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_authkeyid->scact_keynumber = $2;
}

sack_delay
: SACK_DELAY '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sack_delay out of range");
	}
	$$ = 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");
	}
	$$ = new_integer_expression($3, "%u");
}
| SACK_FREQ '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }

sctp_sackinfo
: '{' SACK_ASSOC_ID '=' sctp_assoc_id ',' sack_delay ',' sack_freq '}' {
	$$ = new_expression(EXPR_SCTP_SACKINFO);
	$$->value.sctp_sack_info = calloc(1, sizeof(struct sctp_sack_info_expr));
	$$->value.sctp_sack_info->sack_assoc_id = $4;
	$$->value.sctp_sack_info->sack_delay = $6;
	$$->value.sctp_sack_info->sack_freq = $8;
}
| '{' sack_delay ',' sack_freq '}' {
	$$ = new_expression(EXPR_SCTP_SACKINFO);
	$$->value.sctp_sack_info = calloc(1, sizeof(struct sctp_sack_info_expr));
	$$->value.sctp_sack_info->sack_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_sack_info->sack_delay = $2;
	$$->value.sctp_sack_info->sack_freq = $4;
}
;

sstat_state
: SSTAT_STATE '=' expression { $$ = $3; }
;

sstat_rwnd
: SSTAT_RWND '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sstat_rwnd out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SSTAT_RWND '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sstat_unackdata
: SSTAT_UNACKDATA '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sstat_unackdata out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSTAT_UNACKDATA '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sstat_penddata
: SSTAT_PENDDATA '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sstat_penddata out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSTAT_PENDDATA '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sstat_instrms
: SSTAT_INSTRMS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sstat_instrms out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSTAT_INSTRMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sstat_outstrms
: SSTAT_OUTSTRMS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sstat_outstrms out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSTAT_OUTSTRMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sstat_fragmentation_point
: SSTAT_FRAGMENTATION_POINT '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sstat_fragmentation_point out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SSTAT_FRAGMENTATION_POINT '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sstat_primary
: SSTAT_PRIMARY '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| SSTAT_PRIMARY '=' sctp_paddrinfo  { $$ = $3; }
;

spinfo_address
: SPINFO_ADDRESS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| SPINFO_ADDRESS '=' sockaddr { $$ = $3; }
;

spinfo_state
: SPINFO_STATE '=' INTEGER {
	if (!is_valid_s32($3)) {
		semantic_error("spinfo_state out of range");
	}
	$$ = new_integer_expression($3, "%d");
}
| SPINFO_STATE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SPINFO_STATE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spinfo_cwnd
: SPINFO_CWND '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spinfo_cwnd out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPINFO_CWND '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spinfo_srtt
: SPINFO_SRTT '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spinfo_srtt out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPINFO_SRTT '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spinfo_rto
: SPINFO_RTO '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spinfo_rto out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPINFO_RTO '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spinfo_mtu
: SPINFO_MTU '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spinfo_mtu out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPINFO_MTU '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_paddrinfo
: '{' SPINFO_ASSOC_ID '=' sctp_assoc_id ',' spinfo_address ',' spinfo_state ',' spinfo_cwnd ','
      spinfo_srtt ',' spinfo_rto ',' spinfo_mtu '}' {
	$$ = new_expression(EXPR_SCTP_PADDRINFO);
	$$->value.sctp_paddrinfo = calloc(1, sizeof(struct sctp_paddrinfo_expr));
	$$->value.sctp_paddrinfo->spinfo_assoc_id = $4;
	$$->value.sctp_paddrinfo->spinfo_address = $6;
	$$->value.sctp_paddrinfo->spinfo_state = $8;
	$$->value.sctp_paddrinfo->spinfo_cwnd = $10;
	$$->value.sctp_paddrinfo->spinfo_srtt = $12;
	$$->value.sctp_paddrinfo->spinfo_rto = $14;
	$$->value.sctp_paddrinfo->spinfo_mtu = $16;
}
| '{' spinfo_address ',' spinfo_state ',' spinfo_cwnd ','
      spinfo_srtt ',' spinfo_rto ',' spinfo_mtu '}' {
	$$ = new_expression(EXPR_SCTP_PADDRINFO);
	$$->value.sctp_paddrinfo = calloc(1, sizeof(struct sctp_paddrinfo_expr));
	$$->value.sctp_paddrinfo->spinfo_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_paddrinfo->spinfo_address = $2;
	$$->value.sctp_paddrinfo->spinfo_state = $4;
	$$->value.sctp_paddrinfo->spinfo_cwnd = $6;
	$$->value.sctp_paddrinfo->spinfo_srtt = $8;
	$$->value.sctp_paddrinfo->spinfo_rto = $10;
	$$->value.sctp_paddrinfo->spinfo_mtu = $12;
}
;

sctp_status
: '{' SSTAT_ASSOC_ID '=' sctp_assoc_id ',' sstat_state ',' sstat_rwnd ',' sstat_unackdata ',' sstat_penddata ',' sstat_instrms ',' sstat_outstrms ','
	sstat_fragmentation_point ',' sstat_primary '}' {
	$$ = new_expression(EXPR_SCTP_STATUS);
	$$->value.sctp_status = calloc(1, sizeof(struct sctp_status_expr));
	$$->value.sctp_status->sstat_assoc_id = $4;
	$$->value.sctp_status->sstat_state = $6;
	$$->value.sctp_status->sstat_rwnd = $8;
	$$->value.sctp_status->sstat_unackdata = $10;
	$$->value.sctp_status->sstat_penddata = $12;
	$$->value.sctp_status->sstat_instrms = $14;
	$$->value.sctp_status->sstat_outstrms = $16;
	$$->value.sctp_status->sstat_fragmentation_point = $18;
	$$->value.sctp_status->sstat_primary = $20;
}
| '{' sstat_state ',' sstat_rwnd ',' sstat_unackdata ',' sstat_penddata ',' sstat_instrms ',' sstat_outstrms ','
	sstat_fragmentation_point ',' sstat_primary '}' {
	$$ = new_expression(EXPR_SCTP_STATUS);
	$$->value.sctp_status = calloc(1, sizeof(struct sctp_status_expr));
	$$->value.sctp_status->sstat_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_status->sstat_state = $2;
	$$->value.sctp_status->sstat_rwnd = $4;
	$$->value.sctp_status->sstat_unackdata = $6;
	$$->value.sctp_status->sstat_penddata = $8;
	$$->value.sctp_status->sstat_instrms = $10;
	$$->value.sctp_status->sstat_outstrms = $12;
	$$->value.sctp_status->sstat_fragmentation_point = $14;
	$$->value.sctp_status->sstat_primary = $16;
}
;

spp_address
: SPP_ADDRESS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| SPP_ADDRESS '=' sockaddr { $$ = $3; }
;

spp_hbinterval
: SPP_HBINTERVAL '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spp_hbinterval out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPP_HBINTERVAL '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spp_pathmtu
: SPP_PATHMTU '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spp_pathmtu out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPP_PATHMTU '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spp_pathmaxrxt
: SPP_PATHMAXRXT '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("spp_pathmaxrxt out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SPP_PATHMAXRXT '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spp_flags
: SPP_FLAGS '=' expression { $$ = $3; }
;

spp_ipv6_flowlabel
: SPP_IPV6_FLOWLABEL_ '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spp_ipv6_flowlabel out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPP_IPV6_FLOWLABEL_ '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spp_dscp
: SPP_DSCP_ '=' INTEGER {
	if (!is_valid_u8($3)) {
		semantic_error("spp_dscp out of range");
	}
	$$ = new_integer_expression($3, "%hhu");
}
| SPP_DSCP_ '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_paddrparams
: '{' SPP_ASSOC_ID '=' sctp_assoc_id ',' spp_address ',' spp_hbinterval ',' spp_pathmaxrxt ',' spp_pathmtu ','spp_flags ','
      spp_ipv6_flowlabel ',' spp_dscp'}' {
	$$ = new_expression(EXPR_SCTP_PEER_ADDR_PARAMS);
	$$->value.sctp_paddrparams = calloc(1, sizeof(struct sctp_paddrparams_expr));
	$$->value.sctp_paddrparams->spp_assoc_id = $4;
	$$->value.sctp_paddrparams->spp_address = $6;
	$$->value.sctp_paddrparams->spp_hbinterval = $8;
	$$->value.sctp_paddrparams->spp_pathmaxrxt = $10;
	$$->value.sctp_paddrparams->spp_pathmtu = $12;
	$$->value.sctp_paddrparams->spp_flags = $14;
	$$->value.sctp_paddrparams->spp_ipv6_flowlabel = $16;
	$$->value.sctp_paddrparams->spp_dscp = $18;
}
| '{' spp_address ',' spp_hbinterval ',' spp_pathmaxrxt ',' spp_pathmtu ','spp_flags ','
      spp_ipv6_flowlabel ',' spp_dscp'}' {
	$$ = new_expression(EXPR_SCTP_PEER_ADDR_PARAMS);
	$$->value.sctp_paddrparams = calloc(1, sizeof(struct sctp_paddrparams_expr));
	$$->value.sctp_paddrparams->spp_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_paddrparams->spp_address = $2;
	$$->value.sctp_paddrparams->spp_hbinterval = $4;
	$$->value.sctp_paddrparams->spp_pathmaxrxt = $6;
	$$->value.sctp_paddrparams->spp_pathmtu = $8;
	$$->value.sctp_paddrparams->spp_flags = $10;
	$$->value.sctp_paddrparams->spp_ipv6_flowlabel = $12;
	$$->value.sctp_paddrparams->spp_dscp = $14;
}
;

sasoc_asocmaxrxt
: SASOC_ASOCMAXRXT '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sasoc_asocmaxrxt out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SASOC_ASOCMAXRXT '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sasoc_number_peer_destinations
: SASOC_NUMBER_PEER_DESTINATIONS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sasoc_number_peer_destinations out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SASOC_NUMBER_PEER_DESTINATIONS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sasoc_peer_rwnd
: SASOC_PEER_RWND '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sasoc_peer_rwnd out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SASOC_PEER_RWND '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sasoc_local_rwnd
: SASOC_LOCAL_RWND '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sasoc_local_rwnd out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SASOC_LOCAL_RWND '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sasoc_cookie_life
: SASOC_COOKIE_LIFE '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sasoc_cookie_life out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SASOC_COOKIE_LIFE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_assocparams
: '{' SASOC_ASSOC_ID '=' sctp_assoc_id ',' sasoc_asocmaxrxt ',' sasoc_number_peer_destinations ','
      sasoc_peer_rwnd ',' sasoc_local_rwnd ',' sasoc_cookie_life '}' {
	$$ = new_expression(EXPR_SCTP_ASSOCPARAMS);
        $$->value.sctp_assocparams = calloc(1, sizeof(struct sctp_assocparams_expr));
        $$->value.sctp_assocparams->sasoc_assoc_id = $4;
        $$->value.sctp_assocparams->sasoc_asocmaxrxt = $6;
        $$->value.sctp_assocparams->sasoc_number_peer_destinations = $8;
        $$->value.sctp_assocparams->sasoc_peer_rwnd = $10;
        $$->value.sctp_assocparams->sasoc_local_rwnd = $12;
        $$->value.sctp_assocparams->sasoc_cookie_life = $14;
}
| '{' sasoc_asocmaxrxt ',' sasoc_number_peer_destinations ','
      sasoc_peer_rwnd ',' sasoc_local_rwnd ',' sasoc_cookie_life '}' {
	$$ = new_expression(EXPR_SCTP_ASSOCPARAMS);
        $$->value.sctp_assocparams = calloc(1, sizeof(struct sctp_assocparams_expr));
        $$->value.sctp_assocparams->sasoc_assoc_id = new_expression(EXPR_ELLIPSIS);
        $$->value.sctp_assocparams->sasoc_asocmaxrxt = $2;
        $$->value.sctp_assocparams->sasoc_number_peer_destinations = $4;
        $$->value.sctp_assocparams->sasoc_peer_rwnd = $6;
        $$->value.sctp_assocparams->sasoc_local_rwnd = $8;
        $$->value.sctp_assocparams->sasoc_cookie_life = $10;
}
;

se_type
: SE_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("se_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SE_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
;

se_on
: SE_ON '=' INTEGER {
	if (!is_valid_u8($3)) {
		semantic_error("se_on out of range");
	}
	$$ = new_integer_expression($3, "%hhu");
}
| SE_ON '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_event
: '{' SE_ASSOC_ID '=' sctp_assoc_id ',' se_type ',' se_on '}' {
	$$ = new_expression(EXPR_SCTP_EVENT);
	$$->value.sctp_event = calloc(1, sizeof(struct sctp_event_expr));
	$$->value.sctp_event->se_assoc_id = $4;
	$$->value.sctp_event->se_type = $6;
	$$->value.sctp_event->se_on = $8;
}
| '{' se_type ',' se_on '}' {
	$$ = new_expression(EXPR_SCTP_EVENT);
	$$->value.sctp_event = calloc(1, sizeof(struct sctp_event_expr));
	$$->value.sctp_event->se_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_event->se_type = $2;
	$$->value.sctp_event->se_on = $4;
}
;

sctp_event_subscribe
: '{' _SCTP_DATA_IO_EVENT_          '=' INTEGER ',' _SCTP_ASSOCIATION_EVENT_      '=' INTEGER ','
      _SCTP_ADDRESS_EVENT_          '=' INTEGER ',' _SCTP_SEND_FAILURE_EVENT_     '=' INTEGER ','
      _SCTP_PEER_ERROR_EVENT_       '=' INTEGER ',' _SCTP_SHUTDOWN_EVENT_         '=' INTEGER ','
      _SCTP_PARTIAL_DELIVERY_EVENT_ '=' INTEGER ',' _SCTP_ADAPTATION_LAYER_EVENT_ '=' INTEGER ','
      _SCTP_AUTHENTICATION_EVENT_   '=' INTEGER ',' _SCTP_SENDER_DRY_EVENT_       '=' INTEGER '}' {
	$$ = new_expression(EXPR_SCTP_EVENT_SUBSCRIBE);
	$$->value.sctp_event_subscribe = calloc(1, sizeof(struct sctp_event_subscribe_expr));
	if (!is_valid_u8($4)) {
		semantic_error("sctp_data_io_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_data_io_event =  new_integer_expression($4, "%hhu");
	if (!is_valid_u8($8)) {
		semantic_error("sctp_association_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_association_event =  new_integer_expression($8, "%hhu");
	if (!is_valid_u8($12)) {
		semantic_error("sctp_address_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_address_event =  new_integer_expression($12, "%hhu");
	if (!is_valid_u8($16)) {
		semantic_error("sctp_send_failure_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_send_failure_event =  new_integer_expression($16, "%hhu");
	if (!is_valid_u8($20)) {
		semantic_error("sctp_peer_error_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_peer_error_event =  new_integer_expression($20, "%hhu");
	if (!is_valid_u8($24)) {
		semantic_error("sctp_shutdown_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_shutdown_event =  new_integer_expression($24, "%hhu");
	if (!is_valid_u8($28)) {
		semantic_error("sctp_partial_delivery_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_partial_delivery_event =  new_integer_expression($28, "%hhu");
	if (!is_valid_u8($32)) {
		semantic_error("sctp_adaptation_layer_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_adaptation_layer_event =  new_integer_expression($32, "%hhu");
	if (!is_valid_u8($36)) {
		semantic_error("sctp_authentication_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_authentication_event =  new_integer_expression($36, "%hhu");
	if (!is_valid_u8($40)) {
		semantic_error("sctp_sender_dry_event out of range");
	}
	$$->value.sctp_event_subscribe->sctp_sender_dry_event =  new_integer_expression($40, "%hhu");
}
;

snd_sid
: SND_SID '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("snd_sid out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SND_SID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

snd_flags
: SND_FLAGS '=' expression { $$ = $3; }
;

snd_ppid
: SND_PPID '=' _HTONL_ '(' INTEGER ')'{
	if (!is_valid_u32($5)) {
		semantic_error("snd_ppid out of range");
	}
	$$ = new_integer_expression(htonl((u32)$5), "%u");
}
| SND_PPID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

snd_context
: SND_CONTEXT '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("snd_context out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SND_CONTEXT '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_sndinfo
: '{' snd_sid ',' snd_flags ',' snd_ppid ',' snd_context ',' SND_ASSOC_ID '=' sctp_assoc_id'}' {
	$$ = new_expression(EXPR_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;
	$$->value.sctp_sndinfo->snd_assoc_id = $12;
}
| '{' snd_sid ',' snd_flags ',' snd_ppid ',' snd_context '}' {
	$$ = new_expression(EXPR_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;
	$$->value.sctp_sndinfo->snd_assoc_id = new_expression(EXPR_ELLIPSIS);
}
;
ssp_addr
: SSP_ADDR '=' sockaddr { $$ = $3; }
| SSP_ADDR '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_setprim
: '{' SSP_ASSOC_ID '=' sctp_assoc_id ',' ssp_addr '}' {
	$$ = new_expression(EXPR_SCTP_SETPRIM);
	$$->value.sctp_setprim = calloc(1, sizeof(struct sctp_setprim_expr));
	$$->value.sctp_setprim->ssp_assoc_id = $4;
	$$->value.sctp_setprim->ssp_addr = $6;
}
| '{' ssp_addr '}' {
	$$ = new_expression(EXPR_SCTP_SETPRIM);
	$$->value.sctp_setprim = calloc(1, sizeof(struct sctp_setprim_expr));
	$$->value.sctp_setprim->ssp_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_setprim->ssp_addr = $2;
}
;

sctp_setadaptation
: '{' SSB_ADAPTATION_IND '=' INTEGER '}' {
	$$ = new_expression(EXPR_SCTP_SETADAPTATION);
	$$->value.sctp_setadaptation = calloc(1, sizeof(struct sctp_setadaptation_expr));
	if (!is_valid_u32($4)) {
		semantic_error("ssb_adaptation_ind out of range");
	}
	$$->value.sctp_setadaptation->ssb_adaptation_ind = new_integer_expression($4, "%u");
}
| '{' SSB_ADAPTATION_IND '=' ELLIPSIS '}' {
	$$ = new_expression(EXPR_SCTP_SETADAPTATION);
	$$->value.sctp_setadaptation = calloc(1, sizeof(struct sctp_setadaptation_expr));
	$$->value.sctp_setadaptation->ssb_adaptation_ind = new_expression(EXPR_ELLIPSIS);
}
;

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 '=' expression { $$ = $3; }
;

sinfo_ppid
: SINFO_PPID '=' _HTONL_ '(' INTEGER ')' {
	if (!is_valid_u32($5)) {
		semantic_error("sinfo_ppid out of range");
	}
	$$ = new_integer_expression(htonl((u32)$5), "%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("sinfo_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 ',' SINFO_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_SNDRCVINFO);
	$$->value.sctp_sndrcvinfo = calloc(1, sizeof(struct sctp_sndrcvinfo_expr));
	$$->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;
	$$->value.sctp_sndrcvinfo->sinfo_assoc_id = $20;
}
| '{' 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_expr));
	$$->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;
	$$->value.sctp_sndrcvinfo->sinfo_assoc_id = new_expression(EXPR_ELLIPSIS);
};

sinfo_pr_value
: SINFO_PR_VALUE '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sinfo_pr_value out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SINFO_PR_VALUE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

serinfo_next_stream
: SERINFO_NEXT_STREAM '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("serinfo_next_stream out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SERINFO_NEXT_STREAM '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

serinfo_next_flags
: SERINFO_NEXT_FLAGS '=' expression { $$ = $3; }

serinfo_next_aid
: SERINFO_NEXT_AID '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("serinfo_next_aid out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SERINFO_NEXT_AID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;
serinfo_next_length
: SERINFO_NEXT_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("serinfo_next_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SERINFO_NEXT_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

serinfo_next_ppid
: SERINFO_NEXT_PPID '=' _HTONL_ '(' INTEGER ')' {
	if (!is_valid_u32($5)) {
		semantic_error("serinfo_next_ppid out of range");
	}
	$$ = new_integer_expression(htonl((u32)$5), "%u");
}
| SERINFO_NEXT_PPID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_extrcvinfo
: '{' sinfo_stream ',' sinfo_ssn ',' sinfo_flags ',' sinfo_ppid ',' sinfo_context ',' sinfo_pr_value ',' sinfo_tsn ',' sinfo_cumtsn ','
serinfo_next_flags ',' serinfo_next_stream ',' serinfo_next_aid ',' serinfo_next_length ',' serinfo_next_ppid ',' SINFO_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_EXTRCVINFO);
	$$->value.sctp_extrcvinfo = calloc(1, sizeof(struct sctp_extrcvinfo_expr));
	$$->value.sctp_extrcvinfo->sinfo_stream = $2;
	$$->value.sctp_extrcvinfo->sinfo_ssn = $4;
	$$->value.sctp_extrcvinfo->sinfo_flags = $6;
	$$->value.sctp_extrcvinfo->sinfo_ppid = $8;
	$$->value.sctp_extrcvinfo->sinfo_context = $10;
	$$->value.sctp_extrcvinfo->sinfo_pr_value = $12;
	$$->value.sctp_extrcvinfo->sinfo_tsn = $14;
	$$->value.sctp_extrcvinfo->sinfo_cumtsn = $16;
	$$->value.sctp_extrcvinfo->serinfo_next_flags = $18;
	$$->value.sctp_extrcvinfo->serinfo_next_stream = $20;
	$$->value.sctp_extrcvinfo->serinfo_next_aid = $22;
	$$->value.sctp_extrcvinfo->serinfo_next_length = $24;
	$$->value.sctp_extrcvinfo->serinfo_next_ppid = $26;
	$$->value.sctp_extrcvinfo->sinfo_assoc_id = $30;
}
| '{' sinfo_stream ',' sinfo_ssn ',' sinfo_flags ',' sinfo_ppid ',' sinfo_context ',' sinfo_pr_value ',' sinfo_tsn ',' sinfo_cumtsn ','
serinfo_next_flags ',' serinfo_next_stream ',' serinfo_next_aid ',' serinfo_next_length ',' serinfo_next_ppid '}' {
	$$ = new_expression(EXPR_SCTP_EXTRCVINFO);
	$$->value.sctp_extrcvinfo = calloc(1, sizeof(struct sctp_extrcvinfo_expr));
	$$->value.sctp_extrcvinfo->sinfo_stream = $2;
	$$->value.sctp_extrcvinfo->sinfo_ssn = $4;
	$$->value.sctp_extrcvinfo->sinfo_flags = $6;
	$$->value.sctp_extrcvinfo->sinfo_ppid = $8;
	$$->value.sctp_extrcvinfo->sinfo_context = $10;
	$$->value.sctp_extrcvinfo->sinfo_pr_value = $12;
	$$->value.sctp_extrcvinfo->sinfo_tsn = $14;
	$$->value.sctp_extrcvinfo->sinfo_cumtsn = $16;
	$$->value.sctp_extrcvinfo->serinfo_next_flags = $18;
	$$->value.sctp_extrcvinfo->serinfo_next_stream = $20;
	$$->value.sctp_extrcvinfo->serinfo_next_aid = $22;
	$$->value.sctp_extrcvinfo->serinfo_next_length = $24;
	$$->value.sctp_extrcvinfo->serinfo_next_ppid = $26;
	$$->value.sctp_extrcvinfo->sinfo_assoc_id = new_expression(EXPR_ELLIPSIS);
};

rcv_sid
: RCV_SID '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("rcv_sid out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| RCV_SID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

rcv_ssn
: RCV_SSN '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("rcv_ssn out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| RCV_SSN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

rcv_flags
: RCV_FLAGS '=' expression { $$ = $3; }
;

rcv_ppid
: RCV_PPID '=' _HTONL_ '(' INTEGER ')' {
	if (!is_valid_u32($5)) {
		semantic_error("rcv_ppid out of range");
	}
	$$ = new_integer_expression(htonl($5), "%u");
}
| RCV_PPID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

rcv_tsn
: RCV_TSN '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("rcv_tsn out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| RCV_TSN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

rcv_cumtsn
: RCV_CUMTSN '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("rcv_cumtsn out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| RCV_CUMTSN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

rcv_context
: RCV_CONTEXT '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("rcv_context out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| RCV_CONTEXT '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_rcvinfo
: '{' rcv_sid ',' rcv_ssn ',' rcv_flags ',' rcv_ppid ',' rcv_tsn ',' rcv_cumtsn ',' rcv_context ',' RCV_ASSOC_ID '=' sctp_assoc_id'}' {
	$$ = new_expression(EXPR_SCTP_RCVINFO);
	$$->value.sctp_rcvinfo = calloc(1, sizeof(struct sctp_rcvinfo_expr));
	$$->value.sctp_rcvinfo->rcv_sid = $2;
	$$->value.sctp_rcvinfo->rcv_ssn = $4;
	$$->value.sctp_rcvinfo->rcv_flags = $6;
	$$->value.sctp_rcvinfo->rcv_ppid = $8;
	$$->value.sctp_rcvinfo->rcv_tsn = $10;
	$$->value.sctp_rcvinfo->rcv_cumtsn = $12;
	$$->value.sctp_rcvinfo->rcv_context = $14;
	$$->value.sctp_rcvinfo->rcv_assoc_id = $18;
}
| '{' rcv_sid ',' rcv_ssn ',' rcv_flags ',' rcv_ppid ',' rcv_tsn ',' rcv_cumtsn ',' rcv_context '}' {
	$$ = new_expression(EXPR_SCTP_RCVINFO);
	$$->value.sctp_rcvinfo = calloc(1, sizeof(struct sctp_rcvinfo_expr));
	$$->value.sctp_rcvinfo->rcv_sid = $2;
	$$->value.sctp_rcvinfo->rcv_ssn = $4;
	$$->value.sctp_rcvinfo->rcv_flags = $6;
	$$->value.sctp_rcvinfo->rcv_ppid = $8;
	$$->value.sctp_rcvinfo->rcv_tsn = $10;
	$$->value.sctp_rcvinfo->rcv_cumtsn = $12;
	$$->value.sctp_rcvinfo->rcv_context = $14;
	$$->value.sctp_rcvinfo->rcv_assoc_id = new_expression(EXPR_ELLIPSIS);
}
;

pr_policy
: PR_POLICY '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| PR_POLICY '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("pr_policy out of range");
	}
	$$ = new_integer_expression($3, "%hu");
};

sctp_default_prinfo
: '{' pr_policy ',' PR_VALUE '=' INTEGER ',' PR_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_DEFAULT_PRINFO);
	$$->value.sctp_default_prinfo = calloc(1, sizeof(struct sctp_default_prinfo_expr));
	$$->value.sctp_default_prinfo->pr_policy = $2;
	if (!is_valid_u32($6)) {
		semantic_error("pr_value out of range");
	}
	$$->value.sctp_default_prinfo->pr_value = new_integer_expression($6, "%u");
	$$->value.sctp_default_prinfo->pr_assoc_id = $10;
}
;

sctp_prinfo
: '{' pr_policy ',' PR_VALUE '=' INTEGER '}' {
	$$ = new_expression(EXPR_SCTP_PRINFO);
	$$->value.sctp_prinfo = calloc(1, sizeof(struct sctp_prinfo_expr));
	$$->value.sctp_prinfo->pr_policy = $2;
	if (!is_valid_u32($6)) {
		semantic_error("pr_value out of range");
	}
	$$->value.sctp_prinfo->pr_value = new_integer_expression($6, "%u");
}
;

sctp_authinfo
: '{' AUTH_KEYNUMBER '=' INTEGER '}' {
	$$ = new_expression(EXPR_SCTP_AUTHINFO);
	$$->value.sctp_authinfo = calloc(1, sizeof(struct sctp_authinfo_expr));
	if (!is_valid_u16($4)) {
		semantic_error("auth_keynumber out of range");
	}
	$$->value.sctp_authinfo->auth_keynumber = new_integer_expression($4, "%hu");
}
;

sctp_sendv_spa
: '{' SENDV_FLAGS '=' expression ',' SENDV_SNDINFO '=' expression ',' SENDV_PRINFO '=' expression ',' SENDV_AUTHINFO '=' expression '}' {
	$$ = new_expression(EXPR_SCTP_SENDV_SPA);
	$$->value.sctp_sendv_spa = calloc(1, sizeof(struct sctp_sendv_spa_expr));
	$$->value.sctp_sendv_spa->sendv_flags = $4;
	$$->value.sctp_sendv_spa->sendv_sndinfo = $8;
	$$->value.sctp_sendv_spa->sendv_prinfo = $12;
	$$->value.sctp_sendv_spa->sendv_authinfo = $16;
}
;

nxt_sid
: NXT_SID '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("nxt_sid out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| NXT_SID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

nxt_flags
: NXT_FLAGS '=' expression { $$ = $3; }
;

nxt_ppid
: NXT_PPID '=' _HTONL_ '(' INTEGER ')' {
	if (!is_valid_u32($5)) {
		semantic_error("nxt_ppid out of range");
	}
	$$ = new_integer_expression(htonl((u32)$5), "%u");
}
| NXT_PPID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

nxt_length
: NXT_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("nxt_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| NXT_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_nxtinfo
: '{' nxt_sid ',' nxt_flags ',' nxt_ppid ',' nxt_length ',' NXT_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_NXTINFO);
	$$->value.sctp_nxtinfo = calloc(1, sizeof(struct sctp_nxtinfo_expr));
	$$->value.sctp_nxtinfo->nxt_sid = $2;
	$$->value.sctp_nxtinfo->nxt_flags = $4;
	$$->value.sctp_nxtinfo->nxt_ppid = $6;
	$$->value.sctp_nxtinfo->nxt_length = $8;
	$$->value.sctp_nxtinfo->nxt_assoc_id = $12;
}
| '{' nxt_sid ',' nxt_flags ',' nxt_ppid ',' nxt_length '}' {
	$$ = new_expression(EXPR_SCTP_NXTINFO);
	$$->value.sctp_nxtinfo = calloc(1, sizeof(struct sctp_nxtinfo_expr));
	$$->value.sctp_nxtinfo->nxt_sid = $2;
	$$->value.sctp_nxtinfo->nxt_flags = $4;
	$$->value.sctp_nxtinfo->nxt_ppid = $6;
	$$->value.sctp_nxtinfo->nxt_length = $8;
	$$->value.sctp_nxtinfo->nxt_assoc_id = new_expression(EXPR_ELLIPSIS);
}
;

sctp_recvv_rn
: '{' RECVV_RCVINFO '=' expression ',' RECVV_NXTINFO '=' expression '}' {
	$$ = new_expression(EXPR_SCTP_RECVV_RN);
	$$->value.sctp_recvv_rn = calloc(1, sizeof(struct sctp_recvv_rn_expr));
	$$->value.sctp_recvv_rn->recvv_rcvinfo = $4;
	$$->value.sctp_recvv_rn->recvv_nxtinfo = $8;
}
;

sse_type
: SSE_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sse_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSE_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SSE_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sse_flags
: SSE_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sse_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSE_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sse_length
: SSE_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sse_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SSE_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_shutdown_event
: '{' sse_type ',' sse_flags ',' sse_length ',' SSE_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_SHUTDOWN_EVENT);
	$$->value.sctp_shutdown_event = calloc(1, sizeof(struct sctp_shutdown_event_expr));
	$$->value.sctp_shutdown_event->sse_type = $2;
	$$->value.sctp_shutdown_event->sse_flags = $4;
	$$->value.sctp_shutdown_event->sse_length = $6;
	$$->value.sctp_shutdown_event->sse_assoc_id = $10;
}
| '{' sse_type ',' sse_flags ',' sse_length '}' {
	$$ = new_expression(EXPR_SCTP_SHUTDOWN_EVENT);
	$$->value.sctp_shutdown_event = calloc(1, sizeof(struct sctp_shutdown_event_expr));
	$$->value.sctp_shutdown_event->sse_type = $2;
	$$->value.sctp_shutdown_event->sse_flags = $4;
	$$->value.sctp_shutdown_event->sse_length = $6;
	$$->value.sctp_shutdown_event->sse_assoc_id = new_expression(EXPR_ELLIPSIS);
};

pdapi_type
: PDAPI_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("pdapi_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| PDAPI_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| PDAPI_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;
pdapi_flags
: PDAPI_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("pdapi_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| PDAPI_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

pdapi_length
: PDAPI_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("pdapi_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| PDAPI_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

pdapi_indication
: PDAPI_INDICATION '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("pdapi_indication out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| PDAPI_INDICATION '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| PDAPI_INDICATION '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

pdapi_stream
: PDAPI_STREAM '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("pdapi_stream out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| PDAPI_STREAM '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

pdapi_seq
: PDAPI_SEQ '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("pdapi_seq out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| PDAPI_SEQ '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_pdapi_event
: '{' pdapi_type',' pdapi_flags ',' pdapi_length ',' pdapi_indication ',' pdapi_stream ',' pdapi_seq ',' PDAPI_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_PDAPI_EVENT);
	$$->value.sctp_pdapi_event = calloc(1, sizeof(struct sctp_pdapi_event_expr));
	$$->value.sctp_pdapi_event->pdapi_type = $2;
	$$->value.sctp_pdapi_event->pdapi_flags = $4;
	$$->value.sctp_pdapi_event->pdapi_length = $6;
	$$->value.sctp_pdapi_event->pdapi_indication = $8;
	$$->value.sctp_pdapi_event->pdapi_stream = $10;
	$$->value.sctp_pdapi_event->pdapi_seq = $12;
	$$->value.sctp_pdapi_event->pdapi_assoc_id = $16;
}
| '{' pdapi_type',' pdapi_flags ',' pdapi_length ',' pdapi_indication ',' pdapi_stream ',' pdapi_seq '}' {
	$$ = new_expression(EXPR_SCTP_PDAPI_EVENT);
	$$->value.sctp_pdapi_event = calloc(1, sizeof(struct sctp_pdapi_event_expr));
	$$->value.sctp_pdapi_event->pdapi_type = $2;
	$$->value.sctp_pdapi_event->pdapi_flags = $4;
	$$->value.sctp_pdapi_event->pdapi_length = $6;
	$$->value.sctp_pdapi_event->pdapi_indication = $8;
	$$->value.sctp_pdapi_event->pdapi_stream = $10;
	$$->value.sctp_pdapi_event->pdapi_seq = $12;
	$$->value.sctp_pdapi_event->pdapi_assoc_id = new_expression(EXPR_ELLIPSIS);
}
;

auth_type
: AUTH_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("auth_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| AUTH_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| AUTH_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

auth_flags
: AUTH_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("auth_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| AUTH_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

auth_length
: AUTH_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("auth_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| AUTH_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

auth_keynumber
: AUTH_KEYNUMBER '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("auth_keynumber out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| AUTH_KEYNUMBER '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

auth_indication
: AUTH_INDICATION '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("auth_indication out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| AUTH_INDICATION '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| AUTH_INDICATION '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_authkey_event
: '{' auth_type ',' auth_flags ',' auth_length ',' auth_keynumber ',' auth_indication ',' AUTH_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_AUTHKEY_EVENT);
	$$->value.sctp_authkey_event = calloc(1, sizeof(struct sctp_authkey_event_expr));
	$$->value.sctp_authkey_event->auth_type = $2;
	$$->value.sctp_authkey_event->auth_flags = $4;
	$$->value.sctp_authkey_event->auth_length = $6;
	$$->value.sctp_authkey_event->auth_keynumber = $8;
	$$->value.sctp_authkey_event->auth_indication = $10;
	$$->value.sctp_authkey_event->auth_assoc_id = $14;
}
| '{' auth_type ',' auth_flags ',' auth_length ',' auth_keynumber ',' auth_indication '}' {
	$$ = new_expression(EXPR_SCTP_AUTHKEY_EVENT);
	$$->value.sctp_authkey_event = calloc(1, sizeof(struct sctp_authkey_event_expr));
	$$->value.sctp_authkey_event->auth_type = $2;
	$$->value.sctp_authkey_event->auth_flags = $4;
	$$->value.sctp_authkey_event->auth_length = $6;
	$$->value.sctp_authkey_event->auth_keynumber = $8;
	$$->value.sctp_authkey_event->auth_indication = $10;
	$$->value.sctp_authkey_event->auth_assoc_id = new_expression(EXPR_ELLIPSIS);
}
;

sender_dry_type
: SENDER_DRY_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sender_dry_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SENDER_DRY_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SENDER_DRY_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sender_dry_flags
: SENDER_DRY_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sender_dry_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SENDER_DRY_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sender_dry_length
: SENDER_DRY_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sender_dry_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SENDER_DRY_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_sender_dry_event
: '{'sender_dry_type ',' sender_dry_flags ',' sender_dry_length ',' SENDER_DRY_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_SENDER_DRY_EVENT);
	$$->value.sctp_sender_dry_event = calloc(1, sizeof(struct sctp_sender_dry_event_expr));
	$$->value.sctp_sender_dry_event->sender_dry_type = $2;
	$$->value.sctp_sender_dry_event->sender_dry_flags = $4;
	$$->value.sctp_sender_dry_event->sender_dry_length = $6;
	$$->value.sctp_sender_dry_event->sender_dry_assoc_id = $10;
}
| '{'sender_dry_type ',' sender_dry_flags ',' sender_dry_length '}' {
	$$ = new_expression(EXPR_SCTP_SENDER_DRY_EVENT);
	$$->value.sctp_sender_dry_event = calloc(1, sizeof(struct sctp_sender_dry_event_expr));
	$$->value.sctp_sender_dry_event->sender_dry_type = $2;
	$$->value.sctp_sender_dry_event->sender_dry_flags = $4;
	$$->value.sctp_sender_dry_event->sender_dry_length = $6;
	$$->value.sctp_sender_dry_event->sender_dry_assoc_id = new_expression(EXPR_ELLIPSIS);
}
;

ssfe_type
: SSFE_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("ssfe_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSFE_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SSFE_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

ssfe_flags
: SSFE_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("ssfe_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSFE_FLAGS '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SSFE_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

ssfe_length
: SSFE_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("ssfe_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SSFE_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

ssfe_error
: SSFE_ERROR '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("ssfe_error out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SSFE_ERROR '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

ssfe_data
: SSFE_DATA '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| SSFE_DATA '=' array    { $$ = $3; }
;

sctp_send_failed_event
: '{' ssfe_type ',' ssfe_flags ',' ssfe_length ',' ssfe_error ',' SSFE_INFO '=' sctp_sndinfo ',' SSFE_ASSOC_ID '=' sctp_assoc_id ',' ssfe_data '}' {
	$$ = new_expression(EXPR_SCTP_SEND_FAILED_EVENT);
	$$->value.sctp_send_failed_event = calloc(1, sizeof(struct sctp_send_failed_event_expr));
	$$->value.sctp_send_failed_event->ssfe_type = $2;
	$$->value.sctp_send_failed_event->ssfe_flags = $4;
	$$->value.sctp_send_failed_event->ssfe_length = $6;
	$$->value.sctp_send_failed_event->ssfe_error = $8;
	$$->value.sctp_send_failed_event->ssfe_info = $12;
	$$->value.sctp_send_failed_event->ssfe_assoc_id = $16;
	$$->value.sctp_send_failed_event->ssfe_data = $18;
}
| '{' ssfe_type ',' ssfe_flags ',' ssfe_length ',' ssfe_error ',' SSFE_INFO '=' sctp_sndinfo ',' ssfe_data '}' {
	$$ = new_expression(EXPR_SCTP_SEND_FAILED_EVENT);
	$$->value.sctp_send_failed_event = calloc(1, sizeof(struct sctp_send_failed_event_expr));
	$$->value.sctp_send_failed_event->ssfe_type = $2;
	$$->value.sctp_send_failed_event->ssfe_flags = $4;
	$$->value.sctp_send_failed_event->ssfe_length = $6;
	$$->value.sctp_send_failed_event->ssfe_error = $8;
	$$->value.sctp_send_failed_event->ssfe_info = $12;
	$$->value.sctp_send_failed_event->ssfe_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_send_failed_event->ssfe_data = $14;
};

sac_type
: SAC_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sac_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SAC_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SAC_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sac_flags
: SAC_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sac_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SAC_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sac_length
: SAC_LENGTH '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sac_length out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SAC_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sac_state
: SAC_STATE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sac_state out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SAC_STATE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SAC_STATE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sac_error
: SAC_ERROR '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sac_error out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SAC_ERROR '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sac_outbound_streams
: SAC_OUTBOUND_STREAMS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sac_outbound_streams out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SAC_OUTBOUND_STREAMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sac_inbound_streams
: SAC_INBOUND_STREAMS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sac_inbound_streams out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SAC_INBOUND_STREAMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sac_info
: SAC_INFO '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| SAC_INFO '=' array { $$ = $3; }
;

sctp_assoc_change
: '{' sac_type ',' sac_flags ',' sac_length ',' sac_state ',' sac_error ',' sac_outbound_streams ','
sac_inbound_streams ',' SAC_ASSOC_ID '=' sctp_assoc_id ',' sac_info '}' {
	$$ = new_expression(EXPR_SCTP_ASSOC_CHANGE);
	$$->value.sctp_assoc_change = calloc(1, sizeof(struct sctp_assoc_change_expr));
	$$->value.sctp_assoc_change->sac_type = $2;
	$$->value.sctp_assoc_change->sac_flags = $4;
	$$->value.sctp_assoc_change->sac_length = $6;
	$$->value.sctp_assoc_change->sac_state = $8;
	$$->value.sctp_assoc_change->sac_error = $10;
	$$->value.sctp_assoc_change->sac_outbound_streams = $12;
	$$->value.sctp_assoc_change->sac_inbound_streams = $14;
	$$->value.sctp_assoc_change->sac_assoc_id = $18;
	$$->value.sctp_assoc_change->sac_info = $20;
}
| '{' sac_type ',' sac_flags ',' sac_length ',' sac_state ',' sac_error ',' sac_outbound_streams ','
sac_inbound_streams ',' sac_info '}' {
	$$ = new_expression(EXPR_SCTP_ASSOC_CHANGE);
	$$->value.sctp_assoc_change = calloc(1, sizeof(struct sctp_assoc_change_expr));
	$$->value.sctp_assoc_change->sac_type = $2;
	$$->value.sctp_assoc_change->sac_flags = $4;
	$$->value.sctp_assoc_change->sac_length = $6;
	$$->value.sctp_assoc_change->sac_state = $8;
	$$->value.sctp_assoc_change->sac_error = $10;
	$$->value.sctp_assoc_change->sac_outbound_streams = $12;
	$$->value.sctp_assoc_change->sac_inbound_streams = $14;
	$$->value.sctp_assoc_change->sac_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_assoc_change->sac_info = $16;
}
;

sre_type
: SRE_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sre_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SRE_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SRE_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sre_flags
: SRE_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sre_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SRE_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sre_length
: SRE_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sre_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SRE_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sre_error
: SRE_ERROR '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sre_error out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SRE_ERROR '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sre_data
: SRE_DATA '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| SRE_DATA '=' array { $$ = $3; }
;

sctp_remote_error
: '{' sre_type ',' sre_flags ',' sre_length ',' sre_error ',' SRE_ASSOC_ID '=' sctp_assoc_id ',' sre_data '}' {
	$$ = new_expression(EXPR_SCTP_REMOTE_ERROR);
	$$->value.sctp_remote_error = calloc(1, sizeof(struct sctp_remote_error_expr));
	$$->value.sctp_remote_error->sre_type = $2;
	$$->value.sctp_remote_error->sre_flags = $4;
	$$->value.sctp_remote_error->sre_length = $6;
	$$->value.sctp_remote_error->sre_error = $8;
	$$->value.sctp_remote_error->sre_assoc_id = $12;
	$$->value.sctp_remote_error->sre_data = $14;
}
| '{' sre_type ',' sre_flags ',' sre_length ',' sre_error ',' sre_data '}' {
	$$ = new_expression(EXPR_SCTP_REMOTE_ERROR);
	$$->value.sctp_remote_error = calloc(1, sizeof(struct sctp_remote_error_expr));
	$$->value.sctp_remote_error->sre_type = $2;
	$$->value.sctp_remote_error->sre_flags = $4;
	$$->value.sctp_remote_error->sre_length = $6;
	$$->value.sctp_remote_error->sre_error = $8;
	$$->value.sctp_remote_error->sre_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_remote_error->sre_data = $10;
}
;

spc_type
: SPC_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("spc_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SPC_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SPC_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spc_flags
: SPC_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("spc_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SPC_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spc_length
: SPC_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spc_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPC_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spc_aaddr
: SPC_AADDR '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| SPC_AADDR '=' sockaddr { $$ = $3; }
;

spc_state
: SPC_STATE '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spc_state out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPC_STATE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SPC_STATE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

spc_error
: SPC_ERROR '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("spc_error out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SPC_ERROR '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SPC_ERROR '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_paddr_change
: '{' spc_type ',' spc_flags ',' spc_length ',' spc_aaddr ',' spc_state ',' spc_error ',' SPC_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_PADDR_CHANGE);
	$$->value.sctp_paddr_change = calloc(1, sizeof(struct sctp_paddr_change_expr));
	$$->value.sctp_paddr_change->spc_type = $2;
	$$->value.sctp_paddr_change->spc_flags = $4;
	$$->value.sctp_paddr_change->spc_length = $6;
	$$->value.sctp_paddr_change->spc_aaddr = $8;
	$$->value.sctp_paddr_change->spc_state = $10;
	$$->value.sctp_paddr_change->spc_error = $12;
	$$->value.sctp_paddr_change->spc_assoc_id = $16;
}
| '{' spc_type ',' spc_flags ',' spc_length ',' spc_aaddr ',' spc_state ',' spc_error '}' {
	$$ = new_expression(EXPR_SCTP_PADDR_CHANGE);
	$$->value.sctp_paddr_change = calloc(1, sizeof(struct sctp_paddr_change_expr));
	$$->value.sctp_paddr_change->spc_type = $2;
	$$->value.sctp_paddr_change->spc_flags = $4;
	$$->value.sctp_paddr_change->spc_length = $6;
	$$->value.sctp_paddr_change->spc_aaddr = $8;
	$$->value.sctp_paddr_change->spc_state = $10;
	$$->value.sctp_paddr_change->spc_error = $12;
	$$->value.sctp_paddr_change->spc_assoc_id = new_expression(EXPR_ELLIPSIS);
}
;
ssf_type
: SSF_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("ssf_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSF_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SSF_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

ssf_length
: SSF_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("ssf_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SSF_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

ssf_flags
: SSF_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("ssf_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SSF_FLAGS '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SSF_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

ssf_error
: SSF_ERROR '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("ssf_error out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SSF_ERROR '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SSF_ERROR '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

ssf_info
: SSF_INFO '=' sctp_sndrcvinfo { $$ = $3; }
| SSF_INFO '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

ssf_data
: SSF_DATA '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| SSF_DATA '=' array { $$ = $3; }
;

sctp_send_failed
: '{' ssf_type ',' ssf_flags ',' ssf_length ',' ssf_error ',' ssf_info ',' SSF_ASSOC_ID '=' sctp_assoc_id ',' ssf_data '}' {
	$$ = new_expression(EXPR_SCTP_SEND_FAILED);
	$$->value.sctp_send_failed = calloc(1, sizeof(struct sctp_send_failed_expr));
	$$->value.sctp_send_failed->ssf_type = $2;
	$$->value.sctp_send_failed->ssf_flags = $4;
	$$->value.sctp_send_failed->ssf_length = $6;
	$$->value.sctp_send_failed->ssf_error = $8;
	$$->value.sctp_send_failed->ssf_info = $10;
	$$->value.sctp_send_failed->ssf_assoc_id = $14;
	$$->value.sctp_send_failed->ssf_data = $16;
}
| '{' ssf_type ',' ssf_flags ',' ssf_length ',' ssf_error ',' ssf_info ',' ssf_data '}' {
	$$ = new_expression(EXPR_SCTP_SEND_FAILED);
	$$->value.sctp_send_failed = calloc(1, sizeof(struct sctp_send_failed_expr));
	$$->value.sctp_send_failed->ssf_type = $2;
	$$->value.sctp_send_failed->ssf_flags = $4;
	$$->value.sctp_send_failed->ssf_length = $6;
	$$->value.sctp_send_failed->ssf_error = $8;
	$$->value.sctp_send_failed->ssf_info = $10;
	$$->value.sctp_send_failed->ssf_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_send_failed->ssf_data = $12;
}
;

sai_type
: SAI_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sai_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SAI_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SAI_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sai_flags
: SAI_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sai_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SAI_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sai_length
: SAI_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sai_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SAI_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sai_adaptation_ind
: SAI_ADAPTATION_IND '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sai_adaptation_ind out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SAI_ADAPTATION_IND '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_adaptation_event
: '{' sai_type ',' sai_flags ',' sai_length ',' sai_adaptation_ind ',' SAI_ASSOC_ID '=' sctp_assoc_id '}' {
	$$ = new_expression(EXPR_SCTP_ADAPTATION_EVENT);
	$$->value.sctp_adaptation_event = calloc(1, sizeof(struct sctp_adaptation_event_expr));
	$$->value.sctp_adaptation_event->sai_type = $2;
	$$->value.sctp_adaptation_event->sai_flags = $4;
	$$->value.sctp_adaptation_event->sai_length = $6;
	$$->value.sctp_adaptation_event->sai_adaptation_ind = $8;
	$$->value.sctp_adaptation_event->sai_assoc_id = $12;
}
| '{' sai_type ',' sai_flags ',' sai_length ',' sai_adaptation_ind '}' {
	$$ = new_expression(EXPR_SCTP_ADAPTATION_EVENT);
	$$->value.sctp_adaptation_event = calloc(1, sizeof(struct sctp_adaptation_event_expr));
	$$->value.sctp_adaptation_event->sai_type = $2;
	$$->value.sctp_adaptation_event->sai_flags = $4;
	$$->value.sctp_adaptation_event->sai_length = $6;
	$$->value.sctp_adaptation_event->sai_adaptation_ind = $8;
	$$->value.sctp_adaptation_event->sai_assoc_id = new_expression(EXPR_ELLIPSIS);
}
;

sn_type
: SN_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sn_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SN_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SN_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sn_flags
: SN_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("sn_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SN_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sn_length
: SN_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("sn_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| SN_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_tlv
: '{' sn_type ',' sn_flags ',' sn_length '}' {
	$$ = new_expression(EXPR_SCTP_TLV);
	$$->value.sctp_tlv = calloc(1, sizeof(struct sctp_tlv_expr));
	$$->value.sctp_tlv->sn_type = $2;
	$$->value.sctp_tlv->sn_flags = $4;
	$$->value.sctp_tlv->sn_length = $6;
}
;

gaids_number_of_ids
: GAIDS_NUMBER_OF_IDS '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("gaids_number_of_ids out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| GAIDS_NUMBER_OF_IDS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_assoc_ids
: '{' gaids_number_of_ids ',' GAIDS_ASSOC_ID '=' array '}' {
	$$ = new_expression(EXPR_SCTP_ASSOC_IDS);
	$$->value.sctp_assoc_ids = calloc(1, sizeof(struct sctp_assoc_ids_expr));
	$$->value.sctp_assoc_ids->gaids_number_of_ids = $2;
	$$->value.sctp_assoc_ids->gaids_assoc_id = $6;
};

gauth_number_of_chunks
: GAUTH_NUMBER_OF_CHUNKS '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("gauth_number_of_chunks out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| GAUTH_NUMBER_OF_CHUNKS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_authchunks
: '{' GAUTH_ASSOC_ID '=' sctp_assoc_id ',' gauth_number_of_chunks ',' GAUTH_CHUNKS '=' array '}' {
	$$ = new_expression(EXPR_SCTP_AUTHCHUNKS);
	$$->value.sctp_authchunks = calloc(1, sizeof(struct sctp_authchunks_expr));
	$$->value.sctp_authchunks->gauth_assoc_id = $4;
	$$->value.sctp_authchunks->gauth_number_of_chunks = $6;
	$$->value.sctp_authchunks->gauth_chunks = $10;
}
| '{' gauth_number_of_chunks ',' GAUTH_CHUNKS '=' array '}' {
	$$ = new_expression(EXPR_SCTP_AUTHCHUNKS);
	$$->value.sctp_authchunks = calloc(1, sizeof(struct sctp_authchunks_expr));
	$$->value.sctp_authchunks->gauth_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_authchunks->gauth_number_of_chunks = $2;
	$$->value.sctp_authchunks->gauth_chunks = $6;
};

sctp_setpeerprim
: '{' SSPP_ASSOC_ID '=' sctp_assoc_id ',' SSPP_ADDR '=' sockaddr '}' {
	$$ = new_expression(EXPR_SCTP_SETPEERPRIM);
	$$->value.sctp_setpeerprim = calloc(1, sizeof(struct sctp_setpeerprim_expr));
	$$->value.sctp_setpeerprim->sspp_assoc_id = $4;
	$$->value.sctp_setpeerprim->sspp_addr = $8;
}
| '{' SSPP_ADDR '=' sockaddr '}' {
	$$ = new_expression(EXPR_SCTP_SETPEERPRIM);
	$$->value.sctp_setpeerprim = calloc(1, sizeof(struct sctp_setpeerprim_expr));
	$$->value.sctp_setpeerprim->sspp_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_setpeerprim->sspp_addr = $4;
};

sctp_authchunk
: '{' SAUTH_CHUNK '=' INTEGER '}' {
	$$ = new_expression(EXPR_SCTP_AUTHCHUNK);
	$$->value.sctp_authchunk = calloc(1, sizeof(struct sctp_authchunk_expr));
	if (!is_valid_u8($4)) {
		semantic_error("sauth_chunk out of range");
	}
	$$->value.sctp_authchunk->sauth_chunk = new_integer_expression($4, "%hhu");
};

sctp_authkey
: '{' SCA_ASSOC_ID '=' sctp_assoc_id ',' SCA_KEYNUMBER '=' INTEGER ',' SCA_KEYLENGTH '=' INTEGER ',' SCA_KEY '=' array '}' {
	$$ = new_expression(EXPR_SCTP_AUTHKEY);
	$$->value.sctp_authkey = calloc(1, sizeof(struct sctp_authkey_expr));
	$$->value.sctp_authkey->sca_assoc_id = $4;
	if (!is_valid_u16($8)) {
		semantic_error("sca_keynumber out of range");
	}
	$$->value.sctp_authkey->sca_keynumber = new_integer_expression($8, "%hu");
	if (!is_valid_u16($12)) {
		semantic_error("sca_keylength out of range");
	}
	$$->value.sctp_authkey->sca_keylength = new_integer_expression($12, "%hu");
	$$->value.sctp_authkey->sca_key = $16;
}
| '{' SCA_KEYNUMBER '=' INTEGER ',' SCA_KEYLENGTH '=' INTEGER ',' SCA_KEY '=' array '}' {
	$$ = new_expression(EXPR_SCTP_AUTHKEY);
	$$->value.sctp_authkey = calloc(1, sizeof(struct sctp_authkey_expr));
	$$->value.sctp_authkey->sca_assoc_id = new_expression(EXPR_ELLIPSIS);
	if (!is_valid_u16($4)) {
		semantic_error("sca_keynumber out of range");
	}
	$$->value.sctp_authkey->sca_keynumber = new_integer_expression($4, "%hu");
	if (!is_valid_u16($8)) {
		semantic_error("sca_keylength out of range");
	}
	$$->value.sctp_authkey->sca_keylength = new_integer_expression($8, "%hu");
	$$->value.sctp_authkey->sca_key = $12;
};

srs_flags
: SRS_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("srs_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| SRS_FLAGS '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| SRS_FLAGS '=' binary_expression {
	$$ = $3;
}
;

sctp_reset_streams
: '{' SRS_ASSOC_ID '=' sctp_assoc_id ',' srs_flags ',' SRS_NUMBER_STREAMS '=' INTEGER ',' SRS_STREAM_LIST '=' array '}' {
	$$ = new_expression(EXPR_SCTP_RESET_STREAMS);
	$$->value.sctp_reset_streams = calloc(1, sizeof(struct sctp_reset_streams_expr));
	$$->value.sctp_reset_streams->srs_assoc_id = $4;
	$$->value.sctp_reset_streams->srs_flags = $6;
	if (!is_valid_u16($10)) {
		semantic_error("srs_number_streams out of range");
	}
	$$->value.sctp_reset_streams->srs_number_streams = new_integer_expression($10, "%hu");
	$$->value.sctp_reset_streams->srs_stream_list = $14;
}
| '{' srs_flags ',' SRS_NUMBER_STREAMS '=' INTEGER ',' SRS_STREAM_LIST '=' array '}' {
	$$ = new_expression(EXPR_SCTP_RESET_STREAMS);
	$$->value.sctp_reset_streams = calloc(1, sizeof(struct sctp_reset_streams_expr));
	$$->value.sctp_reset_streams->srs_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_reset_streams->srs_flags = $2;
	if (!is_valid_u16($6)) {
		semantic_error("srs_number_streams out of range");
	}
	$$->value.sctp_reset_streams->srs_number_streams = new_integer_expression($6, "%hu");
	$$->value.sctp_reset_streams->srs_stream_list = $10;
}
;

sctp_add_streams
: '{' SAS_ASSOC_ID '=' sctp_assoc_id ',' SAS_INSTRMS '=' INTEGER ',' SAS_OUTSTRMS '=' INTEGER '}' {
	$$ = new_expression(EXPR_SCTP_ADD_STREAMS);
	$$->value.sctp_add_streams = calloc(1, sizeof(struct sctp_add_streams_expr));
	$$->value.sctp_add_streams->sas_assoc_id = $4;
	if (!is_valid_u16($8)) {
		semantic_error("sas_instrms out of range");
	}
	$$->value.sctp_add_streams->sas_instrms = new_integer_expression($8, "%hu");
	if (!is_valid_u16($12)) {
		semantic_error("sas_outstrms out of range");
	}
	$$->value.sctp_add_streams->sas_outstrms = new_integer_expression($12, "%hu");
}
| '{' SAS_INSTRMS '=' INTEGER ',' SAS_OUTSTRMS '=' INTEGER '}' {
	$$ = new_expression(EXPR_SCTP_ADD_STREAMS);
	$$->value.sctp_add_streams = calloc(1, sizeof(struct sctp_add_streams_expr));
	$$->value.sctp_add_streams->sas_assoc_id = new_expression(EXPR_ELLIPSIS);
	if (!is_valid_u16($4)) {
		semantic_error("sas_instrms out of range");
	}
	$$->value.sctp_add_streams->sas_instrms = new_integer_expression($4, "%hu");
	if (!is_valid_u16($8)) {
		semantic_error("sas_outstrms out of range");
	}
	$$->value.sctp_add_streams->sas_outstrms = new_integer_expression($8, "%hu");
}
;

strreset_type
: STRRESET_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("strreset_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| STRRESET_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| STRRESET_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

strreset_flags
: STRRESET_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("strreset_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| STRRESET_FLAGS '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| STRRESET_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| STRRESET_FLAGS '=' binary_expression { $$ = $3; }
;

strreset_length
: STRRESET_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("strreset_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| STRRESET_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_stream_reset_event
: '{' strreset_type ',' strreset_flags ',' strreset_length ',' STRRESET_ASSOC_ID '=' sctp_assoc_id ',' STRRESET_STREAM_LIST '=' array '}' {
	$$ = new_expression(EXPR_SCTP_STREAM_RESET_EVENT);
	$$->value.sctp_stream_reset_event = calloc(1, sizeof(struct sctp_stream_reset_event_expr));
	$$->value.sctp_stream_reset_event->strreset_type = $2;
	$$->value.sctp_stream_reset_event->strreset_flags = $4;
	$$->value.sctp_stream_reset_event->strreset_length = $6;
	$$->value.sctp_stream_reset_event->strreset_assoc_id = $10;
	$$->value.sctp_stream_reset_event->strreset_stream_list = $14;
}
;

assocreset_type
: ASSOCRESET_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("assocreset_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| ASSOCRESET_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| ASSOCRESET_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

assocreset_flags
: ASSOCRESET_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("assocreset_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| ASSOCRESET_FLAGS '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| ASSOCRESET_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| ASSOCRESET_FLAGS '=' binary_expression { $$ = $3; }
;

assocreset_length
: ASSOCRESET_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("assocreset_length out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| ASSOCRESET_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

assocreset_local_tsn
: ASSOCRESET_LOCAL_TSN '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("assocreset_local_tsn out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| ASSOCRESET_LOCAL_TSN '=' HEX_INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("assocreset_local_tsn out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| ASSOCRESET_LOCAL_TSN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

assocreset_remote_tsn
: ASSOCRESET_REMOTE_TSN '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("assocreset_remote_tsn out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| ASSOCRESET_REMOTE_TSN '=' HEX_INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("assocreset_remote_tsn out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| ASSOCRESET_REMOTE_TSN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_assoc_reset_event
: '{' assocreset_type ',' assocreset_flags ',' assocreset_length ',' ASSOCRESET_ASSOC_ID '=' sctp_assoc_id ','
	assocreset_local_tsn ',' assocreset_remote_tsn '}' {
	$$ = new_expression(EXPR_SCTP_ASSOC_RESET_EVENT);
	$$->value.sctp_assoc_reset_event = calloc(1, sizeof(struct sctp_assoc_reset_event_expr));
	$$->value.sctp_assoc_reset_event->assocreset_type = $2;
	$$->value.sctp_assoc_reset_event->assocreset_flags = $4;
	$$->value.sctp_assoc_reset_event->assocreset_length = $6;
	$$->value.sctp_assoc_reset_event->assocreset_assoc_id = $10;
	$$->value.sctp_assoc_reset_event->assocreset_local_tsn = $12;
	$$->value.sctp_assoc_reset_event->assocreset_remote_tsn = $14;
}
;

strchange_type
: STRCHANGE_TYPE '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("strchange_type out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| STRCHANGE_TYPE '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| STRCHANGE_TYPE '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

strchange_flags
: STRCHANGE_FLAGS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("strchange_flags out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| STRCHANGE_FLAGS '=' WORD {
	$$ = new_expression(EXPR_WORD);
	$$->value.string = $3;
}
| STRCHANGE_FLAGS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
| STRCHANGE_FLAGS '=' binary_expression { $$ = $3; }
;

strchange_length
: STRCHANGE_LENGTH '=' INTEGER {
	if (!is_valid_u32($3)) {
		semantic_error("strchange_length out of range");
	}
	$$ = new_integer_expression($3, "%u");
}
| STRCHANGE_LENGTH '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

strchange_instrms
: STRCHANGE_INSTRMS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("strchange_instrms out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| STRCHANGE_INSTRMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

strchange_outstrms
: STRCHANGE_OUTSTRMS '=' INTEGER {
	if (!is_valid_u16($3)) {
		semantic_error("strchange_outstrms out of range");
	}
	$$ = new_integer_expression($3, "%hu");
}
| STRCHANGE_OUTSTRMS '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
;

sctp_stream_change_event
: '{' strchange_type ',' strchange_flags ',' strchange_length ',' STRCHANGE_ASSOC_ID '=' sctp_assoc_id ',' strchange_instrms ',' strchange_outstrms '}' {
	$$ = new_expression(EXPR_SCTP_STREAM_CHANGE_EVENT);
	$$->value.sctp_stream_change_event = calloc(1, sizeof(struct sctp_stream_change_event_expr));
	$$->value.sctp_stream_change_event->strchange_type = $2;
	$$->value.sctp_stream_change_event->strchange_flags = $4;
	$$->value.sctp_stream_change_event->strchange_length = $6;
	$$->value.sctp_stream_change_event->strchange_assoc_id = $10;
	$$->value.sctp_stream_change_event->strchange_instrms = $12;
	$$->value.sctp_stream_change_event->strchange_outstrms = $14;
}
;

sue_address
: SUE_ADDRESS '=' ELLIPSIS {
	$$ = new_expression(EXPR_ELLIPSIS);
}
| SUE_ADDRESS '=' sockaddr {
	$$ = $3;
}
;

sue_port
: SUE_PORT '=' _HTONS_ '(' INTEGER ')' {
	if (!is_valid_u16($5)) {
		semantic_error("sue_port out of range");
	}
	$$ = new_integer_expression(htons($5), "%u");
}
| SUE_PORT '=' ELLIPSIS {
	$$ = new_expression(EXPR_ELLIPSIS);
}
;

sctp_udpencaps
: '{' SUE_ASSOC_ID '=' sctp_assoc_id ',' sue_address ',' sue_port '}' {
	$$ = new_expression(EXPR_SCTP_UDPENCAPS);
	$$->value.sctp_udpencaps = calloc(1, sizeof(struct sctp_udpencaps_expr));
	$$->value.sctp_udpencaps->sue_assoc_id = $4;
	$$->value.sctp_udpencaps->sue_address = $6;
	$$->value.sctp_udpencaps->sue_port = $8;
}
| '{' sue_address ',' sue_port '}' {
	$$ = new_expression(EXPR_SCTP_UDPENCAPS);
	$$->value.sctp_udpencaps = calloc(1, sizeof(struct sctp_udpencaps_expr));
	$$->value.sctp_udpencaps->sue_assoc_id = new_expression(EXPR_ELLIPSIS);
	$$->value.sctp_udpencaps->sue_address = $2;
	$$->value.sctp_udpencaps->sue_port = $4;
}
;

opt_errno
:                   { $$ = NULL; }
| WORD note         {
	$$ = malloc(sizeof(struct errno_spec));
	$$->errno_macro = $1;
	$$->strerror    = $2;
}
;

opt_note
:                   { $$ = NULL; }
| note              { $$ = $1; }
;

note
: '(' word_list ')' { $$ = $2; }
;

word_list
: WORD              { $$ = $1; }
| word_list WORD    { asprintf(&($$), "%s %s", $1, $2); free($1); free($2); }
;

command_spec
: BACK_QUOTED       {
	$$ = malloc(sizeof(struct command_spec));
	$$->command_line = $1;
	current_script_line = yylineno;
}
;

code_spec
: CODE              {
	$$ = calloc(1, sizeof(struct code_spec));
	$$->text = $1;
	current_script_line = yylineno;
}
;

null
: NULL_ {
	$$ = new_expression(EXPR_NULL);
}
;