1#!/usr/bin/env ksh
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22
23#
24# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
25#
26
27#
28# Test sctp:::state-change and sctp:::{send,receive} by connecting to
29# the local discard service.
30# A number of state transition events along with SCTP send and
31# receive events for the message should result.
32#
33# This may fail due to:
34#
35# 1. A change to the ip stack breaking expected probe behavior,
36#    which is the reason we are testing.
37# 2. The lo0 interface missing or not up.
38# 3. An unlikely race causes the unlocked global send/receive
39#    variables to be corrupted.
40#
41# This test performs a SCTP connection and checks that at least the
42# following packet counts were traced:
43#
44# 7 x ip:::send (4 during the setup, 3 during the teardown)
45# 7 x sctp:::send (4 during the setup, 3 during the teardown)
46# 7 x ip:::receive (4 during the setup, 3 during the teardown)
47# 7 x sctp:::receive (4 during the setup, 3 during the teardown)
48#
49# The actual count tested is 7 each way, since we are tracing both
50# source and destination events.
51#
52
53if (( $# != 1 )); then
54	print -u2 "expected one argument: <dtrace-path>"
55	exit 2
56fi
57
58dtrace=$1
59local=127.0.0.1
60DIR=/var/tmp/dtest.$$
61
62sctpport=1024
63bound=5000
64while [ $sctpport -lt $bound ]; do
65	ncat --sctp -z $local $sctpport > /dev/null || break
66	sctpport=$(($sctpport + 1))
67done
68if [ $sctpport -eq $bound ]; then
69	echo "couldn't find an available SCTP port"
70	exit 1
71fi
72
73mkdir $DIR
74cd $DIR
75
76# ncat will exit when the association is closed.
77ncat --sctp --listen $local $sctpport &
78
79cat > test.pl <<-EOPERL
80	use IO::Socket;
81	my \$s = IO::Socket::INET->new(
82	    Type => SOCK_STREAM,
83	    Proto => "sctp",
84	    LocalAddr => "$local",
85	    PeerAddr => "$local",
86	    PeerPort => $sctpport,
87	    Timeout => 3);
88	die "Could not connect to host $local port $sctpport \$@" unless \$s;
89	close \$s;
90	sleep(2);
91EOPERL
92
93$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
94BEGIN
95{
96	ipsend = sctpsend = ipreceive = sctpreceive = 0;
97}
98
99ip:::send
100/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
101    args[4]->ipv4_protocol == IPPROTO_SCTP/
102{
103	ipsend++;
104}
105
106sctp:::send
107/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
108 (args[4]->sctp_sport == $sctpport || args[4]->sctp_dport == $sctpport)/
109{
110	sctpsend++;
111}
112
113ip:::receive
114/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
115    args[4]->ipv4_protocol == IPPROTO_SCTP/
116{
117	ipreceive++;
118}
119
120sctp:::receive
121/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
122 (args[4]->sctp_sport == $sctpport || args[4]->sctp_dport == $sctpport)/
123{
124	sctpreceive++;
125}
126
127sctp:::state-change
128{
129	state_event[args[3]->sctps_state]++;
130}
131
132END
133{
134	printf("Minimum SCTP events seen\n\n");
135	printf("ip:::send - %s\n", ipsend >= 7 ? "yes" : "no");
136	printf("ip:::receive - %s\n", ipreceive >= 7 ? "yes" : "no");
137	printf("sctp:::send - %s\n", sctpsend >= 7 ? "yes" : "no");
138	printf("sctp:::receive - %s\n", sctpreceive >= 7 ? "yes" : "no");
139	printf("sctp:::state-change to cookie-wait - %s\n",
140	    state_event[SCTP_STATE_COOKIE_WAIT] >=1 ? "yes" : "no");
141	printf("sctp:::state-change to cookie-echoed - %s\n",
142	    state_event[SCTP_STATE_COOKIE_ECHOED] >=1 ? "yes" : "no");
143	printf("sctp:::state-change to established - %s\n",
144	    state_event[SCTP_STATE_ESTABLISHED] >= 2 ? "yes" : "no");
145	printf("sctp:::state-change to shutdown-sent - %s\n",
146	    state_event[SCTP_STATE_SHUTDOWN_SENT] >= 1 ? "yes" : "no");
147	printf("sctp:::state-change to shutdown-received - %s\n",
148	    state_event[SCTP_STATE_SHUTDOWN_RECEIVED] >= 1 ? "yes" : "no");
149	printf("sctp:::state-change to shutdown-ack-sent - %s\n",
150	    state_event[SCTP_STATE_SHUTDOWN_ACK_SENT] >= 1 ? "yes" : "no");
151}
152EODTRACE
153
154status=$?
155
156cd /
157/bin/rm -rf $DIR
158
159exit $status
160