diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index 4cadbae7f5436d244f6479e5fb95c64902e1a442..08ff374e467d804e688f4187bf05bab67d588d58 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -164,7 +164,12 @@ sin_port			return SIN_PORT;
 sin_addr			return SIN_ADDR;
 msg_name			return MSG_NAME;
 msg_iov				return MSG_IOV;
+msg_control			return MSG_CONTROL;
 msg_flags			return MSG_FLAGS;
+cmsg_len                        return CMSG_LEN;
+cmsg_level                      return CMSG_LEVEL;
+cmsg_type                       return CMSG_TYPE;
+cmsg_data                       return CMSG_DATA;
 fd				return FD;
 events				return EVENTS;
 revents				return REVENTS;
@@ -259,6 +264,7 @@ snd_sid				return SND_SID;
 snd_flags			return SND_FLAGS;
 snd_ppid			return SND_PPID;
 snd_context			return SND_CONTEXT;
+snd_assoc_id                    return SND_ASSOC_ID;
 ssb_adaptation_ind		return SSB_ADAPTATION_IND;
 sinfo_stream			return SINFO_STREAM;
 sinfo_ssn			return SINFO_SSN;
@@ -385,6 +391,7 @@ fsn				return FSN;
 cum_tsn				return CUM_TSN;
 gaps				return GAPS;
 dups				return DUPS;
+adaptation_code_point		return ADAPTATION_CODE_POINT;
 PARAMETER			return PARAMETER;
 HEARTBEAT_INFORMATION		return HEARTBEAT_INFORMATION;
 IPV4_ADDRESS			return IPV4_ADDRESS;
@@ -394,6 +401,7 @@ UNRECOGNIZED_PARAMETER		return UNRECOGNIZED_PARAMETER;
 COOKIE_PRESERVATIVE		return COOKIE_PRESERVATIVE;
 HOSTNAME_ADDRESS		return HOSTNAME_ADDRESS;
 SUPPORTED_ADDRESS_TYPES		return SUPPORTED_ADDRESS_TYPES;
+ADAPTATION_INDICATION		return ADAPTATION_INDICATION;
 ECN_CAPABLE			return ECN_CAPABLE;
 SUPPORTED_EXTENSIONS		return SUPPORTED_EXTENSIONS;
 addr				return ADDR;
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index f2d3fc5deb09b0981ccb4f69fdd185ebae8b92f3..357bdc61125699e80bb7017f59f3e0bfc5fb2faa 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -494,7 +494,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
  */
 %token ELLIPSIS
 %token <reserved> SA_FAMILY SIN_PORT SIN_ADDR _HTONS_ _HTONL_ INET_ADDR
-%token <reserved> MSG_NAME MSG_IOV MSG_FLAGS
+%token <reserved> MSG_NAME MSG_IOV MSG_FLAGS MSG_CONTROL CMSG_LEN CMSG_LEVEL CMSG_TYPE CMSG_DATA
 %token <reserved> FD EVENTS REVENTS ONOFF LINGER
 %token <reserved> ACK ECR EOL MSS NOP SACK SACKOK TIMESTAMP VAL WIN WSCALE PRO
 %token <reserved> FAST_OPEN
@@ -522,7 +522,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %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
-%token <reserved> SUPPORTED_EXTENSIONS
+%token <reserved> SUPPORTED_EXTENSIONS ADAPTATION_CODE_POINT ADAPTATION_INDICATION
 %token <reserved> ADDR INCR TYPES PARAMS
 %token <reserved> IPV4_TYPE IPV6_TYPE HOSTNAME_TYPE
 %token <reserved> CAUSE
@@ -538,7 +538,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <reserved> SPP_FLAGS SPP_IPV6_FLOWLABEL_ SPP_DSCP_
 %token <reserved> SASOC_ASOCMAXRXT SASOC_NUMBER_PEER_DESTINATIONS SASOC_PEER_RWND
 %token <reserved> SASOC_LOCAL_RWND SASOC_COOKIE_LIFE SE_TYPE SE_ON
-%token <reserved> SND_SID SND_FLAGS SND_PPID SND_CONTEXT SSB_ADAPTATION_IND
+%token <reserved> 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
 %token <reserved> SINFO_TIMETOLIVE SINFO_TSN SINFO_CUMTSN
@@ -598,7 +598,8 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <expression_list> expression_list function_arguments
 %type <expression> expression binary_expression array
 %type <expression> decimal_integer hex_integer data
-%type <expression> inaddr sockaddr msghdr iovec pollfd opt_revents
+%type <expression> inaddr sockaddr msghdr cmsghdr cmsg_level cmsg_type cmsg_data 
+%type <expression> iovec pollfd opt_revents
 %type <expression> linger l_onoff l_linger
 %type <expression> sctp_status sstat_state sstat_rwnd sstat_unackdata sstat_penddata
 %type <expression> sstat_instrms sstat_outstrms sstat_fragmentation_point sstat_primary
@@ -611,7 +612,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <expression> spinfo_address spinfo_state spinfo_cwnd spinfo_srtt spinfo_rto spinfo_mtu
 %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_sndinfo snd_sid snd_flags snd_ppid snd_assoc_id snd_context
 %type <expression> sctp_event se_type se_on sctp_setadaptation null
 %type <expression> sctp_sndrcvinfo sinfo_stream sinfo_ssn sinfo_flags sinfo_ppid sinfo_context
 %type <expression> sinfo_timetolive sinfo_tsn sinfo_cumtsn
@@ -661,6 +662,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %type <parameter_list_item> sctp_supported_address_types_parameter_spec
 %type <parameter_list_item> sctp_ecn_capable_parameter_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 <cause_list> opt_cause_list_spec sctp_cause_list_spec
 %type <cause_list_item> sctp_cause_spec
@@ -1599,6 +1601,7 @@ sctp_parameter_spec
 | sctp_supported_address_types_parameter_spec { $$ = $1; }
 | sctp_ecn_capable_parameter_spec             { $$ = $1; }
 | sctp_supported_extensions_parameter_spec    { $$ = $1; }
+| sctp_adaptation_indication_parameter_spec   { $$ = $1; }
 | sctp_pad_parameter_spec                     { $$ = $1; }
 ;
 
@@ -1767,6 +1770,13 @@ chunk_types_list
 }
 ;
 
+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);
@@ -2449,6 +2459,9 @@ expression
 | msghdr            {
 	$$ = $1;
 }
+| cmsghdr           {
+	$$ = $1;
+}
 | iovec             {
 	$$ = $1;
 }
@@ -2621,6 +2634,7 @@ data
 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);
@@ -2629,11 +2643,60 @@ msghdr
 	msg_expr->msg_namelen	= new_expression(EXPR_ELLIPSIS);
 	msg_expr->msg_iov	= $14;
 	msg_expr->msg_iovlen	= $11;
-	msg_expr->msg_flags	= $18;
-	/* TODO(ncardwell): msg_control, msg_controllen */
+	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_sndinfo     { $$ = $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));
@@ -3251,14 +3314,30 @@ snd_context
 | SND_CONTEXT '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
 ;
 
+snd_assoc_id
+: SND_ASSOC_ID '=' INTEGER {
+	if (!is_valid_u32($3)) {
+		semantic_error("snd_assoc_id out of range");
+	}
+	$$ = new_integer_expression($3, "%u");
+}
+| SND_ASSOC_ID '=' WORD {
+	$$ = new_expression(EXPR_WORD);
+	$$->value.string = $3;
+}
+| SND_ASSOC_ID '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); }
+;
+
+
 sctp_sndinfo
-: '{' snd_sid ',' snd_flags ',' snd_ppid ',' snd_context '}' {
+: '{' snd_sid ',' snd_flags ',' snd_ppid ',' snd_context ',' snd_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 = $10;
 }
 ;
 
diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index 5c5c426c9aeb78103848f3fbf5794ffce03dcdfd..81db1ed1e57fd184ffb639809e31281694238f50 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -59,7 +59,18 @@ struct sctp_tlv {
 static int check_sctp_notification(struct iovec *iov, struct expression *iovec_expr,
 				   char **error);
 #endif
-
+#if defined(__FreeBSD__)
+static int parse_expression_to_sctp_sndinfo(struct expression *expr, struct sctp_sndinfo *info,
+				            char **error);
+static int parse_expression_to_sctp_prinfo(struct expression *expr, struct sctp_prinfo *info,
+				            char **error);
+static int parse_expression_to_sctp_authinfo(struct expression *expr, struct sctp_authinfo *info,
+				             char **error);
+#endif
+#if defined(SCTP_DEFAULT_SNDINFO) || defined(SCTP_SNDINFO)
+static int check_sctp_sndinfo(struct sctp_sndinfo_expr *expr, struct sctp_sndinfo *sctp_sndinfo,
+			      char **error);
+#endif
 
 /* Provide a wrapper for the Linux gettid() system call (glibc does not). */
 static pid_t gettid(void)
@@ -420,6 +431,69 @@ static int get_sockstorage_arg(struct expression *arg, struct sockaddr_storage *
 }
 #endif
 
+static int check_sockaddr(struct expression *sockaddr_expr, struct sockaddr *live_addr, char **error) {
+
+	if (sockaddr_expr->type != EXPR_ELLIPSIS) {
+		struct sockaddr *script_addr;
+		if (sockaddr_expr->type == EXPR_SOCKET_ADDRESS_IPV4) {
+			script_addr = (struct sockaddr*)sockaddr_expr->value.socket_address_ipv4;
+		} else if (sockaddr_expr->type == EXPR_SOCKET_ADDRESS_IPV6) {
+			script_addr = (struct sockaddr*)sockaddr_expr->value.socket_address_ipv6;
+		} else {
+			asprintf(error, "Bad type for sockaddr");
+			return STATUS_ERR;
+		}
+		if (script_addr->sa_family != live_addr->sa_family) {
+			asprintf(error, "sockaddr sa_family expected: %d actual: %d",
+				 script_addr->sa_family, live_addr->sa_family);
+			return STATUS_ERR;
+		}
+		switch(script_addr->sa_family) {
+		case AF_INET:
+			{
+				struct sockaddr_in *script_sockaddr = (struct sockaddr_in*)script_addr;
+				struct sockaddr_in *live_sockaddr = (struct sockaddr_in*)live_addr;
+				if (live_sockaddr->sin_port != script_sockaddr->sin_port) {
+					asprintf(error, "sockaddr_in from.sinport. expected: %d actual %d",
+						ntohs(script_sockaddr->sin_port), ntohs(live_sockaddr->sin_port));
+					return STATUS_ERR;
+				}
+				if (live_sockaddr->sin_addr.s_addr != script_sockaddr->sin_addr.s_addr) {
+					int len = strnlen(inet_ntoa(script_sockaddr->sin_addr), 16);
+					char *expected_addr = malloc(sizeof(char) * len);
+					memcpy(expected_addr, inet_ntoa(script_sockaddr->sin_addr), len);
+					asprintf(error, "sockaddr_in from.sin_addr. expected: %s actual %s",
+						expected_addr, inet_ntoa(live_sockaddr->sin_addr));
+					free(expected_addr);
+					return STATUS_ERR;
+				}
+			}
+			break;
+		case AF_INET6:
+			{
+				struct sockaddr_in6 *script_sockaddr = (struct sockaddr_in6*)script_addr;
+				struct sockaddr_in6 *live_sockaddr = (struct sockaddr_in6*)live_addr;
+				if (live_sockaddr->sin6_port != script_sockaddr->sin6_port) {
+					asprintf(error, "sockaddr_in6 from.sinport. expected: %d actual %d",
+						ntohs(script_sockaddr->sin6_port), ntohs(live_sockaddr->sin6_port));
+					return STATUS_ERR;
+				}
+				if (live_sockaddr->sin6_addr.s6_addr != script_sockaddr->sin6_addr.s6_addr) {
+					char expected_addr[INET6_ADDRSTRLEN];
+					char live_addr[INET6_ADDRSTRLEN];
+					inet_ntop(AF_INET6, &script_sockaddr->sin6_addr, expected_addr, INET6_ADDRSTRLEN);
+					inet_ntop(AF_INET6, &live_sockaddr->sin6_addr, live_addr, INET6_ADDRSTRLEN);
+					asprintf(error, "sockaddr_in6 from.sin6_addr. expected: %s actual %s",
+						 expected_addr, live_addr);
+					return STATUS_ERR;
+				}
+			}
+			break;
+		}
+	}
+	return STATUS_OK;
+}
+
 #if defined(__FreeBSD__) || defined(linux)
 int check_u8_expr(struct expression *expr, u8 value, char *val_name, char **error) {
 	if (expr->type != EXPR_ELLIPSIS) {
@@ -470,7 +544,7 @@ int check_s32_expr(struct expression *expr, s16 value, char *val_name, char **er
 }
 
 #if defined(__FreeBSD__) || defined(linux)
-int check_u32_expr(struct expression *expr, u16 value, char *val_name, char **error) {
+int check_u32_expr(struct expression *expr, u32 value, char *val_name, char **error) {
 	if (expr->type != EXPR_ELLIPSIS) {
 		u32 script_val;
 
@@ -601,6 +675,123 @@ error_out:
 	return status;
 }
 
+/* Allocate and fill in an 
+cmsghdr described by the given expression.
+ * Return STATUS_OK if the expression is a valid cmsghdr. Otherwise
+ * fill in the error with a human-readable error message and return
+ * STATUS_ERR.
+ */
+static int cmsg_new(struct expression *expression,
+		    void **cmsg_ptr, size_t *cmsg_len_ptr, char **error)
+{
+	struct expression_list *list;
+	int list_len = 0, i = 0;
+	size_t cmsg_size = 0;
+	struct cmsghdr *cmsg;
+
+	if (check_type(expression, EXPR_LIST, error))
+		return STATUS_ERR;
+	list = expression->value.list;
+	list_len = expression_list_length(list);
+	//calc size of cmsg in list
+	if (list_len == 0){
+		cmsg_ptr = NULL;
+		return STATUS_OK;
+	}
+	for (i = 0; i < list_len; i++) {
+		struct expression *cmsg_expr;
+		cmsg_expr = get_arg(list, i, error);
+		switch (cmsg_expr->value.cmsghdr->cmsg_data->type) {
+		case EXPR_SCTP_SNDINFO:
+			cmsg_size += CMSG_SPACE(sizeof(struct sctp_sndinfo));
+			break;
+		case EXPR_SCTP_PRINFO:
+			cmsg_size += CMSG_SPACE(sizeof(struct sctp_prinfo));
+			break;
+		case EXPR_SCTP_AUTHINFO:
+			cmsg_size += CMSG_SPACE(sizeof(struct sctp_authinfo));
+			break;
+		case EXPR_SOCKET_ADDRESS_IPV4:
+			cmsg_size += CMSG_SPACE(sizeof(struct in_addr));
+			break;
+		case EXPR_SOCKET_ADDRESS_IPV6:
+			cmsg_size += CMSG_SPACE(sizeof(struct in6_addr));
+			break;
+		default:
+			asprintf(error,"cmsg %d type not valid", i);
+			return STATUS_ERR;
+		}
+	}
+
+	*cmsg_len_ptr = cmsg_size;
+	cmsg = calloc(1, cmsg_size);
+	*cmsg_ptr = (void *)cmsg;
+		
+	for (i = 0; i < list_len; i++) {
+		struct expression *expr;
+		struct cmsghdr_expr *cmsg_expr;
+
+		expr = get_arg(list, i, error);
+		if(check_type(expr, EXPR_CMSGHDR, error))
+			goto error_out;
+		cmsg_expr = expr->value.cmsghdr;
+		if (get_u32(cmsg_expr->cmsg_len, &cmsg->cmsg_len, error))
+			goto error_out;
+		if (get_s32(cmsg_expr->cmsg_level, &cmsg->cmsg_level, error))
+			goto error_out;
+		if (get_s32(cmsg_expr->cmsg_type, &cmsg->cmsg_type, error))
+			goto error_out;
+
+		switch(cmsg_expr->cmsg_data->type) {
+		case EXPR_SCTP_SNDINFO: {
+			struct sctp_sndinfo info;			
+			if (parse_expression_to_sctp_sndinfo(cmsg_expr->cmsg_data, &info, error)) {
+				goto error_out;
+			}
+			memcpy(CMSG_DATA(cmsg), &info, sizeof(struct sctp_sndinfo)); 
+			cmsg = (struct cmsghdr *) ((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
+			break;
+		}
+		case EXPR_SCTP_PRINFO: {
+			struct sctp_prinfo info;			
+			if (parse_expression_to_sctp_prinfo(cmsg_expr->cmsg_data, &info, error)) {
+				goto error_out;
+			}
+			memcpy(CMSG_DATA(cmsg), &info, sizeof(struct sctp_prinfo)); 
+			cmsg = (struct cmsghdr *) ((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
+			break;
+		}		
+		case EXPR_SCTP_AUTHINFO: {
+			struct sctp_authinfo info;			
+			if (parse_expression_to_sctp_authinfo(cmsg_expr->cmsg_data, &info, error)) {
+				goto error_out;
+			}
+			memcpy(CMSG_DATA(cmsg), &info, sizeof(struct sctp_authinfo)); 
+			cmsg = (struct cmsghdr *) ((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
+			break;
+		}		
+		case EXPR_SOCKET_ADDRESS_IPV4:
+			memcpy(CMSG_DATA(cmsg), &cmsg_expr->cmsg_data->value.socket_address_ipv4->sin_addr, sizeof(struct in_addr));
+			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
+			break;
+		case EXPR_SOCKET_ADDRESS_IPV6:
+			memcpy(CMSG_DATA(cmsg), &cmsg_expr->cmsg_data->value.socket_address_ipv6->sin6_addr, sizeof(struct in6_addr));
+			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
+			break;
+		default:
+			asprintf(error,"cmsg.cmsg_data %d type not valid", i);
+			goto error_out;
+		}
+	}
+
+	return STATUS_OK;
+error_out:
+	free(*cmsg_ptr);
+	*cmsg_ptr = NULL;
+	*cmsg_len_ptr = 0;
+	return STATUS_ERR;
+}
+
 /* Free all the space used by the given msghdr. */
 static void msghdr_free(struct msghdr *msg, size_t iov_len)
 {
@@ -622,6 +813,7 @@ static int msghdr_new(struct expression *expression,
 	struct msghdr_expr *msg_expr;	/* input expression from script */
 	socklen_t name_len = sizeof(struct sockaddr_storage);
 	struct msghdr *msg = NULL;	/* live output */
+	size_t cmsg_len = 0;
 
 	if (check_type(expression, EXPR_MSGHDR, error))
 		goto error_out;
@@ -659,14 +851,29 @@ static int msghdr_new(struct expression *expression,
 		goto error_out;
 	}
 
+	if (msg_expr->msg_control != NULL) {
+		if (cmsg_new(msg_expr->msg_control, &msg->msg_control, &cmsg_len, error))
+			goto error_out;
+	}
+
+	if (msg_expr->msg_controllen != NULL) {
+		if (get_u32(msg_expr->msg_controllen, &msg->msg_controllen, error))
+			goto error_out;
+	}
+
+	if (msg->msg_controllen != cmsg_len) {
+		asprintf(error,
+			 "msg_controllen %u does not match %u size of cmsghdr array",
+			 msg->msg_controllen, cmsg_len);
+		goto error_out;
+	}
+
 	if (msg_expr->msg_flags != NULL) {
 		if (get_s32(msg_expr->msg_flags, &s32_val, error))
 			goto error_out;
 		msg->msg_flags = s32_val;
 	}
 
-	/* TODO(ncardwell): msg_control, msg_controllen */
-
 	status = STATUS_OK;
 
 error_out:
@@ -1679,6 +1886,105 @@ static int syscall_sendto(struct state *state, struct syscall_spec *syscall,
 	return status;
 }
 
+static int check_cmsghdr(struct expression *expr_list, struct msghdr *msg, char  **error) {
+	struct expression_list *list;
+	struct expression *cmsg_expr;
+	struct cmsghdr *cmsg_ptr;
+	int cnt=0;
+
+	assert(expr_list->type == EXPR_LIST);
+
+	list = expr_list->value.list;
+	for (cmsg_ptr = CMSG_FIRSTHDR(msg); cmsg_ptr != NULL; cmsg_ptr = CMSG_NXTHDR(msg, cmsg_ptr)) {
+		cmsg_expr = get_arg(list, cnt, error);
+		if (cmsg_expr->type != EXPR_ELLIPSIS) {
+			struct cmsghdr_expr *expr;
+			expr = cmsg_expr->value.cmsghdr;
+			if (check_u32_expr(expr->cmsg_len, cmsg_ptr->cmsg_len,
+					   "cmsghdr.cmsg_len", error))
+				return STATUS_ERR;
+			if (check_s32_expr(expr->cmsg_level, cmsg_ptr->cmsg_level,
+					   "cmsghdr.cmsg_level", error))
+				return STATUS_ERR;
+			if (check_s32_expr(expr->cmsg_type, cmsg_ptr->cmsg_type,
+					   "cmsghdr.cmsg_type", error))
+				return STATUS_ERR;
+
+			if (expr->cmsg_data->type == EXPR_ELLIPSIS) {
+				continue;
+			}
+			switch(cmsg_ptr->cmsg_type) {
+#ifdef SCTP_SNDINFO
+			case SCTP_SNDINFO:
+				if (check_sctp_sndinfo(expr->cmsg_data->value.sctp_sndinfo,
+						       (struct sctp_sndinfo *) CMSG_DATA(cmsg_ptr),
+						       error)) {
+					return STATUS_ERR;
+				}
+				break;
+#endif
+#ifdef SCTP_PRINFO
+			case SCTP_PRINFO:
+				if (check_u16_expr(expr->cmsg_data->value.sctp_prinfo->pr_policy,
+					   ((struct sctp_prinfo *)CMSG_DATA(cmsg_ptr))->pr_policy,
+					   "prinfo.pr_policy", error))
+					return STATUS_ERR;
+				if (check_u32_expr(expr->cmsg_data->value.sctp_prinfo->pr_value,
+					   ((struct sctp_prinfo *)CMSG_DATA(cmsg_ptr))->pr_value,
+					   "prinfo.pr_value", error))
+					return STATUS_ERR;
+				break;
+#endif
+#ifdef SCTP_AUTHINFO
+			case SCTP_AUTHINFO:
+				if (check_u16_expr(expr->cmsg_data->value.sctp_authinfo->auth_keynumber,
+					   ((struct sctp_authinfo *)CMSG_DATA(cmsg_ptr))->auth_keynumber,
+					   "authinfo.auth_keynumber", error))
+					return STATUS_ERR;
+				break;
+#endif
+#ifdef SCTP_DSTADDRV4
+			case SCTP_DSTADDRV4:
+				if (expr->cmsg_data->type != EXPR_ELLIPSIS) {
+					struct sockaddr_in *addr = expr->cmsg_data->value.socket_address_ipv4;
+					struct in_addr *cmsg_addr = (struct in_addr *) CMSG_DATA(cmsg_ptr);
+					if (addr->sin_addr.s_addr != cmsg_addr->s_addr) {
+						asprintf(error, "cmsg_data for SCTP_DSTADDRV4: expected: %s actual: %s",
+							 inet_ntoa(addr->sin_addr),
+							 inet_ntoa(*cmsg_addr));
+						return STATUS_ERR;
+					}
+				}
+				break;
+#endif
+#ifdef SCTP_DSTADDRV6
+			case SCTP_DSTADDRV6:
+				if (expr->cmsg_data->type != EXPR_ELLIPSIS) {
+					struct sockaddr_in6 *addr = expr->cmsg_data->value.socket_address_ipv6;
+					struct in6_addr *cmsg_addr = (struct in6_addr *) CMSG_DATA(cmsg_ptr);
+					if (memcmp(&addr->sin6_addr, cmsg_addr, sizeof(struct in6_addr))) {
+						char expected_addr[INET6_ADDRSTRLEN];
+						char live_addr[INET6_ADDRSTRLEN];
+						inet_ntop(AF_INET6, &addr->sin6_addr, expected_addr, INET6_ADDRSTRLEN);
+						inet_ntop(AF_INET6, cmsg_addr, live_addr, INET6_ADDRSTRLEN);
+						asprintf(error, "sockaddr_in6 from.sin6_addr. expected: %s actual %s",
+							 expected_addr, live_addr);
+						return STATUS_ERR;
+					}
+					
+				}
+				break;
+#endif
+			default:
+				asprintf(error, "can't check cmsg type");
+				return STATUS_ERR;
+			}
+		}
+		cnt++;
+	}
+	return STATUS_OK;	
+}
+
 static int syscall_sendmsg(struct state *state, struct syscall_spec *syscall,
 			   struct expression_list *args, char **error)
 {
@@ -1714,10 +2020,13 @@ static int syscall_sendmsg(struct state *state, struct syscall_spec *syscall,
 	}
 
 	begin_syscall(state, syscall);
-
+	
 	result = sendmsg(live_fd, msg, flags);
 
-	status = end_syscall(state, syscall, CHECK_EXACT, result, error);
+	if (end_syscall(state, syscall, CHECK_EXACT, result, error))
+		goto error_out;
+
+	 status = check_cmsghdr(msg_expression->value.msghdr->msg_control, msg, error);
 
 error_out:
 	msghdr_free(msg, iov_len);
@@ -2143,7 +2452,8 @@ static int check_sctp_event_subscribe(struct sctp_event_subscribe_expr *expr,
 	return STATUS_OK;
 }
 #endif
-#ifdef SCTP_DEFAULT_SNDINFO
+
+#if defined(SCTP_DEFAULT_SNDINFO) || defined(SCTP_SNDINFO)
 static int check_sctp_sndinfo(struct sctp_sndinfo_expr *expr,
 			      struct sctp_sndinfo *sctp_sndinfo,
 			      char **error)
@@ -2169,6 +2479,9 @@ static int check_sctp_sndinfo(struct sctp_sndinfo_expr *expr,
 	if (check_u32_expr(expr->snd_context, sctp_sndinfo->snd_context,
 			   "sctp_sndinfo.snd_context", error))
 		return STATUS_ERR;
+	if (check_u32_expr(expr->snd_assoc_id, sctp_sndinfo->snd_assoc_id,
+			   "sctp_sndinfo.snd_assoc_id", error))
+		return STATUS_ERR;
 
 	return STATUS_OK;
 }
@@ -2330,7 +2643,12 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall,
 	case EXPR_SCTP_SNDINFO:
 		live_optval = malloc(sizeof(struct sctp_sndinfo));
 		live_optlen = sizeof(struct sctp_sndinfo);
-		((struct sctp_sndinfo *)live_optval)->snd_assoc_id = 0;
+		if (get_u32(val_expression->value.sctp_sndinfo->snd_assoc_id,
+			    &((struct sctp_sndinfo *)live_optval)->snd_assoc_id,
+			    error)) {
+			free(live_optval);
+			return STATUS_ERR;
+		}
 		break;
 #endif
 #ifdef SCTP_ADAPTATION_LAYER
@@ -2714,7 +3032,6 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 #endif
 #ifdef SCTP_DEFAULT_SNDINFO
 	case EXPR_SCTP_SNDINFO:
-		sndinfo.snd_assoc_id = 0;
 		if (get_u16(val_expression->value.sctp_sndinfo->snd_sid,
 			    &sndinfo.snd_sid, error)) {
 			return STATUS_ERR;
@@ -2731,6 +3048,10 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall,
 			    &sndinfo.snd_context, error)) {
 			return STATUS_ERR;
 		}
+		if (get_u32(val_expression->value.sctp_sndinfo->snd_assoc_id,
+			    &sndinfo.snd_assoc_id, error)) {
+			return STATUS_ERR;
+		}
 		optval = &sndinfo;
 		break;
 #endif
@@ -2981,68 +3302,6 @@ static int check_sctp_sndrcvinfo(struct sctp_sndrcvinfo_expr *expr,
 	return STATUS_OK;
 }
 
-static int check_sockaddr(struct expression *sockaddr_expr, struct sockaddr *live_addr, char **error) {
-
-	if (sockaddr_expr->type != EXPR_ELLIPSIS) {
-		struct sockaddr *script_addr;
-		if (sockaddr_expr->type == EXPR_SOCKET_ADDRESS_IPV4) {
-			script_addr = (struct sockaddr*)sockaddr_expr->value.socket_address_ipv4;
-		} else if (sockaddr_expr->type == EXPR_SOCKET_ADDRESS_IPV6) {
-			script_addr = (struct sockaddr*)sockaddr_expr->value.socket_address_ipv6;
-		} else {
-			asprintf(error, "Bad type for sockaddr");
-			return STATUS_ERR;
-		}
-		if (script_addr->sa_family != live_addr->sa_family) {
-			asprintf(error, "sockaddr sa_family expected: %d actual: %d",
-				 script_addr->sa_family, live_addr->sa_family);
-			return STATUS_ERR;
-		}
-		switch(script_addr->sa_family) {
-		case AF_INET:
-			{
-				struct sockaddr_in *script_sockaddr = (struct sockaddr_in*)script_addr;
-				struct sockaddr_in *live_sockaddr = (struct sockaddr_in*)live_addr;
-				if (live_sockaddr->sin_port != script_sockaddr->sin_port) {
-					asprintf(error, "sockaddr_in from.sinport. expected: %d actual %d",
-						ntohs(script_sockaddr->sin_port), ntohs(live_sockaddr->sin_port));
-					return STATUS_ERR;
-				}
-				if (live_sockaddr->sin_addr.s_addr != script_sockaddr->sin_addr.s_addr) {
-					int len = strnlen(inet_ntoa(script_sockaddr->sin_addr), 16);
-					char *expected_addr = malloc(sizeof(char) * len);
-					memcpy(expected_addr, inet_ntoa(script_sockaddr->sin_addr), len);
-					asprintf(error, "sockaddr_in from.sin_addr. expected: %s actual %s",
-						expected_addr, inet_ntoa(live_sockaddr->sin_addr));
-					free(expected_addr);
-					return STATUS_ERR;
-				}
-			}
-			break;
-		case AF_INET6:
-			{
-				struct sockaddr_in6 *script_sockaddr = (struct sockaddr_in6*)script_addr;
-				struct sockaddr_in6 *live_sockaddr = (struct sockaddr_in6*)live_addr;
-				if (live_sockaddr->sin6_port != script_sockaddr->sin6_port) {
-					asprintf(error, "sockaddr_in6 from.sinport. expected: %d actual %d",
-						ntohs(script_sockaddr->sin6_port), ntohs(live_sockaddr->sin6_port));
-					return STATUS_ERR;
-				}
-				if (live_sockaddr->sin6_addr.s6_addr != script_sockaddr->sin6_addr.s6_addr) {
-					char expected_addr[INET6_ADDRSTRLEN];
-					char live_addr[INET6_ADDRSTRLEN];
-					inet_ntop(AF_INET6, &script_sockaddr->sin6_addr, expected_addr, INET6_ADDRSTRLEN);
-					inet_ntop(AF_INET6, &live_sockaddr->sin6_addr, live_addr, INET6_ADDRSTRLEN);
-					asprintf(error, "sockaddr_in6 from.sin6_addr. expected: %s actual %s",
-						 expected_addr, live_addr);
-					return STATUS_ERR;
-				}
-			}
-			break;
-		}
-	}
-	return STATUS_OK;
-}
 #endif
 
 static int syscall_sctp_recvmsg(struct state *state, struct syscall_spec *syscall,
@@ -3127,7 +3386,6 @@ static int syscall_sctp_recvmsg(struct state *state, struct syscall_spec *syscal
 static int parse_expression_to_sctp_sndinfo(struct expression *expr, struct sctp_sndinfo *info, char **error) {
 	if (expr->type == EXPR_SCTP_SNDINFO) {
 		struct sctp_sndinfo_expr *sndinfo_expr = expr->value.sctp_sndinfo;
-		info->snd_assoc_id = 0;
 		if (get_u16(sndinfo_expr->snd_sid, &info->snd_sid, error)) {
 			return STATUS_ERR;
 		}
@@ -3140,6 +3398,9 @@ static int parse_expression_to_sctp_sndinfo(struct expression *expr, struct sctp
 		if (get_u32(sndinfo_expr->snd_context, &info->snd_context, error)) {
 			return STATUS_ERR;
 		}
+		if (get_u32(sndinfo_expr->snd_assoc_id, &info->snd_assoc_id, error)) {
+			return STATUS_ERR;
+		}
 	} else {
 		return STATUS_ERR;
 	}
@@ -3792,7 +4053,6 @@ static int check_sctp_notification(struct iovec *iov,
 				return STATUS_ERR;
 			break;
 		case EXPR_ELLIPSIS:
-			printf("check Ellipsis\n");
 			break;
 		default:
 			asprintf(error, "Bad type for iov_base. Can't check type %s",
diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c
index 336374356ad389bd00034b6d481c417767d348d8..58604198be75911c62d284e264349820ee1ca0da 100644
--- a/gtests/net/packetdrill/script.c
+++ b/gtests/net/packetdrill/script.c
@@ -65,6 +65,7 @@ struct expression_type_entry expression_type_table[] = {
 	{ EXPR_LIST,                 "list" },
 	{ EXPR_IOVEC,                "iovec" },
 	{ EXPR_MSGHDR,               "msghdr" },
+	{ EXPR_CMSGHDR,              "cmsghdr"},
 	{ EXPR_POLLFD,               "pollfd" },
 	{ EXPR_SCTP_RTOINFO,         "sctp_rtoinfo"},
 	{ EXPR_SCTP_INITMSG,         "sctp_initmsg"},
@@ -394,6 +395,7 @@ void free_expression(struct expression *expression)
 		free_expression(expression->value.sctp_sndinfo->snd_flags);
 		free_expression(expression->value.sctp_sndinfo->snd_ppid);
 		free_expression(expression->value.sctp_sndinfo->snd_context);
+		free_expression(expression->value.sctp_sndinfo->snd_assoc_id);
 		break;		
 	case EXPR_SCTP_SETADAPTATION:
 		free_expression(expression->value.sctp_setadaptation->ssb_adaptation_ind);
@@ -563,8 +565,16 @@ void free_expression(struct expression *expression)
 		free_expression(expression->value.msghdr->msg_namelen);
 		free_expression(expression->value.msghdr->msg_iov);
 		free_expression(expression->value.msghdr->msg_iovlen);
+		free_expression(expression->value.msghdr->msg_control);
+		free_expression(expression->value.msghdr->msg_controllen);
 		free_expression(expression->value.msghdr->msg_flags);
 		break;
+	case EXPR_CMSGHDR:
+		free_expression(expression->value.cmsghdr->cmsg_len);
+		free_expression(expression->value.cmsghdr->cmsg_level);
+		free_expression(expression->value.cmsghdr->cmsg_type);
+		free_expression(expression->value.cmsghdr->cmsg_data);
+		break;
 	case EXPR_POLLFD:
 		assert(expression->value.pollfd);
 		free_expression(expression->value.pollfd->fd);
@@ -656,6 +666,33 @@ static int evaluate_iovec_expression(struct expression *in,
 	return STATUS_OK;
 }
 
+static int evaluate_cmsghdr_expression(struct expression *in,
+				       struct expression *out, char **error)
+{
+	struct cmsghdr_expr *in_cmsg;
+	struct cmsghdr_expr *out_cmsg;
+
+	assert(in->type == EXPR_CMSGHDR);
+	assert(in->value.msghdr);
+	assert(out->type == EXPR_CMSGHDR);
+
+	out->value.cmsghdr = calloc(1, sizeof(struct cmsghdr_expr));
+
+	in_cmsg = in->value.cmsghdr;
+	out_cmsg = out->value.cmsghdr;
+
+	if (evaluate(in_cmsg->cmsg_len,		&out_cmsg->cmsg_len,	error))
+		return STATUS_ERR;
+	if (evaluate(in_cmsg->cmsg_level,	&out_cmsg->cmsg_level,	error))
+		return STATUS_ERR;
+	if (evaluate(in_cmsg->cmsg_type,	&out_cmsg->cmsg_type,	error))
+		return STATUS_ERR;
+	if (evaluate(in_cmsg->cmsg_data,	&out_cmsg->cmsg_data,	error))
+		return STATUS_ERR;
+
+	return STATUS_OK;
+}
+
 static int evaluate_msghdr_expression(struct expression *in,
 				      struct expression *out, char **error)
 {
@@ -679,6 +716,10 @@ static int evaluate_msghdr_expression(struct expression *in,
 		return STATUS_ERR;
 	if (evaluate(in_msg->msg_iovlen,	&out_msg->msg_iovlen,	error))
 		return STATUS_ERR;
+	if (evaluate(in_msg->msg_control,	&out_msg->msg_control,	error))
+		return STATUS_ERR;
+	if (evaluate(in_msg->msg_controllen,	&out_msg->msg_controllen,error))
+		return STATUS_ERR;
 	if (evaluate(in_msg->msg_flags,		&out_msg->msg_flags,	error))
 		return STATUS_ERR;
 
@@ -1159,6 +1200,10 @@ static int evaluate_sctp_sndinfo_expression(struct expression *in,
 		     &out_sndinfo->snd_context,
 		     error))
 		return STATUS_ERR;
+	if (evaluate(in_sndinfo->snd_assoc_id,
+		     &out_sndinfo->snd_assoc_id,
+		     error))
+		return STATUS_ERR;
 	return STATUS_OK;
 }
 
@@ -2065,6 +2110,9 @@ static int evaluate(struct expression *in,
 	case EXPR_MSGHDR:
 		result = evaluate_msghdr_expression(in, out, error);
 		break;
+	case EXPR_CMSGHDR:
+		result = evaluate_cmsghdr_expression(in, out, error);
+		break;
 	case EXPR_POLLFD:
 		result = evaluate_pollfd_expression(in, out, error);
 		break;
diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h
index bb60524ff45952a372108df958fdfbef5f63567a..5dccd49ca7b55432e1c8cf326e6f04379d471f6d 100644
--- a/gtests/net/packetdrill/script.h
+++ b/gtests/net/packetdrill/script.h
@@ -45,6 +45,7 @@ enum expression_t {
 	EXPR_LIST,		  /* list of expressions */
 	EXPR_IOVEC,		  /* expression tree for an iovec struct */
 	EXPR_MSGHDR,		  /* expression tree for a msghdr struct */
+	EXPR_CMSGHDR,             /* expression tree for a cmsghdr struct */
 	EXPR_POLLFD,		  /* expression tree for a pollfd struct */
 	EXPR_SCTP_RTOINFO,	  /* struct sctp_rtoinfo for SCTP_RTOINFO */
 	EXPR_SCTP_INITMSG,	  /* struct sctp_initmsg for SCTP_INITMSG */
@@ -95,6 +96,7 @@ struct expression {
 		struct expression_list *list;
 		struct iovec_expr *iovec;
 		struct msghdr_expr *msghdr;
+		struct cmsghdr_expr *cmsghdr;
 		struct pollfd_expr *pollfd;
 		struct sctp_rtoinfo_expr *sctp_rtoinfo;
 		struct sctp_initmsg_expr *sctp_initmsg;
@@ -158,9 +160,19 @@ struct msghdr_expr {
 	struct expression *msg_namelen;
 	struct expression *msg_iov;
 	struct expression *msg_iovlen;
+	struct expression *msg_control;
+	struct expression *msg_controllen;
 	struct expression *msg_flags;
 };
 
+/* Parse tree for a cmsghdr struct in a struct msghdr. */
+struct cmsghdr_expr {
+	struct expression *cmsg_len;
+	struct expression *cmsg_level;
+	struct expression *cmsg_type;
+	struct expression *cmsg_data;
+};
+
 /* Parse tree for a pollfd struct in a poll syscall. */
 struct pollfd_expr {
 	struct expression *fd;		/* file descriptor */
@@ -274,6 +286,7 @@ struct sctp_sndinfo_expr {
 	struct expression *snd_flags;
 	struct expression *snd_ppid;
 	struct expression *snd_context;
+	struct expression *snd_assoc_id;
 };
 
 /* Parse tree for sctp_setadaptation struct in [gs]etsockopt syscall. */
diff --git a/gtests/net/packetdrill/sctp.h b/gtests/net/packetdrill/sctp.h
index dc9d2051513aca263324290f056af93ef26bfb98..0c737cf6ea67070986509d8604b8a7925e43e24e 100644
--- a/gtests/net/packetdrill/sctp.h
+++ b/gtests/net/packetdrill/sctp.h
@@ -244,8 +244,10 @@ struct sctp_pad_chunk {
 #define SCTP_ECN_CAPABLE_PARAMETER_TYPE			0x8000
 #define SCTP_SUPPORTED_EXTENSIONS_PARAMETER_TYPE	0x8008
 #define SCTP_PAD_PARAMETER_TYPE				0x8005
+#define SCTP_Set_Primary_Address			0xc004
+#define SCTP_ADAPTATION_INDICATION_PARAMETER_TYPE	0xc006
 
-#define MAX_SCTP_PARAMETER_BYTES	0xffff
+#define MAX_SCTP_PARAMETER_BYTES			0xffff
 
 struct sctp_parameter {
 	__be16 type;
@@ -318,6 +320,12 @@ struct sctp_pad_parameter {
 	__be16 padding_data[];
 } __packed;
 
+struct sctp_adaptation_indication_parameter {
+	__be16 type;
+	__be16 length;
+	__be32 adaptation_code_point;
+} __packed;
+
 #define SCTP_INVALID_STREAM_IDENTIFIER_CAUSE_CODE	0x0001
 #define SCTP_MISSING_MANDATORY_PARAMETER_CAUSE_CODE	0x0002
 #define SCTP_STALE_COOKIE_ERROR_CAUSE_CODE		0x0003
diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c
index 8dc2ca83547de2a6f006d252430c66093c944937..027873a947c3b8b21fa4eec314a20a63a29a1ee2 100644
--- a/gtests/net/packetdrill/sctp_chunk_to_string.c
+++ b/gtests/net/packetdrill/sctp_chunk_to_string.c
@@ -338,6 +338,27 @@ static int sctp_unknown_parameter_to_string(
 	return STATUS_OK;
 }
 
+static int sctp_adaptation_indication_parameter_to_string(
+	FILE *s,
+	struct sctp_adaptation_indication_parameter *parameter,
+	char **error)
+{
+	u16 length;
+
+	length = ntohs(parameter->length);
+	if (length < sizeof(struct sctp_adaptation_indication_parameter)) {
+		asprintf(error, "PARAMETER too short (type=0x%04x, length=%u)",
+			 ntohs(parameter->type), length);
+		return STATUS_ERR;
+	}
+	fputs("ADAPTATION_INDICATION[", s);
+	fprintf(s, "type=0x%04x, ", ntohs(parameter->type));
+	fprintf(s, "len=%hu, ", ntohs(parameter->length));
+	fprintf(s, "val=%u", ntohl(parameter->adaptation_code_point));
+	fputs("]", s);
+	return STATUS_OK;
+}
+
 static int sctp_parameter_to_string(FILE *s,
 				    struct sctp_parameter *parameter,
 				    char **error)
@@ -394,6 +415,10 @@ static int sctp_parameter_to_string(FILE *s,
 		result = sctp_pad_parameter_to_string(s,
 			(struct sctp_pad_parameter *)parameter, error);
 		break;
+	case SCTP_ADAPTATION_INDICATION_PARAMETER_TYPE:
+		result = sctp_adaptation_indication_parameter_to_string(s,
+			(struct sctp_adaptation_indication_parameter *)parameter, error);
+		break;
 	default:
 		result = sctp_unknown_parameter_to_string(s, parameter, error);
 		break;
diff --git a/gtests/net/packetdrill/sctp_packet.c b/gtests/net/packetdrill/sctp_packet.c
index 70f81259f54ced9e77c0898e8284e4a2c2cf8d49..5ddca4a72b388f1d5488bd6dd00a9e19e97d0f71 100644
--- a/gtests/net/packetdrill/sctp_packet.c
+++ b/gtests/net/packetdrill/sctp_packet.c
@@ -1611,6 +1611,33 @@ sctp_supported_extensions_parameter_new(struct sctp_byte_list *list)
 	                                    parameter_length, flags);
 }
 
+struct sctp_parameter_list_item *
+sctp_adaptation_indication_parameter_new(s64 val)
+{
+	u32 flags;
+	struct sctp_adaptation_indication_parameter *parameter;
+	u16 parameter_length;
+
+	flags = 0;
+	parameter_length = sizeof(struct sctp_adaptation_indication_parameter);
+
+	parameter = malloc(parameter_length);
+	assert(parameter != NULL);
+	memset(parameter, 0, parameter_length);
+
+	parameter->type = htons(SCTP_ADAPTATION_INDICATION_PARAMETER_TYPE);
+	parameter->length = htons(parameter_length);
+	if (val == -1) {
+		parameter->adaptation_code_point = htonl(0);
+		flags |= FLAG_PARAMETER_VALUE_NOCHECK;
+	} else {
+		assert(is_valid_u32(val));
+		parameter->adaptation_code_point = htonl((u32)val);
+	}
+	return sctp_parameter_list_item_new((struct sctp_parameter *)parameter,
+	                                    parameter_length, flags);
+}
+
 struct sctp_parameter_list_item *
 sctp_pad_parameter_new(s64 len, u8 *padding)
 {
diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h
index c32e8d9d6878ed480890735478ec254c21483741..b492ebc736cb5e504e079ac981e59d1f3b933639 100644
--- a/gtests/net/packetdrill/sctp_packet.h
+++ b/gtests/net/packetdrill/sctp_packet.h
@@ -340,6 +340,9 @@ sctp_ecn_capable_parameter_new(void);
 struct sctp_parameter_list_item *
 sctp_pad_parameter_new(s64 len, u8 *padding);
 
+struct sctp_parameter_list_item *
+sctp_adaptation_indication_parameter_new(s64 val);
+
 struct sctp_parameter_list_item *
 sctp_supported_extensions_parameter_new(struct sctp_byte_list *list);
 
diff --git a/gtests/net/packetdrill/symbols_freebsd.c b/gtests/net/packetdrill/symbols_freebsd.c
index 9b0bc90bc370a39d4290c88fcd923801218762ad..b8d5288ba0690bbab275a8ebdce2e20e5ccc7cc0 100644
--- a/gtests/net/packetdrill/symbols_freebsd.c
+++ b/gtests/net/packetdrill/symbols_freebsd.c
@@ -82,6 +82,7 @@ struct int_symbol platform_symbols_table[] = {
 	{ SCTP_RTOINFO,                     "SCTP_RTOINFO"                    },
 	{ SCTP_ASSOCINFO,                   "SCTP_ASSOCINFO"                  },
 	{ SCTP_INITMSG,                     "SCTP_INITMSG"                    },
+	{ SCTP_INIT,                        "SCTP_INIT"                       },
 	{ SCTP_NODELAY,                     "SCTP_NODELAY"                    },
 	{ SCTP_ADAPTATION_LAYER,	    "SCTP_ADAPTATION_LAYER"           },
 	{ SCTP_MAXSEG,                      "SCTP_MAXSEG"                     },
@@ -221,6 +222,11 @@ struct int_symbol platform_symbols_table[] = {
 	{ SCTP_ADDR_UNREACHABLE,            "SCTP_ADDR_UNREACHABLE"           },
 	{ SCTP_ADDR_REMOVED,                "SCTP_ADDR_REMOVED"               },
 	{ SCTP_ADDR_MADE_PRIM,              "SCTP_ADDR_MADE_PRIM"             },
+	{ SCTP_SNDINFO,                     "SCTP_SNDINFO"                    },
+	{ SCTP_PRINFO,                      "SCTP_PRINFO"                     },
+	{ SCTP_AUTHINFO,                    "SCTP_AUTHINFO"                   },
+	{ SCTP_DSTADDRV4,                   "SCTP_DSTADDRV4"                  },
+	{ SCTP_DSTADDRV6,                   "SCTP_DSTADDRV6"                  },
 	/* /usr/include/netinet/tcp.h */
 	{ TCP_NODELAY,                      "TCP_NODELAY"                     },
 	{ TCP_MAXSEG,                       "TCP_MAXSEG"                      },
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/notifications/sctp_adaptation_event.pkt b/gtests/net/packetdrill/tests/bsd/sctp/notifications/sctp_adaptation_event.pkt
index e5b5e282881bb8babb97e8ed423b50a7583ac14f..282b383885d289485e3e1b9d225fd6387131e6bf 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/notifications/sctp_adaptation_event.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/notifications/sctp_adaptation_event.pkt
@@ -2,14 +2,26 @@
 +0.0 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
 +0.0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
 // Check the handshake with an empty(!) cookie
-+0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)
++0.0 bind(3, ..., ...) = 0
++0.0 listen(3, 1) = 0
+
+// Enable Event notification
 +0.0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_ADAPTATION_INDICATION, se_on=1}, 8) = 0
 +0.0 getsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_ADAPTATION_INDICATION, se_on=1}, [8]) = 0
-+0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...]
-+0.1 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...]]
-+0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...]
-+0.1 < sctp: COOKIE_ACK[flgs=0]
+
+// Send Adaptation Indication with Init chunk
++0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=1500, os=1, is=1, tsn=0,
+                  ECN_CAPABLE[],
+		  ADAPTATION_INDICATION[adaptation_code_point=3],
+                  COOKIE_PRESERVATIVE[incr=12345],
+                  SUPPORTED_ADDRESS_TYPES[types=[IPv4]]]
+
+*    > sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=..., os=..., is=..., tsn=10, ...]
++0.0 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...]
+*    > sctp: COOKIE_ACK[flgs=0]
+
++0.0 accept(3, ..., ...) = 4
 
 //TODO: Packetdrill does not support Path reconfiguration, after that update this test
-+0.0 sctp_recvv(3, [{iov_base={sai_type=SCTP_ADAPTATION_INDICATION, sai_flags=0, sai_length=16, sai_adaptation_ind=0, sai_assoc_id=...},
-iov_len=1000}], 1, ..., 20, NULL, [0], [SCTP_RECVV_NOINFO],[MSG_NOTIFICATION|MSG_EOR]) = 21
++0.0 sctp_recvv(4, [{iov_base={sai_type=SCTP_ADAPTATION_INDICATION, sai_flags=0, sai_length=16, sai_adaptation_ind=3, sai_assoc_id=...},
+iov_len=1000}], 1, ..., 20, NULL, [0], [SCTP_RECVV_NOINFO],[MSG_NOTIFICATION|MSG_EOR]) = 16
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt
index 2b9f57a45ab668a1797af277c6744b7bd6fe6933..a33a6d1950fec9df17d13a79b78dd047d694a1fb 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt
@@ -115,14 +115,14 @@ sasoc_cookie_life=...}, [20]) = 0
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=1}, 8) = 0
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_EVENT, {se_type=SCTP_SHUTDOWN_EVENT, se_on=1}, [8]) = 0
 
-+0 setsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=0, snd_ppid=htonl(1), snd_context=1}, 16) = 0
-+0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=0, snd_ppid=htonl(1), snd_context=1}, [16]) = 0
-+0 setsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=SCTP_UNORDERED, snd_ppid=htonl(2), snd_context=2}, 16) = 0
-+0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=SCTP_UNORDERED, snd_ppid=htonl(2), snd_context=2}, [16]) = 0
-+0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=SCTP_UNORDERED, snd_ppid=htonl(2), snd_context=...}, [16]) = 0
-+0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=SCTP_UNORDERED, snd_ppid=..., snd_context=2}, [16]) = 0
-+0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=..., snd_ppid=htonl(2), snd_context=2}, [16]) = 0
-+0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=..., snd_flags=SCTP_UNORDERED, snd_ppid=htonl(2), snd_context=2}, [16]) = 0
++0 setsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=0, snd_ppid=htonl(1), snd_context=1, snd_assoc_id=0}, 16) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=0, snd_ppid=htonl(1), snd_context=1, snd_assoc_id=0}, [16]) = 0
++0 setsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=SCTP_UNORDERED, snd_ppid=htonl(2), snd_context=2, snd_assoc_id=0}, 16) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=SCTP_UNORDERED, snd_ppid=htonl(2), snd_context=2, snd_assoc_id=0}, [16]) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=SCTP_UNORDERED, snd_ppid=htonl(2), snd_context=..., snd_assoc_id=0}, [16]) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=SCTP_UNORDERED, snd_ppid=..., snd_context=2, snd_assoc_id=0},[16]) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=0, snd_flags=..., snd_ppid=htonl(2), snd_context=2, snd_assoc_id=0}, [16]) = 0
++0 getsockopt(3, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, {snd_sid=..., snd_flags=SCTP_UNORDERED, snd_ppid=htonl(2), snd_context=2, snd_assoc_id=0}, [16]) = 0
 
 +0 setsockopt(3, IPPROTO_SCTP, SCTP_ADAPTATION_LAYER, {ssb_adaptation_ind=2}, 4) = 0
 +0 getsockopt(3, IPPROTO_SCTP, SCTP_ADAPTATION_LAYER, {ssb_adaptation_ind=2}, [4]) = 0
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_sendv.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_sendv.pkt
index 114a476808ae46fa799c0b32ea28b879eb416d27..b5dbb6f097c0a049c4684c5c3dda42f80115b8f8 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_sendv.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_sendv.pkt
@@ -50,14 +50,15 @@
 
 //test with all sctp_sendv_spainfo
 +1.0 sctp_sendv(3, [{..., 500}, {..., 500}], 2, ..., 1, {sendv_flags=SCTP_SEND_SNDINFO_VALID,
-sendv_sndinfo={snd_sid=2, snd_flags=0, snd_ppid=htonl(0), snd_context=0},
+sendv_sndinfo={snd_sid=2, snd_flags=0, snd_ppid=htonl(0), snd_context=0, snd_assoc_id=0},
 sendv_prinfo={pr_policy=SCTP_PR_SCTP_TTL, pr_value=10},
 sendv_authinfo={auth_keynumber=123}}, 32, SCTP_SENDV_SPA, 0) = 1000
 *    > sctp: DATA[flgs=BE, len=1016, tsn=8, sid=2, ssn=0, ppid=0]
 +0.0 < sctp: SACK[flgs=0, cum_tsn=8, a_rwnd=1500, gaps=[], dups=[]]
 
 //test with sctp_sendv_sndinfo
-+1.0 sctp_sendv(3, [{iov_base=..., iov_len=1000}], 1, ..., 1, {snd_sid=1, snd_flags=0, snd_ppid=htonl(1234), snd_context=0}, 16, SCTP_SENDV_SNDINFO, 0) = 1000
++1.0 sctp_sendv(3, [{iov_base=..., iov_len=1000}], 1, ..., 1, {snd_sid=1, snd_flags=0, snd_ppid=htonl(1234), snd_context=0, snd_assoc_id=0}, 16, SCTP_SENDV_SNDINFO, 0) 
+= 1000
 *    > sctp: DATA[flgs=BE, len=1016, tsn=9, sid=1, ssn=0, ppid=1234]
 +0.0 < sctp: SACK[flgs=0, cum_tsn=9, a_rwnd=1500, gaps=[], dups=[]]
 
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sendmsg.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sendmsg.pkt
new file mode 100644
index 0000000000000000000000000000000000000000..a8639456fbb6e3f9dabfc4af97b4943a111bee9b
--- /dev/null
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sendmsg.pkt
@@ -0,0 +1,70 @@
+
++0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
++0.0 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
++0.0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
++0.0 bind(3, ..., ...) = 0
+// Check the handshake with an empty(!) cookie
++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)
++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...]
++0.1 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=16, is=16, tsn=1, STATE_COOKIE[len=4, val=...]]
++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...]
++0.1 < sctp: COOKIE_ACK[flgs=0]
++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
+//sendmsg(sd, msghdr, flags)
+
++1.0 sendmsg(3, {msg_name(...)=..., msg_iov(1)=[{iov_base=..., iov_len=1000}], msg_control(0)=[], msg_flags=0}, 0) = 1000
+*    > sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0]
++0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=1500, gaps=[], dups=[]]
+
+//base test
++1.0 sendmsg(3, {msg_name(...)=..., msg_iov(1)=[{iov_base=..., iov_len=1000}], msg_control(28)=
+	[{cmsg_len=28, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_SNDINFO, cmsg_data=
+	 {snd_sid=2, snd_flags=0, snd_ppid=htonl(3), snd_context=2, snd_assoc_id=0}
+	}],
+	msg_flags=0}, 0) = 1000
+*    > sctp: DATA[flgs=BE, len=1016, tsn=2, sid=2, ssn=0, ppid=3]
++0.0 < sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=1500, gaps=[], dups=[]]
+
+// test with 2 cmsg
++1.0 sendmsg(3, {msg_name(...)=..., msg_iov(1)=[{iov_base=..., iov_len=1000}], msg_control(44)=
+	[{cmsg_len=28, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_SNDINFO, cmsg_data=
+	 {snd_sid=2, snd_flags=0, snd_ppid=htonl(4), snd_context=2, snd_assoc_id=0}
+	},{cmsg_len=16, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_DSTADDRV4, cmsg_data=
+	 {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")}
+	}],
+	msg_flags=0}, 0) = 1000
+*    > sctp: DATA[flgs=BE, len=1016, tsn=3, sid=2, ssn=1, ppid=4]
++0.0 < sctp: SACK[flgs=0, cum_tsn=3, a_rwnd=1500, gaps=[], dups=[]]
+
+// test with 2 cmsg
++1.0 sendmsg(3, {msg_name(...)=..., msg_iov(1)=[{iov_base=..., iov_len=1000}], msg_control(64)=
+	[{cmsg_len=28, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_SNDINFO, cmsg_data=
+	 {snd_sid=2, snd_flags=0, snd_ppid=htonl(5), snd_context=2, snd_assoc_id=0}
+	},{cmsg_len=16, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_DSTADDRV4, cmsg_data=
+	 {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")}
+	},{cmsg_len=18, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_PRINFO, cmsg_data=
+	 {pr_policy=SCTP_PR_SCTP_TTL, pr_value=30}
+	}],
+	msg_flags=0}, 0) = 1000
+*    > sctp: DATA[flgs=BE, len=1016, tsn=4, sid=2, ssn=2, ppid=5]
++0.0 < sctp: SACK[flgs=0, cum_tsn=4, a_rwnd=1500, gaps=[], dups=[]]
+
+// test with 2 cmsg
++1.0 sendmsg(3, {msg_name(...)=..., msg_iov(1)=[{iov_base=..., iov_len=1000}], msg_control(80)=
+	[{cmsg_len=28, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_SNDINFO, cmsg_data=
+	 {snd_sid=2, snd_flags=0, snd_ppid=htonl(6), snd_context=2, snd_assoc_id=0}
+	},{cmsg_len=16, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_DSTADDRV4, cmsg_data=
+	 {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")}
+	},{cmsg_len=18, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_PRINFO, cmsg_data=
+	 {pr_policy=SCTP_PR_SCTP_TTL, pr_value=30}
+	},{cmsg_len=14, cmsg_level=IPPROTO_SCTP, cmsg_type=SCTP_AUTHINFO, cmsg_data=
+	 {auth_keynumber=123}
+	}],
+	msg_flags=0}, 0) = 1000
+*    > sctp: DATA[flgs=BE, len=1016, tsn=5, sid=2, ssn=3, ppid=6]
++0.0 < sctp: SACK[flgs=0, cum_tsn=5, a_rwnd=1500, gaps=[], dups=[]]
+
++0.0 close(3) = 0
++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=0]
++0.1 < sctp: SHUTDOWN_ACK[flgs=0]
++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0]