From 65e035f8af14500053c345deccc82114b9ee3768 Mon Sep 17 00:00:00 2001
From: Michael Tuexen <tuexen@fh-muenster.de>
Date: Tue, 22 Jul 2014 16:00:53 +0200
Subject: [PATCH] packetdrill: add initial support for SCTP socket options.

This commit adds support for the following SCTP socket options:
* SCTP_RTOINFO
* SCTP_INITMSG
* SCTP_NODELAY
* SCTP_MAXSEG
* SCTP_DELAYED_SACK
* SCTP_MAX_BURST

Tested on Linux and FreeBSD. NetBSD and OpenBSD doen't support
SCTP and should not be affected.

Signed-off-by: Michael Tuexen <tuexen@fh-muenster.de>
---
 gtests/net/packetdrill/README                 |  1 +
 gtests/net/packetdrill/contrib/packetdrill.el |  4 +-
 .../net/packetdrill/contrib/packetdrill.vim   |  4 +-
 gtests/net/packetdrill/lexer.l                | 10 ++
 gtests/net/packetdrill/parser.y               | 98 +++++++++++++++++++
 gtests/net/packetdrill/platforms.h            |  2 +
 gtests/net/packetdrill/run_system_call.c      | 19 ++++
 gtests/net/packetdrill/script.c               | 52 ++++++++++
 gtests/net/packetdrill/script.h               | 25 +++++
 gtests/net/packetdrill/symbols_freebsd.c      |  8 ++
 gtests/net/packetdrill/symbols_linux.c        | 22 +++++
 11 files changed, 241 insertions(+), 4 deletions(-)

diff --git a/gtests/net/packetdrill/README b/gtests/net/packetdrill/README
index bfa0a478..026f6b95 100644
--- a/gtests/net/packetdrill/README
+++ b/gtests/net/packetdrill/README
@@ -14,6 +14,7 @@ building
 ========
 
 To build packetdrill, first install flex and bison.
+On Linux you will also need to install the libsctp-dev package.
 
 Then set up the Makefile for your platform:
 
diff --git a/gtests/net/packetdrill/contrib/packetdrill.el b/gtests/net/packetdrill/contrib/packetdrill.el
index 6af4be40..d8c329d0 100644
--- a/gtests/net/packetdrill/contrib/packetdrill.el
+++ b/gtests/net/packetdrill/contrib/packetdrill.el
@@ -1,6 +1,6 @@
-(setq packetdrill-keywords '("sa_family" "sin_port" "sin_addr" "msg_name" "msg_iov" "msg_flags" "fd" "events" "revents" "htons" "icmp" "udp" "inet_addr" "ack" "eol" "ecr" "mss" "mtu" "nop" "sack" "sackOK" "TS" "FO" "LS" "gcn" "minRTO" "val" "win" "wscale" "ect01" "ect0" "ect1" "noecn" "ce" "pro"))
+(setq packetdrill-keywords '("sa_family" "sin_port" "sin_addr" "msg_name" "msg_iov" "msg_flags" "fd" "events" "revents" "htons" "icmp" "udp" "inet_addr" "ack" "eol" "ecr" "mss" "mtu" "nop" "sack" "sackOK" "TS" "FO" "LS" "gcn" "minRTO" "val" "win" "wscale" "ect01" "ect0" "ect1" "noecn" "ce" "pro" "onoff" "linger" "srto_initial" "srto_max" "srto_min" "sinit_num_ostreams" "sinit_max_instreams" "sinit_max_attempts" "sinit_max_init_timeo" "assoc_value" "sack_delay" "sack_freq"))
 
-(setq packetdrill-constants '("AF_INET" "AF_INET6" "PF_INET" "PF_INET6" "SOCK_STREAM" "SOCK_DGRAM" "IPPROTO_IP" "IPPROTO_IPV6" "IPPROTO_ICMP" "IPPROTO_TCP" "IPPROTO_UDP" "SOL_SOCKET" "SOL_IP" "SOL_IPV6" "SOL_TCP" "SOL_UDP" "SO_ACCEPTCONN" "SO_ATTACH_FILTER" "SO_BINDTODEVICE" "SO_BROADCAST" "SO_BSDCOMPAT" "SO_DEBUG" "SO_DETACH_FILTER" "SO_DONTROUTE" "SO_ERROR" "SO_KEEPALIVE" "SO_LINGER" "SO_NO_CHECK" "SO_OOBINLINE" "SO_PASSCRED" "SO_PEERCRED" "SO_PEERNAME" "SO_PEERSEC" "SO_PRIORITY" "SO_RCVBUF" "SO_RCVLOWAT" "SO_RCVTIMEO" "SO_REUSEADDR" "SO_REUSEPORT" "SO_SECURITY_AUTHENTICATION" "SO_SECURITY_ENCRYPTION_NETWORK" "SO_SECURITY_ENCRYPTION_TRANSPORT" "SO_SNDBUF" "SO_SNDLOWAT" "SO_SNDTIMEO" "SO_TIMESTAMP" "SO_TYPE" "IP_TOS" "IP_MTU_DISCOVER" "IP_PMTUDISC_WANT" "IP_PMTUDISC_DONT" "IP_PMTUDISC_DO" "IP_PMTUDISC_PROBE" "IP_MTU" "IPV6_MTU" "TCP_NODELAY" "TCP_MAXSEG" "TCP_CORK" "TCP_KEEPIDLE" "TCP_KEEPINTVL" "TCP_KEEPCNT" "TCP_SYNCNT" "TCP_LINGER2" "TCP_DEFER_ACCEPT" "TCP_WINDOW_CLAMP" "TCP_INFO" "TCP_QUICKACK" "TCP_CONGESTION" "TCP_MD5SIG" "TCP_COOKIE_TRANSACTIONS" "TCP_THIN_LINEAR_TIMEOUTS" "TCP_THIN_DUPACK" "TCP_USER_TIMEOUT" "TCP_MIN_RTO" "TCP_INFO_EXT" "TCP_CWND" "TCP_XMIT_COMPL_SEQ" "TCP_CWND_CLAMP" "TCP_SAVE_SYN" "TCP_SAVED_SYN" "TCP_FASTOPEN" "TCP_MULTIPLE_CONNECTIONS" "O_RDONLY" "O_WRONLY" "O_RDWR" "O_ACCMODE" "O_CREAT" "O_EXCL" "O_NOCTTY" "O_TRUNC" "O_APPEND" "O_NONBLOCK" "F_DUPFD" "F_GETFD" "F_SETFD" "F_GETFL" "F_SETFL" "F_GETLK" "F_SETLK" "F_SETLKW" "F_GETOWN" "F_SETOWN" "F_SETSIG" "F_GETSIG" "F_GETOWN" "F_SETOWN" "F_SETLK" "F_SETLKW" "F_GETLK" "F_SETLK64" "F_SETLKW64" "F_GETLK64" "F_SETLEASE" "F_GETLEASE" "F_NOTIFY" "F_DUPFD_CLOEXEC" "FD_CLOEXEC" "LOCK_SH" "LOCK_EX" "LOCK_NB" "LOCK_UN" "F_RDLCK" "F_WRLCK" "F_UNLCK" "F_EXLCK" "F_SHLCK" "SEEK_SET" "SEEK_CUR" "SEEK_END" "MSG_OOB" "MSG_DONTROUTE" "MSG_PEEK" "MSG_CTRUNC" "MSG_PROXY" "MSG_EOR" "MSG_WAITALL" "MSG_TRUNC" "MSG_CTRUNC" "MSG_ERRQUEUE" "MSG_DONTWAIT" "MSG_CONFIRM" "MSG_FIN" "MSG_SYN" "MSG_RST" "MSG_NOSIGNAL" "MSG_MORE" "MSG_CMSG_CLOEXEC" "MSG_FASTOPEN" "SIOCINQ" "FIONREAD" "POLLIN" "POLLPRI" "POLLOUT" "POLLRDNORM" "POLLRDBAND" "POLLWRNORM" "POLLWRBAND" "POLLMSG" "POLLREMOVE" "POLLRDHUP" "POLLERR" "POLLHUP" "POLLNVAL" "EPERM" "ENOENT" "ESRCH" "EINTR" "EIO" "ENXIO" "E2BIG" "ENOEXEC" "EBADF" "ECHILD" "EAGAIN" "ENOMEM" "EACCES" "EFAULT" "ENOTBLK" "EBUSY" "EEXIST" "EXDEV" "ENODEV" "ENOTDIR" "EISDIR" "EINVAL" "ENFILE" "EMFILE" "ENOTTY" "ETXTBSY" "EFBIG" "ENOSPC" "ESPIPE" "EROFS" "EMLINK" "EPIPE" "EDOM" "ERANGE" "EDEADLK" "ENAMETOOLONG" "ENOLCK" "ENOSYS" "ENOTEMPTY" "ELOOP" "EWOULDBLOCK" "ENOMSG" "EIDRM" "ECHRNG" "EL2NSYNC" "EL3HLT" "EL3RST" "ELNRNG" "EUNATCH" "ENOCSI" "EL2HLT" "EBADE" "EBADR" "EXFULL" "ENOANO" "EBADRQC" "EBADSLT" "EDEADLOCK" "EBFONT" "ENOSTR" "ENODATA" "ETIME" "ENOSR" "ENONET" "ENOPKG" "EREMOTE" "ENOLINK" "EADV" "ESRMNT" "ECOMM" "EPROTO" "EMULTIHOP" "EDOTDOT" "EBADMSG" "EOVERFLOW" "ENOTUNIQ" "EBADFD" "EREMCHG" "ELIBACC" "ELIBBAD" "ELIBSCN" "ELIBMAX" "ELIBEXEC" "EILSEQ" "ERESTART" "ESTRPIPE" "EUSERS" "ENOTSOCK" "EDESTADDRREQ" "EMSGSIZE" "EPROTOTYPE" "ENOPROTOOPT" "EPROTONOSUPPORT" "ESOCKTNOSUPPORT" "EOPNOTSUPP" "EPFNOSUPPORT" "EAFNOSUPPORT" "EADDRINUSE" "EADDRNOTAVAIL" "ENETDOWN" "ENETUNREACH" "ENETRESET" "ECONNABORTED" "ECONNRESET" "ENOBUFS" "EISCONN" "ENOTCONN" "ESHUTDOWN" "ETOOMANYREFS" "ETIMEDOUT" "ECONNREFUSED" "EHOSTDOWN" "EHOSTUNREACH" "EALREADY" "EINPROGRESS" "ESTALE" "EUCLEAN" "ENOTNAM" "ENAVAIL" "EISNAM" "EREMOTEIO" "EDQUOT" "ENOMEDIUM" "EMEDIUMTYPE" "ECANCELED" "ENOKEY" "EKEYEXPIRED" "EKEYREVOKED" "EKEYREJECTED" "EOWNERDEAD" "ENOTRECOVERABLE" "ERFKILL" "POLLIN" "POLLPRI" "POLLOUT" "POLLRDNORM" "POLLRDBAND" "POLLWRNORM" "POLLWRBAND" "POLLMSG" "POLLREMOVE" "POLLRDHUP" "POLLERR" "POLLHUP" "POLLNVAL"))
+(setq packetdrill-constants '("AF_INET" "AF_INET6" "PF_INET" "PF_INET6" "SOCK_STREAM" "SOCK_DGRAM" "IPPROTO_IP" "IPPROTO_IPV6" "IPPROTO_ICMP" "IPPROTO_SCTP" "IPPROTO_TCP" "IPPROTO_UDP" "SOL_SOCKET" "SOL_IP" "SOL_IPV6" "SOL_SCTP" "SOL_TCP" "SOL_UDP" "SO_ACCEPTCONN" "SO_ATTACH_FILTER" "SO_BINDTODEVICE" "SO_BROADCAST" "SO_BSDCOMPAT" "SO_DEBUG" "SO_DETACH_FILTER" "SO_DONTROUTE" "SO_ERROR" "SO_KEEPALIVE" "SO_LINGER" "SO_NO_CHECK" "SO_OOBINLINE" "SO_PASSCRED" "SO_PEERCRED" "SO_PEERNAME" "SO_PEERSEC" "SO_PRIORITY" "SO_RCVBUF" "SO_RCVLOWAT" "SO_RCVTIMEO" "SO_REUSEADDR" "SO_REUSEPORT" "SO_SECURITY_AUTHENTICATION" "SO_SECURITY_ENCRYPTION_NETWORK" "SO_SECURITY_ENCRYPTION_TRANSPORT" "SO_SNDBUF" "SO_SNDLOWAT" "SO_SNDTIMEO" "SO_TIMESTAMP" "SO_TYPE" "IP_TOS" "IP_MTU_DISCOVER" "IP_PMTUDISC_WANT" "IP_PMTUDISC_DONT" "IP_PMTUDISC_DO" "IP_PMTUDISC_PROBE" "IP_MTU" "IPV6_MTU" "SCTP_RTOINFO" "SCTP_INITMSG" "SCTP_NODELAY" "SCTP_MAXSEG" "SCTP_DELAYED_SACK" "SCTP_MAX_BURST" "TCP_NODELAY" "TCP_MAXSEG" "TCP_CORK" "TCP_KEEPIDLE" "TCP_KEEPINTVL" "TCP_KEEPCNT" "TCP_SYNCNT" "TCP_LINGER2" "TCP_DEFER_ACCEPT" "TCP_WINDOW_CLAMP" "TCP_INFO" "TCP_QUICKACK" "TCP_CONGESTION" "TCP_MD5SIG" "TCP_COOKIE_TRANSACTIONS" "TCP_THIN_LINEAR_TIMEOUTS" "TCP_THIN_DUPACK" "TCP_USER_TIMEOUT" "TCP_MIN_RTO" "TCP_INFO_EXT" "TCP_CWND" "TCP_XMIT_COMPL_SEQ" "TCP_CWND_CLAMP" "TCP_SAVE_SYN" "TCP_SAVED_SYN" "TCP_FASTOPEN" "TCP_MULTIPLE_CONNECTIONS" "O_RDONLY" "O_WRONLY" "O_RDWR" "O_ACCMODE" "O_CREAT" "O_EXCL" "O_NOCTTY" "O_TRUNC" "O_APPEND" "O_NONBLOCK" "F_DUPFD" "F_GETFD" "F_SETFD" "F_GETFL" "F_SETFL" "F_GETLK" "F_SETLK" "F_SETLKW" "F_GETOWN" "F_SETOWN" "F_SETSIG" "F_GETSIG" "F_GETOWN" "F_SETOWN" "F_SETLK" "F_SETLKW" "F_GETLK" "F_SETLK64" "F_SETLKW64" "F_GETLK64" "F_SETLEASE" "F_GETLEASE" "F_NOTIFY" "F_DUPFD_CLOEXEC" "FD_CLOEXEC" "LOCK_SH" "LOCK_EX" "LOCK_NB" "LOCK_UN" "F_RDLCK" "F_WRLCK" "F_UNLCK" "F_EXLCK" "F_SHLCK" "SEEK_SET" "SEEK_CUR" "SEEK_END" "MSG_OOB" "MSG_DONTROUTE" "MSG_PEEK" "MSG_CTRUNC" "MSG_PROXY" "MSG_EOR" "MSG_WAITALL" "MSG_TRUNC" "MSG_CTRUNC" "MSG_ERRQUEUE" "MSG_DONTWAIT" "MSG_CONFIRM" "MSG_FIN" "MSG_SYN" "MSG_RST" "MSG_NOSIGNAL" "MSG_MORE" "MSG_CMSG_CLOEXEC" "MSG_FASTOPEN" "SIOCINQ" "FIONREAD" "POLLIN" "POLLPRI" "POLLOUT" "POLLRDNORM" "POLLRDBAND" "POLLWRNORM" "POLLWRBAND" "POLLMSG" "POLLREMOVE" "POLLRDHUP" "POLLERR" "POLLHUP" "POLLNVAL" "EPERM" "ENOENT" "ESRCH" "EINTR" "EIO" "ENXIO" "E2BIG" "ENOEXEC" "EBADF" "ECHILD" "EAGAIN" "ENOMEM" "EACCES" "EFAULT" "ENOTBLK" "EBUSY" "EEXIST" "EXDEV" "ENODEV" "ENOTDIR" "EISDIR" "EINVAL" "ENFILE" "EMFILE" "ENOTTY" "ETXTBSY" "EFBIG" "ENOSPC" "ESPIPE" "EROFS" "EMLINK" "EPIPE" "EDOM" "ERANGE" "EDEADLK" "ENAMETOOLONG" "ENOLCK" "ENOSYS" "ENOTEMPTY" "ELOOP" "EWOULDBLOCK" "ENOMSG" "EIDRM" "ECHRNG" "EL2NSYNC" "EL3HLT" "EL3RST" "ELNRNG" "EUNATCH" "ENOCSI" "EL2HLT" "EBADE" "EBADR" "EXFULL" "ENOANO" "EBADRQC" "EBADSLT" "EDEADLOCK" "EBFONT" "ENOSTR" "ENODATA" "ETIME" "ENOSR" "ENONET" "ENOPKG" "EREMOTE" "ENOLINK" "EADV" "ESRMNT" "ECOMM" "EPROTO" "EMULTIHOP" "EDOTDOT" "EBADMSG" "EOVERFLOW" "ENOTUNIQ" "EBADFD" "EREMCHG" "ELIBACC" "ELIBBAD" "ELIBSCN" "ELIBMAX" "ELIBEXEC" "EILSEQ" "ERESTART" "ESTRPIPE" "EUSERS" "ENOTSOCK" "EDESTADDRREQ" "EMSGSIZE" "EPROTOTYPE" "ENOPROTOOPT" "EPROTONOSUPPORT" "ESOCKTNOSUPPORT" "EOPNOTSUPP" "EPFNOSUPPORT" "EAFNOSUPPORT" "EADDRINUSE" "EADDRNOTAVAIL" "ENETDOWN" "ENETUNREACH" "ENETRESET" "ECONNABORTED" "ECONNRESET" "ENOBUFS" "EISCONN" "ENOTCONN" "ESHUTDOWN" "ETOOMANYREFS" "ETIMEDOUT" "ECONNREFUSED" "EHOSTDOWN" "EHOSTUNREACH" "EALREADY" "EINPROGRESS" "ESTALE" "EUCLEAN" "ENOTNAM" "ENAVAIL" "EISNAM" "EREMOTEIO" "EDQUOT" "ENOMEDIUM" "EMEDIUMTYPE" "ECANCELED" "ENOKEY" "EKEYEXPIRED" "EKEYREVOKED" "EKEYREJECTED" "EOWNERDEAD" "ENOTRECOVERABLE" "ERFKILL" "POLLIN" "POLLPRI" "POLLOUT" "POLLRDNORM" "POLLRDBAND" "POLLWRNORM" "POLLWRBAND" "POLLMSG" "POLLREMOVE" "POLLRDHUP" "POLLERR" "POLLHUP" "POLLNVAL"))
 
 (setq packetdrill-functions '("accept" "bind" "close" "connect" "fcntl" "getsockopt" "ioctl" "listen" "poll" "read" "readv" "recv" "recvfrom" "recvmsg" "send" "sendmsg" "sendto" "setsockopt" "shutdown" "socket" "write" "writev"))
 
diff --git a/gtests/net/packetdrill/contrib/packetdrill.vim b/gtests/net/packetdrill/contrib/packetdrill.vim
index 8bc803e0..4e1e8b9b 100644
--- a/gtests/net/packetdrill/contrib/packetdrill.vim
+++ b/gtests/net/packetdrill/contrib/packetdrill.vim
@@ -11,8 +11,8 @@ endif
 let s:cpo_save = &cpo
 set cpo&vim
 
-syn keyword     pKeyword        sa_family sin_port sin_addr msg_name msg_iov msg_flags fd events revents htons icmp udp inet_addr ack eol ecr mss mtu nop sack sackOK TS FO LS gcn minRTO val win wscale ect01 ect0 ect1 noecn ce pro
-syn keyword     pConstant       AF_INET AF_INET6 PF_INET PF_INET6 SOCK_STREAM SOCK_DGRAM IPPROTO_IP IPPROTO_IPV6 IPPROTO_ICMP IPPROTO_TCP IPPROTO_UDP SOL_SOCKET SOL_IP SOL_IPV6 SOL_TCP SOL_UDP SO_ACCEPTCONN SO_ATTACH_FILTER SO_BINDTODEVICE SO_BROADCAST SO_BSDCOMPAT SO_DEBUG SO_DETACH_FILTER SO_DONTROUTE SO_ERROR SO_KEEPALIVE SO_LINGER SO_NO_CHECK SO_OOBINLINE SO_PASSCRED SO_PEERCRED SO_PEERNAME SO_PEERSEC SO_PRIORITY SO_RCVBUF SO_RCVLOWAT SO_RCVTIMEO SO_REUSEADDR SO_REUSEPORT SO_SECURITY_AUTHENTICATION SO_SECURITY_ENCRYPTION_NETWORK SO_SECURITY_ENCRYPTION_TRANSPORT SO_SNDBUF SO_SNDLOWAT SO_SNDTIMEO SO_TIMESTAMP SO_TYPE IP_TOS IP_MTU_DISCOVER IP_PMTUDISC_WANT IP_PMTUDISC_DONT IP_PMTUDISC_DO IP_PMTUDISC_PROBE IP_MTU IPV6_MTU TCP_NODELAY TCP_MAXSEG TCP_CORK TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT TCP_SYNCNT TCP_LINGER2 TCP_DEFER_ACCEPT TCP_WINDOW_CLAMP TCP_INFO TCP_QUICKACK TCP_CONGESTION TCP_MD5SIG TCP_COOKIE_TRANSACTIONS TCP_THIN_LINEAR_TIMEOUTS TCP_THIN_DUPACK TCP_USER_TIMEOUT TCP_MIN_RTO TCP_INFO_EXT TCP_CWND TCP_XMIT_COMPL_SEQ TCP_CWND_CLAMP TCP_SAVE_SYN TCP_SAVED_SYN TCP_FASTOPEN TCP_MULTIPLE_CONNECTIONS
+syn keyword     pKeyword        sa_family sin_port sin_addr msg_name msg_iov msg_flags fd events revents htons icmp udp inet_addr ack eol ecr mss mtu nop sack sackOK TS FO LS gcn minRTO val win wscale ect01 ect0 ect1 noecn ce pro onoff linger srto_initial srto_max srto_min sinit_num_ostreams sinit_max_instreams sinit_max_attempts sinit_max_init_timeo assoc_value sack_delay sack_freq
+syn keyword     pConstant       AF_INET AF_INET6 PF_INET PF_INET6 SOCK_STREAM SOCK_DGRAM IPPROTO_IP IPPROTO_IPV6 IPPROTO_ICMP IPPROTO_SCTP IPPROTO_TCP IPPROTO_UDP SOL_SOCKET SOL_IP SOL_IPV6 SOL_SCTP SOL_TCP SOL_UDP SO_ACCEPTCONN SO_ATTACH_FILTER SO_BINDTODEVICE SO_BROADCAST SO_BSDCOMPAT SO_DEBUG SO_DETACH_FILTER SO_DONTROUTE SO_ERROR SO_KEEPALIVE SO_LINGER SO_NO_CHECK SO_OOBINLINE SO_PASSCRED SO_PEERCRED SO_PEERNAME SO_PEERSEC SO_PRIORITY SO_RCVBUF SO_RCVLOWAT SO_RCVTIMEO SO_REUSEADDR SO_REUSEPORT SO_SECURITY_AUTHENTICATION SO_SECURITY_ENCRYPTION_NETWORK SO_SECURITY_ENCRYPTION_TRANSPORT SO_SNDBUF SO_SNDLOWAT SO_SNDTIMEO SO_TIMESTAMP SO_TYPE IP_TOS IP_MTU_DISCOVER IP_PMTUDISC_WANT IP_PMTUDISC_DONT IP_PMTUDISC_DO IP_PMTUDISC_PROBE IP_MTU IPV6_MTU SCTP_RTOINFO SCTP_INITMSG SCTP_NODELAY SCTP_MAXSEG SCTP_DELAYED_SACK SCTP_MAX_BURST TCP_NODELAY TCP_MAXSEG TCP_CORK TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT TCP_SYNCNT TCP_LINGER2 TCP_DEFER_ACCEPT TCP_WINDOW_CLAMP TCP_INFO TCP_QUICKACK TCP_CONGESTION TCP_MD5SIG TCP_COOKIE_TRANSACTIONS TCP_THIN_LINEAR_TIMEOUTS TCP_THIN_DUPACK TCP_USER_TIMEOUT TCP_MIN_RTO TCP_INFO_EXT TCP_CWND TCP_XMIT_COMPL_SEQ TCP_CWND_CLAMP TCP_SAVE_SYN TCP_SAVED_SYN TCP_FASTOPEN TCP_MULTIPLE_CONNECTIONS
 syn keyword     pConstant       O_RDONLY O_WRONLY O_RDWR O_ACCMODE O_CREAT O_EXCL O_NOCTTY O_TRUNC O_APPEND O_NONBLOCK F_DUPFD F_GETFD F_SETFD F_GETFL F_SETFL F_GETLK F_SETLK F_SETLKW F_GETOWN F_SETOWN F_SETSIG F_GETSIG F_GETOWN F_SETOWN F_SETLK F_SETLKW F_GETLK F_SETLK64 F_SETLKW64 F_GETLK64 F_SETLEASE F_GETLEASE F_NOTIFY F_DUPFD_CLOEXEC FD_CLOEXEC LOCK_SH LOCK_EX LOCK_NB LOCK_UN F_RDLCK F_WRLCK F_UNLCK F_EXLCK F_SHLCK SEEK_SET SEEK_CUR SEEK_END MSG_OOB MSG_DONTROUTE MSG_PEEK MSG_CTRUNC MSG_PROXY MSG_EOR MSG_WAITALL MSG_TRUNC MSG_CTRUNC MSG_ERRQUEUE MSG_DONTWAIT MSG_CONFIRM MSG_FIN MSG_SYN MSG_RST MSG_NOSIGNAL MSG_MORE MSG_CMSG_CLOEXEC MSG_FASTOPEN SIOCINQ FIONREAD POLLIN POLLPRI POLLOUT POLLRDNORM POLLRDBAND POLLWRNORM POLLWRBAND POLLMSG POLLREMOVE POLLRDHUP POLLERR POLLHUP POLLNVAL EPERM ENOENT ESRCH EINTR EIO ENXIO E2BIG ENOEXEC EBADF ECHILD EAGAIN ENOMEM EACCES EFAULT ENOTBLK EBUSY EEXIST EXDEV ENODEV ENOTDIR EISDIR EINVAL ENFILE EMFILE ENOTTY ETXTBSY EFBIG ENOSPC ESPIPE EROFS EMLINK EPIPE EDOM ERANGE EDEADLK ENAMETOOLONG ENOLCK ENOSYS ENOTEMPTY ELOOP EWOULDBLOCK ENOMSG EIDRM ECHRNG EL2NSYNC EL3HLT EL3RST ELNRNG EUNATCH ENOCSI EL2HLT EBADE EBADR EXFULL ENOANO EBADRQC EBADSLT EDEADLOCK EBFONT ENOSTR ENODATA ETIME ENOSR ENONET ENOPKG EREMOTE ENOLINK EADV ESRMNT ECOMM EPROTO EMULTIHOP EDOTDOT EBADMSG EOVERFLOW ENOTUNIQ EBADFD EREMCHG ELIBACC ELIBBAD ELIBSCN ELIBMAX ELIBEXEC EILSEQ ERESTART ESTRPIPE EUSERS ENOTSOCK EDESTADDRREQ EMSGSIZE EPROTOTYPE ENOPROTOOPT EPROTONOSUPPORT ESOCKTNOSUPPORT EOPNOTSUPP EPFNOSUPPORT EAFNOSUPPORT EADDRINUSE EADDRNOTAVAIL ENETDOWN ENETUNREACH ENETRESET ECONNABORTED ECONNRESET ENOBUFS EISCONN ENOTCONN ESHUTDOWN ETOOMANYREFS ETIMEDOUT ECONNREFUSED EHOSTDOWN EHOSTUNREACH EALREADY EINPROGRESS ESTALE EUCLEAN ENOTNAM ENAVAIL EISNAM EREMOTEIO EDQUOT ENOMEDIUM EMEDIUMTYPE ECANCELED ENOKEY EKEYEXPIRED EKEYREVOKED EKEYREJECTED EOWNERDEAD ENOTRECOVERABLE ERFKILL POLLIN POLLPRI POLLOUT POLLRDNORM POLLRDBAND POLLWRNORM POLLWRBAND POLLMSG POLLREMOVE POLLRDHUP POLLERR POLLHUP POLLNVAL
 syn keyword	pSyscall        accept bind close connect fcntl getsockopt ioctl listen poll read readv recv recvfrom recvmsg send sendmsg sendto setsockopt shutdown socket write writev
 syn keyword	pPythonCmds     contained assert print
diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index c52669d7..09cefdcd 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -200,6 +200,16 @@ ect1			return ECT1;
 noecn			return NO_ECN;
 ce			return CE;
 [.][.][.]		return ELLIPSIS;
+assoc_value		return ASSOC_VALUE;
+sack_delay		return SACK_DELAY;
+sack_freq		return SACK_FREQ;
+srto_initial		return SRTO_INITIAL;
+srto_max		return SRTO_MAX;
+srto_min		return SRTO_MIN;
+sinit_num_ostreams	return SINIT_NUM_OSTREAMS;
+sinit_max_instreams	return SINIT_MAX_INSTREAMS;
+sinit_max_attempts	return SINIT_MAX_ATTEMPTS;
+sinit_max_init_timeo	return SINIT_MAX_INIT_TIMEO;
 --[a-zA-Z0-9_]+		yylval.string	= option(yytext); return OPTION;
 [-]?[0-9]*[.][0-9]+	yylval.floating	= atof(yytext);   return FLOAT;
 [-]?[0-9]+		yylval.integer	= atoll(yytext);  return INTEGER;
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index a6d405f6..6bee8a9d 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -480,6 +480,11 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> IPV4 IPV6 ICMP UDP GRE MTU
 %token <reserved> MPLS LABEL TC TTL
 %token <reserved> OPTION
+%token <reserved> 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_VALUE
+%token <reserved> SACK_DELAY SACK_FREQ
 %token <floating> FLOAT
 %token <integer> INTEGER HEX_INTEGER
 %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR
@@ -512,6 +517,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <expression> expression binary_expression array
 %type <expression> decimal_integer hex_integer
 %type <expression> inaddr sockaddr msghdr iovec pollfd opt_revents linger
+%type <expression> sctp_rtoinfo sctp_initmsg sctp_assocval sctp_sackinfo
 %type <errno_info> opt_errno
 
 %%  /* The grammar follows. */
@@ -1113,6 +1119,18 @@ expression
 | linger            {
 	$$ = $1;
 }
+| sctp_rtoinfo      {
+	$$ = $1;
+}
+| sctp_initmsg      {
+	$$ = $1;
+}
+| sctp_assocval     {
+	$$ = $1;
+}
+| sctp_sackinfo     {
+	$$ = $1;
+}
 ;
 
 decimal_integer
@@ -1239,6 +1257,86 @@ linger
 }
 ;
 
+sctp_rtoinfo
+: '{' SRTO_INITIAL '=' INTEGER ',' SRTO_MAX '=' INTEGER ',' SRTO_MIN '=' INTEGER '}' {
+#ifdef SCTP_RTOINFO
+	$$ = new_expression(EXPR_SCTP_RTOINFO);
+	if (!is_valid_u32($4)) {
+		semantic_error("srto_initial out of range");
+	}
+	$$->value.sctp_rtoinfo.srto_initial = $4;
+	if (!is_valid_u32($8)) {
+		semantic_error("srto_max out of range");
+	}
+	$$->value.sctp_rtoinfo.srto_max = $8;
+	if (!is_valid_u32($12)) {
+		semantic_error("srto_min out of range");
+	}
+	$$->value.sctp_rtoinfo.srto_min = $12;
+#else
+	$$ = NULL;
+#endif
+}
+;
+
+sctp_initmsg
+: '{' SINIT_NUM_OSTREAMS '=' INTEGER ',' SINIT_MAX_INSTREAMS '=' INTEGER ',' SINIT_MAX_ATTEMPTS '=' INTEGER ',' SINIT_MAX_INIT_TIMEO '=' INTEGER '}' {
+#ifdef SCTP_INITMSG
+	$$ = new_expression(EXPR_SCTP_INITMSG);
+	if (!is_valid_u16($4)) {
+		semantic_error("sinit_num_ostreams out of range");
+	}
+	$$->value.sctp_initmsg.sinit_num_ostreams = $4;
+	if (!is_valid_u16($8)) {
+		semantic_error("sinit_max_instreams out of range");
+	}
+	$$->value.sctp_initmsg.sinit_max_instreams = $8;
+	if (!is_valid_u16($12)) {
+		semantic_error("sinit_max_attempts out of range");
+	}
+	$$->value.sctp_initmsg.sinit_max_attempts = $12;
+	if (!is_valid_u16($16)) {
+		semantic_error("sinit_max_init_timeo out of range");
+	}
+	$$->value.sctp_initmsg.sinit_max_init_timeo = $16;
+#else
+	$$ = NULL;
+#endif
+}
+;
+
+sctp_assocval
+: '{' ASSOC_VALUE '=' INTEGER '}' {
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
+	$$ = new_expression(EXPR_SCTP_ASSOCVAL);
+	if (!is_valid_u32($4)) {
+		semantic_error("assoc_value out of range");
+	}
+	$$->value.sctp_assoc_value.assoc_value = $4;
+#else
+	$$ = NULL;
+#endif
+}
+;
+
+sctp_sackinfo
+: '{' SACK_DELAY '=' INTEGER ',' SACK_FREQ '=' INTEGER '}' {
+#ifdef SCTP_DELAYED_SACK
+	$$ = new_expression(EXPR_SCTP_SACKINFO);
+	if (!is_valid_u32($4)) {
+		semantic_error("sack_delay out of range");
+	}
+	$$->value.sctp_sack_info.sack_delay = $4;
+	if (!is_valid_u32($8)) {
+		semantic_error("sack_freq out of range");
+	}
+	$$->value.sctp_sack_info.sack_freq  = $8;
+#else
+	$$ = NULL;
+#endif
+}
+;
+
 opt_errno
 :                   { $$ = NULL; }
 | WORD note         {
diff --git a/gtests/net/packetdrill/platforms.h b/gtests/net/packetdrill/platforms.h
index 5fdda2cc..16086902 100644
--- a/gtests/net/packetdrill/platforms.h
+++ b/gtests/net/packetdrill/platforms.h
@@ -30,6 +30,7 @@
 
 #ifdef linux
 
+#include <netinet/sctp.h>
 #include <features.h>
 #define HAVE_OPEN_MEMSTREAM     1
 #define HAVE_FMEMOPEN           1
@@ -43,6 +44,7 @@
 
 #if defined(__FreeBSD__)
 
+#include <netinet/sctp.h>
 #include <sys/param.h>
 #define USE_LIBPCAP             1
 #define TUN_PATH                "/dev/tun0"
diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index 46baeb6f..aa9c3a90 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -152,6 +152,9 @@ static struct expression *get_arg(struct expression_list *args,
 		++current;
 	}
 	if ((args != NULL) && (current == index)) {
+		if (!args->expression)
+			asprintf(error, "Unknown expression at index %d",
+				 index);
 		return args->expression;
 	} else {
 		asprintf(error, "Argument list too short");
@@ -1633,6 +1636,22 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 		if (s32_bracketed_arg(args, 3, &optval_s32, error))
 			return STATUS_ERR;
 		optval = &optval_s32;
+#ifdef SCTP_RTOINFO
+	} else if (val_expression->type == EXPR_SCTP_RTOINFO) {
+		optval = &val_expression->value.sctp_rtoinfo;
+#endif
+#ifdef SCTP_INITMSG
+	} else if (val_expression->type == EXPR_SCTP_INITMSG) {
+		optval = &val_expression->value.sctp_initmsg;
+#endif
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
+	} else if (val_expression->type == EXPR_SCTP_ASSOCVAL) {
+		optval = &val_expression->value.sctp_assoc_value;
+#endif
+#ifdef SCTP_DELAYED_SACK
+	} else if (val_expression->type == EXPR_SCTP_SACKINFO) {
+		optval = &val_expression->value.sctp_sack_info;
+#endif
 	} else {
 		asprintf(error, "unsupported setsockopt value type: %s",
 			 expression_type_to_string(
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index f6692030..fbf150c9 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -65,6 +65,18 @@ struct expression_type_entry expression_type_table[] = {
 	{ EXPR_IOVEC,                "iovec" },
 	{ EXPR_MSGHDR,               "msghdr" },
 	{ EXPR_POLLFD,               "pollfd" },
+#ifdef SCTP_RTOINFO
+	{ EXPR_SCTP_RTOINFO,         "sctp_rtoinfo"},
+#endif
+#ifdef SCTP_INITMSG
+	{ EXPR_SCTP_INITMSG,         "sctp_initmsg"},
+#endif
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
+	{ EXPR_SCTP_ASSOCVAL,        "sctp_assocvalue"},
+#endif
+#ifdef SCTP_DELAYED_SACK
+	{ EXPR_SCTP_SACKINFO,        "sctp_sackinfo"},
+#endif
 	{ NUM_EXPR_TYPES,            NULL}
 };
 
@@ -92,6 +104,9 @@ struct int_symbol cross_platform_symbols[] = {
 	{ IPPROTO_IP,                       "IPPROTO_IP"                      },
 	{ IPPROTO_IPV6,                     "IPPROTO_IPV6"                    },
 	{ IPPROTO_ICMP,                     "IPPROTO_ICMP"                    },
+#ifdef IPPROTO_SCTP
+	{ IPPROTO_SCTP,                     "IPPROTO_SCTP"                    },
+#endif
 	{ IPPROTO_TCP,                      "IPPROTO_TCP"                     },
 	{ IPPROTO_UDP,                      "IPPROTO_UDP"                     },
 
@@ -269,6 +284,18 @@ void free_expression(struct expression *expression)
 	case EXPR_ELLIPSIS:
 	case EXPR_INTEGER:
 	case EXPR_LINGER:
+#ifdef SCTP_RTOINFO
+	case EXPR_SCTP_RTOINFO:
+#endif
+#ifdef SCTP_INITMSG
+	case EXPR_SCTP_INITMSG:
+#endif
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
+	case EXPR_SCTP_ASSOCVAL:
+#endif
+#ifdef SCTP_DELAYED_SACK
+	case EXPR_SCTP_SACKINFO:
+#endif
 		break;
 	case EXPR_WORD:
 		assert(expression->value.string);
@@ -478,6 +505,31 @@ static int evaluate(struct expression *in,
 		memcpy(&out->value.linger, &in->value.linger,
 		       sizeof(in->value.linger));
 		break;
+#ifdef SCTP_RTOINFO
+	case EXPR_SCTP_RTOINFO:		/* copy as-is */
+		memcpy(&out->value.sctp_rtoinfo, &in->value.sctp_rtoinfo,
+		       sizeof(in->value.sctp_rtoinfo));
+		break;
+#endif
+#ifdef SCTP_INITMSG
+	case EXPR_SCTP_INITMSG:		/* copy as-is */
+		memcpy(&out->value.sctp_initmsg, &in->value.sctp_initmsg,
+		       sizeof(in->value.sctp_initmsg));
+		break;
+#endif
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
+	case EXPR_SCTP_ASSOCVAL:	/* copy as-is */
+		memcpy(&out->value.sctp_assoc_value,
+		       &in->value.sctp_assoc_value,
+		       sizeof(in->value.sctp_assoc_value));
+		break;
+#endif
+#ifdef SCTP_DELAYED_SACK
+	case EXPR_SCTP_SACKINFO:	/* copy as-is */
+		memcpy(&out->value.sctp_sack_info, &in->value.sctp_sack_info,
+		       sizeof(in->value.sctp_sack_info));
+		break;
+#endif
 	case EXPR_WORD:
 		out->type = EXPR_INTEGER;
 		if (symbol_to_int(in->value.string,
diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h
index ac14e65b..cab9a22d 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -45,6 +45,19 @@ enum expression_t {
 	EXPR_IOVEC,		  /* expression tree for an iovec struct */
 	EXPR_MSGHDR,		  /* expression tree for a msghdr struct */
 	EXPR_POLLFD,		  /* expression tree for a pollfd struct */
+#ifdef SCTP_RTOINFO
+	EXPR_SCTP_RTOINFO,	  /* struct sctp_rtoinfo for SCTP_RTOINFO */
+#endif
+#ifdef SCTP_INITMSG
+	EXPR_SCTP_INITMSG,	  /* struct sctp_initmsg for SCTP_INITMSG */
+#endif
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
+	EXPR_SCTP_ASSOCVAL,	  /* struct sctp_assoc_value */
+#endif
+#ifdef SCTP_DELAYED_SACK
+	EXPR_SCTP_SACKINFO,	  /* struct sctp_sack_info for
+				   * SCTP_DELAYED_SACK */
+#endif
 	NUM_EXPR_TYPES,
 };
 /* Convert an expression type to a human-readable string */
@@ -64,6 +77,18 @@ struct expression {
 		struct iovec_expr *iovec;
 		struct msghdr_expr *msghdr;
 		struct pollfd_expr *pollfd;
+#ifdef SCTP_RTOINFO
+		struct sctp_rtoinfo sctp_rtoinfo;
+#endif
+#ifdef SCTP_INITMSG
+		struct sctp_initmsg sctp_initmsg;
+#endif
+#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST)
+		struct sctp_assoc_value sctp_assoc_value;
+#endif
+#ifdef SCTP_DELAYED_SACK
+		struct sctp_sack_info sctp_sack_info;
+#endif
 	} value;
 	const char *format;	/* the printf format for printing the value */
 };
diff --git a/gtests/net/packetdrill/symbols_freebsd.c b/gtests/net/packetdrill/symbols_freebsd.c
index 9f630f50..d78a73ec 100644
--- a/gtests/net/packetdrill/symbols_freebsd.c
+++ b/gtests/net/packetdrill/symbols_freebsd.c
@@ -78,6 +78,14 @@ struct int_symbol platform_symbols_table[] = {
 	{ SO_SETFIB,                        "SO_SETFIB"                       },
 	{ SO_USER_COOKIE,                   "SO_USER_COOKIE"                  },
 
+	/* /usr/include/netinet/sctp.h */
+	{ SCTP_RTOINFO,                     "SCTP_RTOINFO"                    },
+	{ SCTP_INITMSG,                     "SCTP_INITMSG"                    },
+	{ SCTP_NODELAY,                     "SCTP_NODELAY"                    },
+	{ SCTP_MAXSEG,                      "SCTP_MAXSEG"                     },
+	{ SCTP_DELAYED_SACK,                "SCTP_DELAYED_SACK"               },
+	{ SCTP_MAX_BURST,                   "SCTP_MAX_BURST"                  },
+
 	/* /usr/include/netinet/tcp.h */
 	{ TCP_NODELAY,                      "TCP_NODELAY"                     },
 	{ TCP_MAXSEG,                       "TCP_MAXSEG"                      },
diff --git a/gtests/net/packetdrill/symbols_linux.c b/gtests/net/packetdrill/symbols_linux.c
index 641e3781..17347436 100644
--- a/gtests/net/packetdrill/symbols_linux.c
+++ b/gtests/net/packetdrill/symbols_linux.c
@@ -48,6 +48,9 @@
 struct int_symbol platform_symbols_table[] = {
 	{ SOL_IP,                           "SOL_IP"                          },
 	{ SOL_IPV6,                         "SOL_IPV6"                        },
+#ifdef SOL_SCTP
+	{ SOL_SCTP,                         "SOL_SCTP"                        },
+#endif
 	{ SOL_TCP,                          "SOL_TCP"                         },
 	{ SOL_UDP,                          "SOL_UDP"                         },
 
@@ -96,6 +99,25 @@ struct int_symbol platform_symbols_table[] = {
 	{ IPV6_MTU,                         "IPV6_MTU"                        },
 #endif
 
+#ifdef SCTP_RTOINFO
+	{ SCTP_RTOINFO,                     "SCTP_RTOINFO"                    },
+#endif
+#ifdef SCTP_INITMSG
+	{ SCTP_INITMSG,                     "SCTP_INITMSG"                    },
+#endif
+#ifdef SCTP_NODELAY
+	{ SCTP_NODELAY,                     "SCTP_NODELAY"                    },
+#endif
+#ifdef SCTP_MAXSEG
+	{ SCTP_MAXSEG,                      "SCTP_MAXSEG"                     },
+#endif
+#ifdef SCTP_DELAYED_SACK
+	{ SCTP_DELAYED_SACK,                "SCTP_DELAYED_SACK"               },
+#endif
+#ifdef SCTP_MAX_BURST
+	{ SCTP_MAX_BURST,                   "SCTP_MAX_BURST"                  },
+#endif
+
 	{ TCP_NODELAY,                      "TCP_NODELAY"                     },
 	{ TCP_MAXSEG,                       "TCP_MAXSEG"                      },
 	{ TCP_CORK,                         "TCP_CORK"                        },
-- 
GitLab