aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorVenkata Mohan Reddy <mohanreddykv@gmail.com>2010-02-18 06:31:05 -0500
committerPatrick McHardy <kaber@trash.net>2010-02-18 06:31:05 -0500
commit2906f66a5682e5670a5eefe991843689b8d8563f (patch)
treedcbc3ef175c609d2fa32a8e7478eb0d17015c0a7 /net/netfilter
parent477c608673526afc094be521086fed186c7ccf7d (diff)
ipvs: SCTP Trasport Loadbalancing Support
Enhance IPVS to load balance SCTP transport protocol packets. This is done based on the SCTP rfc 4960. All possible control chunks have been taken care. The state machine used in this code looks some what lengthy. I tried to make the state machine easy to understand. Signed-off-by: Venkata Mohan Reddy Koppula <mohanreddykv@gmail.com> Signed-off-by: Simon Horman <horms@verge.net.au> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/ipvs/Kconfig7
-rw-r--r--net/netfilter/ipvs/Makefile1
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c62
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_proto.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c1183
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c14
7 files changed, 1264 insertions, 11 deletions
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
index 817a8898203..712ccad1334 100644
--- a/net/netfilter/ipvs/Kconfig
+++ b/net/netfilter/ipvs/Kconfig
@@ -104,6 +104,13 @@ config IP_VS_PROTO_AH
104 This option enables support for load balancing AH (Authentication 104 This option enables support for load balancing AH (Authentication
105 Header) transport protocol. Say Y if unsure. 105 Header) transport protocol. Say Y if unsure.
106 106
107config IP_VS_PROTO_SCTP
108 bool "SCTP load balancing support"
109 select LIBCRC32C
110 ---help---
111 This option enables support for load balancing SCTP transport
112 protocol. Say Y if unsure.
113
107comment "IPVS scheduler" 114comment "IPVS scheduler"
108 115
109config IP_VS_RR 116config IP_VS_RR
diff --git a/net/netfilter/ipvs/Makefile b/net/netfilter/ipvs/Makefile
index 73a46fe1fe4..e3baefd7066 100644
--- a/net/netfilter/ipvs/Makefile
+++ b/net/netfilter/ipvs/Makefile
@@ -7,6 +7,7 @@ ip_vs_proto-objs-y :=
7ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_TCP) += ip_vs_proto_tcp.o 7ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_TCP) += ip_vs_proto_tcp.o
8ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_UDP) += ip_vs_proto_udp.o 8ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_UDP) += ip_vs_proto_udp.o
9ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH_ESP) += ip_vs_proto_ah_esp.o 9ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH_ESP) += ip_vs_proto_ah_esp.o
10ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_SCTP) += ip_vs_proto_sctp.o
10 11
11ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \ 12ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \
12 ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \ 13 ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 847ffca4018..72e96d823eb 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -31,6 +31,7 @@
31#include <linux/kernel.h> 31#include <linux/kernel.h>
32#include <linux/ip.h> 32#include <linux/ip.h>
33#include <linux/tcp.h> 33#include <linux/tcp.h>
34#include <linux/sctp.h>
34#include <linux/icmp.h> 35#include <linux/icmp.h>
35 36
36#include <net/ip.h> 37#include <net/ip.h>
@@ -81,6 +82,8 @@ const char *ip_vs_proto_name(unsigned proto)
81 return "UDP"; 82 return "UDP";
82 case IPPROTO_TCP: 83 case IPPROTO_TCP:
83 return "TCP"; 84 return "TCP";
85 case IPPROTO_SCTP:
86 return "SCTP";
84 case IPPROTO_ICMP: 87 case IPPROTO_ICMP:
85 return "ICMP"; 88 return "ICMP";
86#ifdef CONFIG_IP_VS_IPV6 89#ifdef CONFIG_IP_VS_IPV6
@@ -589,8 +592,9 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
589 ip_send_check(ciph); 592 ip_send_check(ciph);
590 } 593 }
591 594
592 /* the TCP/UDP port */ 595 /* the TCP/UDP/SCTP port */
593 if (IPPROTO_TCP == ciph->protocol || IPPROTO_UDP == ciph->protocol) { 596 if (IPPROTO_TCP == ciph->protocol || IPPROTO_UDP == ciph->protocol ||
597 IPPROTO_SCTP == ciph->protocol) {
594 __be16 *ports = (void *)ciph + ciph->ihl*4; 598 __be16 *ports = (void *)ciph + ciph->ihl*4;
595 599
596 if (inout) 600 if (inout)
@@ -630,8 +634,9 @@ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
630 ciph->saddr = cp->daddr.in6; 634 ciph->saddr = cp->daddr.in6;
631 } 635 }
632 636
633 /* the TCP/UDP port */ 637 /* the TCP/UDP/SCTP port */
634 if (IPPROTO_TCP == ciph->nexthdr || IPPROTO_UDP == ciph->nexthdr) { 638 if (IPPROTO_TCP == ciph->nexthdr || IPPROTO_UDP == ciph->nexthdr ||
639 IPPROTO_SCTP == ciph->nexthdr) {
635 __be16 *ports = (void *)ciph + sizeof(struct ipv6hdr); 640 __be16 *ports = (void *)ciph + sizeof(struct ipv6hdr);
636 641
637 if (inout) 642 if (inout)
@@ -679,7 +684,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
679 goto out; 684 goto out;
680 } 685 }
681 686
682 if (IPPROTO_TCP == protocol || IPPROTO_UDP == protocol) 687 if (IPPROTO_TCP == protocol || IPPROTO_UDP == protocol ||
688 IPPROTO_SCTP == protocol)
683 offset += 2 * sizeof(__u16); 689 offset += 2 * sizeof(__u16);
684 if (!skb_make_writable(skb, offset)) 690 if (!skb_make_writable(skb, offset))
685 goto out; 691 goto out;
@@ -857,6 +863,21 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
857} 863}
858#endif 864#endif
859 865
866/*
867 * Check if sctp chunc is ABORT chunk
868 */
869static inline int is_sctp_abort(const struct sk_buff *skb, int nh_len)
870{
871 sctp_chunkhdr_t *sch, schunk;
872 sch = skb_header_pointer(skb, nh_len + sizeof(sctp_sctphdr_t),
873 sizeof(schunk), &schunk);
874 if (sch == NULL)
875 return 0;
876 if (sch->type == SCTP_CID_ABORT)
877 return 1;
878 return 0;
879}
880
860static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len) 881static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len)
861{ 882{
862 struct tcphdr _tcph, *th; 883 struct tcphdr _tcph, *th;
@@ -999,7 +1020,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
999 if (unlikely(!cp)) { 1020 if (unlikely(!cp)) {
1000 if (sysctl_ip_vs_nat_icmp_send && 1021 if (sysctl_ip_vs_nat_icmp_send &&
1001 (pp->protocol == IPPROTO_TCP || 1022 (pp->protocol == IPPROTO_TCP ||
1002 pp->protocol == IPPROTO_UDP)) { 1023 pp->protocol == IPPROTO_UDP ||
1024 pp->protocol == IPPROTO_SCTP)) {
1003 __be16 _ports[2], *pptr; 1025 __be16 _ports[2], *pptr;
1004 1026
1005 pptr = skb_header_pointer(skb, iph.len, 1027 pptr = skb_header_pointer(skb, iph.len,
@@ -1014,8 +1036,13 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
1014 * existing entry if it is not RST 1036 * existing entry if it is not RST
1015 * packet or not TCP packet. 1037 * packet or not TCP packet.
1016 */ 1038 */
1017 if (iph.protocol != IPPROTO_TCP 1039 if ((iph.protocol != IPPROTO_TCP &&
1018 || !is_tcp_reset(skb, iph.len)) { 1040 iph.protocol != IPPROTO_SCTP)
1041 || ((iph.protocol == IPPROTO_TCP
1042 && !is_tcp_reset(skb, iph.len))
1043 || (iph.protocol == IPPROTO_SCTP
1044 && !is_sctp_abort(skb,
1045 iph.len)))) {
1019#ifdef CONFIG_IP_VS_IPV6 1046#ifdef CONFIG_IP_VS_IPV6
1020 if (af == AF_INET6) 1047 if (af == AF_INET6)
1021 icmpv6_send(skb, 1048 icmpv6_send(skb,
@@ -1235,7 +1262,8 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
1235 1262
1236 /* do the statistics and put it back */ 1263 /* do the statistics and put it back */
1237 ip_vs_in_stats(cp, skb); 1264 ip_vs_in_stats(cp, skb);
1238 if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr) 1265 if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr ||
1266 IPPROTO_SCTP == cih->nexthdr)
1239 offset += 2 * sizeof(__u16); 1267 offset += 2 * sizeof(__u16);
1240 verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset); 1268 verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset);
1241 /* do not touch skb anymore */ 1269 /* do not touch skb anymore */
@@ -1358,6 +1386,21 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
1358 * encorage the standby servers to update the connections timeout 1386 * encorage the standby servers to update the connections timeout
1359 */ 1387 */
1360 pkts = atomic_add_return(1, &cp->in_pkts); 1388 pkts = atomic_add_return(1, &cp->in_pkts);
1389 if (af == AF_INET && (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
1390 cp->protocol == IPPROTO_SCTP) {
1391 if ((cp->state == IP_VS_SCTP_S_ESTABLISHED &&
1392 (atomic_read(&cp->in_pkts) %
1393 sysctl_ip_vs_sync_threshold[1]
1394 == sysctl_ip_vs_sync_threshold[0])) ||
1395 (cp->old_state != cp->state &&
1396 ((cp->state == IP_VS_SCTP_S_CLOSED) ||
1397 (cp->state == IP_VS_SCTP_S_SHUT_ACK_CLI) ||
1398 (cp->state == IP_VS_SCTP_S_SHUT_ACK_SER)))) {
1399 ip_vs_sync_conn(cp);
1400 goto out;
1401 }
1402 }
1403
1361 if (af == AF_INET && 1404 if (af == AF_INET &&
1362 (ip_vs_sync_state & IP_VS_STATE_MASTER) && 1405 (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
1363 (((cp->protocol != IPPROTO_TCP || 1406 (((cp->protocol != IPPROTO_TCP ||
@@ -1370,6 +1413,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
1370 (cp->state == IP_VS_TCP_S_CLOSE_WAIT) || 1413 (cp->state == IP_VS_TCP_S_CLOSE_WAIT) ||
1371 (cp->state == IP_VS_TCP_S_TIME_WAIT))))) 1414 (cp->state == IP_VS_TCP_S_TIME_WAIT)))))
1372 ip_vs_sync_conn(cp); 1415 ip_vs_sync_conn(cp);
1416out:
1373 cp->old_state = cp->state; 1417 cp->old_state = cp->state;
1374 1418
1375 ip_vs_conn_put(cp); 1419 ip_vs_conn_put(cp);
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 00d0b152db3..7ee9c3426f4 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -2132,8 +2132,9 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2132 } 2132 }
2133 } 2133 }
2134 2134
2135 /* Check for valid protocol: TCP or UDP, even for fwmark!=0 */ 2135 /* Check for valid protocol: TCP or UDP or SCTP, even for fwmark!=0 */
2136 if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP) { 2136 if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP &&
2137 usvc.protocol != IPPROTO_SCTP) {
2137 pr_err("set_ctl: invalid protocol: %d %pI4:%d %s\n", 2138 pr_err("set_ctl: invalid protocol: %d %pI4:%d %s\n",
2138 usvc.protocol, &usvc.addr.ip, 2139 usvc.protocol, &usvc.addr.ip,
2139 ntohs(usvc.port), usvc.sched_name); 2140 ntohs(usvc.port), usvc.sched_name);
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index 3e767167454..0e584553819 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -257,6 +257,9 @@ int __init ip_vs_protocol_init(void)
257#ifdef CONFIG_IP_VS_PROTO_UDP 257#ifdef CONFIG_IP_VS_PROTO_UDP
258 REGISTER_PROTOCOL(&ip_vs_protocol_udp); 258 REGISTER_PROTOCOL(&ip_vs_protocol_udp);
259#endif 259#endif
260#ifdef CONFIG_IP_VS_PROTO_SCTP
261 REGISTER_PROTOCOL(&ip_vs_protocol_sctp);
262#endif
260#ifdef CONFIG_IP_VS_PROTO_AH 263#ifdef CONFIG_IP_VS_PROTO_AH
261 REGISTER_PROTOCOL(&ip_vs_protocol_ah); 264 REGISTER_PROTOCOL(&ip_vs_protocol_ah);
262#endif 265#endif
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
new file mode 100644
index 00000000000..c9a3f7a21d5
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -0,0 +1,1183 @@
1#include <linux/kernel.h>
2#include <linux/ip.h>
3#include <linux/sctp.h>
4#include <net/ip.h>
5#include <net/ip6_checksum.h>
6#include <linux/netfilter.h>
7#include <linux/netfilter_ipv4.h>
8#include <net/sctp/checksum.h>
9#include <net/ip_vs.h>
10
11
12static struct ip_vs_conn *
13sctp_conn_in_get(int af,
14 const struct sk_buff *skb,
15 struct ip_vs_protocol *pp,
16 const struct ip_vs_iphdr *iph,
17 unsigned int proto_off,
18 int inverse)
19{
20 __be16 _ports[2], *pptr;
21
22 pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
23 if (pptr == NULL)
24 return NULL;
25
26 if (likely(!inverse))
27 return ip_vs_conn_in_get(af, iph->protocol,
28 &iph->saddr, pptr[0],
29 &iph->daddr, pptr[1]);
30 else
31 return ip_vs_conn_in_get(af, iph->protocol,
32 &iph->daddr, pptr[1],
33 &iph->saddr, pptr[0]);
34}
35
36static struct ip_vs_conn *
37sctp_conn_out_get(int af,
38 const struct sk_buff *skb,
39 struct ip_vs_protocol *pp,
40 const struct ip_vs_iphdr *iph,
41 unsigned int proto_off,
42 int inverse)
43{
44 __be16 _ports[2], *pptr;
45
46 pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
47 if (pptr == NULL)
48 return NULL;
49
50 if (likely(!inverse))
51 return ip_vs_conn_out_get(af, iph->protocol,
52 &iph->saddr, pptr[0],
53 &iph->daddr, pptr[1]);
54 else
55 return ip_vs_conn_out_get(af, iph->protocol,
56 &iph->daddr, pptr[1],
57 &iph->saddr, pptr[0]);
58}
59
60static int
61sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
62 int *verdict, struct ip_vs_conn **cpp)
63{
64 struct ip_vs_service *svc;
65 sctp_chunkhdr_t _schunkh, *sch;
66 sctp_sctphdr_t *sh, _sctph;
67 struct ip_vs_iphdr iph;
68
69 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
70
71 sh = skb_header_pointer(skb, iph.len, sizeof(_sctph), &_sctph);
72 if (sh == NULL)
73 return 0;
74
75 sch = skb_header_pointer(skb, iph.len + sizeof(sctp_sctphdr_t),
76 sizeof(_schunkh), &_schunkh);
77 if (sch == NULL)
78 return 0;
79
80 if ((sch->type == SCTP_CID_INIT) &&
81 (svc = ip_vs_service_get(af, skb->mark, iph.protocol,
82 &iph.daddr, sh->dest))) {
83 if (ip_vs_todrop()) {
84 /*
85 * It seems that we are very loaded.
86 * We have to drop this packet :(
87 */
88 ip_vs_service_put(svc);
89 *verdict = NF_DROP;
90 return 0;
91 }
92 /*
93 * Let the virtual server select a real server for the
94 * incoming connection, and create a connection entry.
95 */
96 *cpp = ip_vs_schedule(svc, skb);
97 if (!*cpp) {
98 *verdict = ip_vs_leave(svc, skb, pp);
99 return 0;
100 }
101 ip_vs_service_put(svc);
102 }
103
104 return 1;
105}
106
107static int
108sctp_snat_handler(struct sk_buff *skb,
109 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
110{
111 sctp_sctphdr_t *sctph;
112 unsigned int sctphoff;
113 __be32 crc32;
114
115#ifdef CONFIG_IP_VS_IPV6
116 if (cp->af == AF_INET6)
117 sctphoff = sizeof(struct ipv6hdr);
118 else
119#endif
120 sctphoff = ip_hdrlen(skb);
121
122 /* csum_check requires unshared skb */
123 if (!skb_make_writable(skb, sctphoff + sizeof(*sctph)))
124 return 0;
125
126 if (unlikely(cp->app != NULL)) {
127 /* Some checks before mangling */
128 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
129 return 0;
130
131 /* Call application helper if needed */
132 if (!ip_vs_app_pkt_out(cp, skb))
133 return 0;
134 }
135
136 sctph = (void *) skb_network_header(skb) + sctphoff;
137 sctph->source = cp->vport;
138
139 /* Calculate the checksum */
140 crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff);
141 for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next)
142 crc32 = sctp_update_cksum((u8 *) skb->data, skb_headlen(skb),
143 crc32);
144 crc32 = sctp_end_cksum(crc32);
145 sctph->checksum = crc32;
146
147 return 1;
148}
149
150static int
151sctp_dnat_handler(struct sk_buff *skb,
152 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
153{
154
155 sctp_sctphdr_t *sctph;
156 unsigned int sctphoff;
157 __be32 crc32;
158
159#ifdef CONFIG_IP_VS_IPV6
160 if (cp->af == AF_INET6)
161 sctphoff = sizeof(struct ipv6hdr);
162 else
163#endif
164 sctphoff = ip_hdrlen(skb);
165
166 /* csum_check requires unshared skb */
167 if (!skb_make_writable(skb, sctphoff + sizeof(*sctph)))
168 return 0;
169
170 if (unlikely(cp->app != NULL)) {
171 /* Some checks before mangling */
172 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
173 return 0;
174
175 /* Call application helper if needed */
176 if (!ip_vs_app_pkt_out(cp, skb))
177 return 0;
178 }
179
180 sctph = (void *) skb_network_header(skb) + sctphoff;
181 sctph->dest = cp->dport;
182
183 /* Calculate the checksum */
184 crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff);
185 for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next)
186 crc32 = sctp_update_cksum((u8 *) skb->data, skb_headlen(skb),
187 crc32);
188 crc32 = sctp_end_cksum(crc32);
189 sctph->checksum = crc32;
190
191 return 1;
192}
193
194static int
195sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
196{
197 struct sk_buff *list = skb_shinfo(skb)->frag_list;
198 unsigned int sctphoff;
199 struct sctphdr *sh, _sctph;
200 __le32 cmp;
201 __le32 val;
202 __u32 tmp;
203
204#ifdef CONFIG_IP_VS_IPV6
205 if (af == AF_INET6)
206 sctphoff = sizeof(struct ipv6hdr);
207 else
208#endif
209 sctphoff = ip_hdrlen(skb);
210
211 sh = skb_header_pointer(skb, sctphoff, sizeof(_sctph), &_sctph);
212 if (sh == NULL)
213 return 0;
214
215 cmp = sh->checksum;
216
217 tmp = sctp_start_cksum((__u8 *) sh, skb_headlen(skb));
218 for (; list; list = list->next)
219 tmp = sctp_update_cksum((__u8 *) list->data,
220 skb_headlen(list), tmp);
221
222 val = sctp_end_cksum(tmp);
223
224 if (val != cmp) {
225 /* CRC failure, dump it. */
226 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
227 "Failed checksum for");
228 return 0;
229 }
230 return 1;
231}
232
233struct ipvs_sctp_nextstate {
234 int next_state;
235};
236enum ipvs_sctp_event_t {
237 IP_VS_SCTP_EVE_DATA_CLI,
238 IP_VS_SCTP_EVE_DATA_SER,
239 IP_VS_SCTP_EVE_INIT_CLI,
240 IP_VS_SCTP_EVE_INIT_SER,
241 IP_VS_SCTP_EVE_INIT_ACK_CLI,
242 IP_VS_SCTP_EVE_INIT_ACK_SER,
243 IP_VS_SCTP_EVE_COOKIE_ECHO_CLI,
244 IP_VS_SCTP_EVE_COOKIE_ECHO_SER,
245 IP_VS_SCTP_EVE_COOKIE_ACK_CLI,
246 IP_VS_SCTP_EVE_COOKIE_ACK_SER,
247 IP_VS_SCTP_EVE_ABORT_CLI,
248 IP_VS_SCTP_EVE__ABORT_SER,
249 IP_VS_SCTP_EVE_SHUT_CLI,
250 IP_VS_SCTP_EVE_SHUT_SER,
251 IP_VS_SCTP_EVE_SHUT_ACK_CLI,
252 IP_VS_SCTP_EVE_SHUT_ACK_SER,
253 IP_VS_SCTP_EVE_SHUT_COM_CLI,
254 IP_VS_SCTP_EVE_SHUT_COM_SER,
255 IP_VS_SCTP_EVE_LAST
256};
257
258static enum ipvs_sctp_event_t sctp_events[255] = {
259 IP_VS_SCTP_EVE_DATA_CLI,
260 IP_VS_SCTP_EVE_INIT_CLI,
261 IP_VS_SCTP_EVE_INIT_ACK_CLI,
262 IP_VS_SCTP_EVE_DATA_CLI,
263 IP_VS_SCTP_EVE_DATA_CLI,
264 IP_VS_SCTP_EVE_DATA_CLI,
265 IP_VS_SCTP_EVE_ABORT_CLI,
266 IP_VS_SCTP_EVE_SHUT_CLI,
267 IP_VS_SCTP_EVE_SHUT_ACK_CLI,
268 IP_VS_SCTP_EVE_DATA_CLI,
269 IP_VS_SCTP_EVE_COOKIE_ECHO_CLI,
270 IP_VS_SCTP_EVE_COOKIE_ACK_CLI,
271 IP_VS_SCTP_EVE_DATA_CLI,
272 IP_VS_SCTP_EVE_DATA_CLI,
273 IP_VS_SCTP_EVE_SHUT_COM_CLI,
274};
275
276static struct ipvs_sctp_nextstate
277 sctp_states_table[IP_VS_SCTP_S_LAST][IP_VS_SCTP_EVE_LAST] = {
278 /*
279 * STATE : IP_VS_SCTP_S_NONE
280 */
281 /*next state *//*event */
282 {{IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_CLI */ },
283 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_SER */ },
284 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
285 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
286 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
287 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
288 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
289 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
290 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
291 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
292 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
293 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
294 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_CLI */ },
295 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_SER */ },
296 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
297 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
298 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
299 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ },
300 },
301 /*
302 * STATE : IP_VS_SCTP_S_INIT_CLI
303 * Cient sent INIT and is waiting for reply from server(In ECHO_WAIT)
304 */
305 {{IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_CLI */ },
306 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_SER */ },
307 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
308 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
309 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
310 {IP_VS_SCTP_S_INIT_ACK_SER /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
311 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ECHO_CLI */ },
312 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_ECHO_SER */ },
313 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
314 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
315 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
316 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
317 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_CLI */ },
318 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_SER */ },
319 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
320 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
321 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
322 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
323 },
324 /*
325 * State : IP_VS_SCTP_S_INIT_SER
326 * Server sent INIT and waiting for INIT ACK from the client
327 */
328 {{IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_CLI */ },
329 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_SER */ },
330 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
331 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
332 {IP_VS_SCTP_S_INIT_ACK_CLI /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
333 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
334 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
335 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
336 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
337 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
338 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
339 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
340 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_CLI */ },
341 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_SER */ },
342 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
343 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
344 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
345 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
346 },
347 /*
348 * State : IP_VS_SCTP_S_INIT_ACK_CLI
349 * Client sent INIT ACK and waiting for ECHO from the server
350 */
351 {{IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_CLI */ },
352 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_SER */ },
353 /*
354 * We have got an INIT from client. From the spec.“Upon receipt of
355 * an INIT in the COOKIE-WAIT state, an endpoint MUST respond with
356 * an INIT ACK using the same parameters it sent in its original
357 * INIT chunk (including its Initiate Tag, unchanged”).
358 */
359 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
360 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
361 /*
362 * INIT_ACK has been resent by the client, let us stay is in
363 * the same state
364 */
365 {IP_VS_SCTP_S_INIT_ACK_CLI /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
366 /*
367 * INIT_ACK sent by the server, close the connection
368 */
369 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
370 /*
371 * ECHO by client, it should not happen, close the connection
372 */
373 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
374 /*
375 * ECHO by server, this is what we are expecting, move to ECHO_SER
376 */
377 {IP_VS_SCTP_S_ECHO_SER /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
378 /*
379 * COOKIE ACK from client, it should not happen, close the connection
380 */
381 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
382 /*
383 * Unexpected COOKIE ACK from server, staty in the same state
384 */
385 {IP_VS_SCTP_S_INIT_ACK_CLI /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
386 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
387 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
388 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_CLI */ },
389 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_SER */ },
390 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
391 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
392 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
393 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
394 },
395 /*
396 * State : IP_VS_SCTP_S_INIT_ACK_SER
397 * Server sent INIT ACK and waiting for ECHO from the client
398 */
399 {{IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_CLI */ },
400 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_SER */ },
401 /*
402 * We have got an INIT from client. From the spec.“Upon receipt of
403 * an INIT in the COOKIE-WAIT state, an endpoint MUST respond with
404 * an INIT ACK using the same parameters it sent in its original
405 * INIT chunk (including its Initiate Tag, unchanged”).
406 */
407 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
408 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
409 /*
410 * Unexpected INIT_ACK by the client, let us close the connection
411 */
412 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
413 /*
414 * INIT_ACK resent by the server, let us move to same state
415 */
416 {IP_VS_SCTP_S_INIT_ACK_SER /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
417 /*
418 * Client send the ECHO, this is what we are expecting,
419 * move to ECHO_CLI
420 */
421 {IP_VS_SCTP_S_ECHO_CLI /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
422 /*
423 * ECHO received from the server, Not sure what to do,
424 * let us close it
425 */
426 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
427 /*
428 * COOKIE ACK from client, let us stay in the same state
429 */
430 {IP_VS_SCTP_S_INIT_ACK_SER /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
431 /*
432 * COOKIE ACK from server, hmm... this should not happen, lets close
433 * the connection.
434 */
435 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
436 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
437 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
438 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_CLI */ },
439 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_SER */ },
440 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
441 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
442 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
443 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
444 },
445 /*
446 * State : IP_VS_SCTP_S_ECHO_CLI
447 * Cient sent ECHO and waiting COOKEI ACK from the Server
448 */
449 {{IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_CLI */ },
450 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_SER */ },
451 /*
452 * We have got an INIT from client. From the spec.“Upon receipt of
453 * an INIT in the COOKIE-WAIT state, an endpoint MUST respond with
454 * an INIT ACK using the same parameters it sent in its original
455 * INIT chunk (including its Initiate Tag, unchanged”).
456 */
457 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
458 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
459 /*
460 * INIT_ACK has been by the client, let us close the connection
461 */
462 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
463 /*
464 * INIT_ACK sent by the server, Unexpected INIT ACK, spec says,
465 * “If an INIT ACK is received by an endpoint in any state other
466 * than the COOKIE-WAIT state, the endpoint should discard the
467 * INIT ACK chunk”. Stay in the same state
468 */
469 {IP_VS_SCTP_S_ECHO_CLI /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
470 /*
471 * Client resent the ECHO, let us stay in the same state
472 */
473 {IP_VS_SCTP_S_ECHO_CLI /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
474 /*
475 * ECHO received from the server, Not sure what to do,
476 * let us close it
477 */
478 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
479 /*
480 * COOKIE ACK from client, this shoud not happen, let's close the
481 * connection
482 */
483 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
484 /*
485 * COOKIE ACK from server, this is what we are awaiting,lets move to
486 * ESTABLISHED.
487 */
488 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
489 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
490 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
491 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_CLI */ },
492 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_SER */ },
493 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
494 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
495 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
496 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
497 },
498 /*
499 * State : IP_VS_SCTP_S_ECHO_SER
500 * Server sent ECHO and waiting COOKEI ACK from the client
501 */
502 {{IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_CLI */ },
503 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_SER */ },
504 /*
505 * We have got an INIT from client. From the spec.“Upon receipt of
506 * an INIT in the COOKIE-WAIT state, an endpoint MUST respond with
507 * an INIT ACK using the same parameters it sent in its original
508 * INIT chunk (including its Initiate Tag, unchanged”).
509 */
510 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
511 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
512 /*
513 * INIT_ACK sent by the server, Unexpected INIT ACK, spec says,
514 * “If an INIT ACK is received by an endpoint in any state other
515 * than the COOKIE-WAIT state, the endpoint should discard the
516 * INIT ACK chunk”. Stay in the same state
517 */
518 {IP_VS_SCTP_S_ECHO_SER /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
519 /*
520 * INIT_ACK has been by the server, let us close the connection
521 */
522 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
523 /*
524 * Client sent the ECHO, not sure what to do, let's close the
525 * connection.
526 */
527 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
528 /*
529 * ECHO resent by the server, stay in the same state
530 */
531 {IP_VS_SCTP_S_ECHO_SER /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
532 /*
533 * COOKIE ACK from client, this is what we are expecting, let's move
534 * to ESTABLISHED.
535 */
536 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
537 /*
538 * COOKIE ACK from server, this should not happen, lets close the
539 * connection.
540 */
541 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
542 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
543 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
544 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_CLI */ },
545 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_SER */ },
546 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
547 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
548 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
549 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
550 },
551 /*
552 * State : IP_VS_SCTP_S_ESTABLISHED
553 * Association established
554 */
555 {{IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_DATA_CLI */ },
556 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_DATA_SER */ },
557 /*
558 * We have got an INIT from client. From the spec.“Upon receipt of
559 * an INIT in the COOKIE-WAIT state, an endpoint MUST respond with
560 * an INIT ACK using the same parameters it sent in its original
561 * INIT chunk (including its Initiate Tag, unchanged”).
562 */
563 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
564 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
565 /*
566 * INIT_ACK sent by the server, Unexpected INIT ACK, spec says,
567 * “If an INIT ACK is received by an endpoint in any state other
568 * than the COOKIE-WAIT state, the endpoint should discard the
569 * INIT ACK chunk”. Stay in the same state
570 */
571 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
572 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
573 /*
574 * Client sent ECHO, Spec(sec 5.2.4) says it may be handled by the
575 * peer and peer shall move to the ESTABISHED. if it doesn't handle
576 * it will send ERROR chunk. So, stay in the same state
577 */
578 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
579 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
580 /*
581 * COOKIE ACK from client, not sure what to do stay in the same state
582 */
583 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
584 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
585 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
586 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
587 /*
588 * SHUTDOWN from the client, move to SHUDDOWN_CLI
589 */
590 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_SHUT_CLI */ },
591 /*
592 * SHUTDOWN from the server, move to SHUTDOWN_SER
593 */
594 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_SHUT_SER */ },
595 /*
596 * client sent SHUDTDOWN_ACK, this should not happen, let's close
597 * the connection
598 */
599 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
600 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
601 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
602 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
603 },
604 /*
605 * State : IP_VS_SCTP_S_SHUT_CLI
606 * SHUTDOWN sent from the client, waitinf for SHUT ACK from the server
607 */
608 /*
609 * We recieved the data chuck, keep the state unchanged. I assume
610 * that still data chuncks can be received by both the peers in
611 * SHUDOWN state
612 */
613
614 {{IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_DATA_CLI */ },
615 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_DATA_SER */ },
616 /*
617 * We have got an INIT from client. From the spec.“Upon receipt of
618 * an INIT in the COOKIE-WAIT state, an endpoint MUST respond with
619 * an INIT ACK using the same parameters it sent in its original
620 * INIT chunk (including its Initiate Tag, unchanged”).
621 */
622 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
623 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
624 /*
625 * INIT_ACK sent by the server, Unexpected INIT ACK, spec says,
626 * “If an INIT ACK is received by an endpoint in any state other
627 * than the COOKIE-WAIT state, the endpoint should discard the
628 * INIT ACK chunk”. Stay in the same state
629 */
630 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
631 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
632 /*
633 * Client sent ECHO, Spec(sec 5.2.4) says it may be handled by the
634 * peer and peer shall move to the ESTABISHED. if it doesn't handle
635 * it will send ERROR chunk. So, stay in the same state
636 */
637 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
638 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
639 /*
640 * COOKIE ACK from client, not sure what to do stay in the same state
641 */
642 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
643 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
644 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
645 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
646 /*
647 * SHUTDOWN resent from the client, move to SHUDDOWN_CLI
648 */
649 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_SHUT_CLI */ },
650 /*
651 * SHUTDOWN from the server, move to SHUTDOWN_SER
652 */
653 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_SHUT_SER */ },
654 /*
655 * client sent SHUDTDOWN_ACK, this should not happen, let's close
656 * the connection
657 */
658 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
659 /*
660 * Server sent SHUTDOWN ACK, this is what we are expecting, let's move
661 * to SHUDOWN_ACK_SER
662 */
663 {IP_VS_SCTP_S_SHUT_ACK_SER /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
664 /*
665 * SHUTDOWN COM from client, this should not happen, let's close the
666 * connection
667 */
668 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
669 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
670 },
671 /*
672 * State : IP_VS_SCTP_S_SHUT_SER
673 * SHUTDOWN sent from the server, waitinf for SHUTDOWN ACK from client
674 */
675 /*
676 * We recieved the data chuck, keep the state unchanged. I assume
677 * that still data chuncks can be received by both the peers in
678 * SHUDOWN state
679 */
680
681 {{IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_DATA_CLI */ },
682 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_DATA_SER */ },
683 /*
684 * We have got an INIT from client. From the spec.“Upon receipt of
685 * an INIT in the COOKIE-WAIT state, an endpoint MUST respond with
686 * an INIT ACK using the same parameters it sent in its original
687 * INIT chunk (including its Initiate Tag, unchanged”).
688 */
689 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
690 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
691 /*
692 * INIT_ACK sent by the server, Unexpected INIT ACK, spec says,
693 * “If an INIT ACK is received by an endpoint in any state other
694 * than the COOKIE-WAIT state, the endpoint should discard the
695 * INIT ACK chunk”. Stay in the same state
696 */
697 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
698 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
699 /*
700 * Client sent ECHO, Spec(sec 5.2.4) says it may be handled by the
701 * peer and peer shall move to the ESTABISHED. if it doesn't handle
702 * it will send ERROR chunk. So, stay in the same state
703 */
704 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
705 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
706 /*
707 * COOKIE ACK from client, not sure what to do stay in the same state
708 */
709 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
710 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
711 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
712 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
713 /*
714 * SHUTDOWN resent from the client, move to SHUDDOWN_CLI
715 */
716 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_SHUT_CLI */ },
717 /*
718 * SHUTDOWN resent from the server, move to SHUTDOWN_SER
719 */
720 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_SHUT_SER */ },
721 /*
722 * client sent SHUDTDOWN_ACK, this is what we are expecting, let's
723 * move to SHUT_ACK_CLI
724 */
725 {IP_VS_SCTP_S_SHUT_ACK_CLI /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
726 /*
727 * Server sent SHUTDOWN ACK, this should not happen, let's close the
728 * connection
729 */
730 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
731 /*
732 * SHUTDOWN COM from client, this should not happen, let's close the
733 * connection
734 */
735 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
736 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
737 },
738
739 /*
740 * State : IP_VS_SCTP_S_SHUT_ACK_CLI
741 * SHUTDOWN ACK from the client, awaiting for SHUTDOWN COM from server
742 */
743 /*
744 * We recieved the data chuck, keep the state unchanged. I assume
745 * that still data chuncks can be received by both the peers in
746 * SHUDOWN state
747 */
748
749 {{IP_VS_SCTP_S_SHUT_ACK_CLI /* IP_VS_SCTP_EVE_DATA_CLI */ },
750 {IP_VS_SCTP_S_SHUT_ACK_CLI /* IP_VS_SCTP_EVE_DATA_SER */ },
751 /*
752 * We have got an INIT from client. From the spec.“Upon receipt of
753 * an INIT in the COOKIE-WAIT state, an endpoint MUST respond with
754 * an INIT ACK using the same parameters it sent in its original
755 * INIT chunk (including its Initiate Tag, unchanged”).
756 */
757 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
758 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
759 /*
760 * INIT_ACK sent by the server, Unexpected INIT ACK, spec says,
761 * “If an INIT ACK is received by an endpoint in any state other
762 * than the COOKIE-WAIT state, the endpoint should discard the
763 * INIT ACK chunk”. Stay in the same state
764 */
765 {IP_VS_SCTP_S_SHUT_ACK_CLI /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
766 {IP_VS_SCTP_S_SHUT_ACK_CLI /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
767 /*
768 * Client sent ECHO, Spec(sec 5.2.4) says it may be handled by the
769 * peer and peer shall move to the ESTABISHED. if it doesn't handle
770 * it will send ERROR chunk. So, stay in the same state
771 */
772 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
773 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
774 /*
775 * COOKIE ACK from client, not sure what to do stay in the same state
776 */
777 {IP_VS_SCTP_S_SHUT_ACK_CLI /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
778 {IP_VS_SCTP_S_SHUT_ACK_CLI /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
779 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
780 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
781 /*
782 * SHUTDOWN sent from the client, move to SHUDDOWN_CLI
783 */
784 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_SHUT_CLI */ },
785 /*
786 * SHUTDOWN sent from the server, move to SHUTDOWN_SER
787 */
788 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_SHUT_SER */ },
789 /*
790 * client resent SHUDTDOWN_ACK, let's stay in the same state
791 */
792 {IP_VS_SCTP_S_SHUT_ACK_CLI /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
793 /*
794 * Server sent SHUTDOWN ACK, this should not happen, let's close the
795 * connection
796 */
797 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
798 /*
799 * SHUTDOWN COM from client, this should not happen, let's close the
800 * connection
801 */
802 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
803 /*
804 * SHUTDOWN COMPLETE from server this is what we are expecting.
805 */
806 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
807 },
808
809 /*
810 * State : IP_VS_SCTP_S_SHUT_ACK_SER
811 * SHUTDOWN ACK from the server, awaiting for SHUTDOWN COM from client
812 */
813 /*
814 * We recieved the data chuck, keep the state unchanged. I assume
815 * that still data chuncks can be received by both the peers in
816 * SHUDOWN state
817 */
818
819 {{IP_VS_SCTP_S_SHUT_ACK_SER /* IP_VS_SCTP_EVE_DATA_CLI */ },
820 {IP_VS_SCTP_S_SHUT_ACK_SER /* IP_VS_SCTP_EVE_DATA_SER */ },
821 /*
822 * We have got an INIT from client. From the spec.“Upon receipt of
823 * an INIT in the COOKIE-WAIT state, an endpoint MUST respond with
824 * an INIT ACK using the same parameters it sent in its original
825 * INIT chunk (including its Initiate Tag, unchanged”).
826 */
827 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
828 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
829 /*
830 * INIT_ACK sent by the server, Unexpected INIT ACK, spec says,
831 * “If an INIT ACK is received by an endpoint in any state other
832 * than the COOKIE-WAIT state, the endpoint should discard the
833 * INIT ACK chunk”. Stay in the same state
834 */
835 {IP_VS_SCTP_S_SHUT_ACK_SER /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
836 {IP_VS_SCTP_S_SHUT_ACK_SER /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
837 /*
838 * Client sent ECHO, Spec(sec 5.2.4) says it may be handled by the
839 * peer and peer shall move to the ESTABISHED. if it doesn't handle
840 * it will send ERROR chunk. So, stay in the same state
841 */
842 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
843 {IP_VS_SCTP_S_ESTABLISHED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
844 /*
845 * COOKIE ACK from client, not sure what to do stay in the same state
846 */
847 {IP_VS_SCTP_S_SHUT_ACK_SER /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
848 {IP_VS_SCTP_S_SHUT_ACK_SER /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
849 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
850 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
851 /*
852 * SHUTDOWN sent from the client, move to SHUDDOWN_CLI
853 */
854 {IP_VS_SCTP_S_SHUT_CLI /* IP_VS_SCTP_EVE_SHUT_CLI */ },
855 /*
856 * SHUTDOWN sent from the server, move to SHUTDOWN_SER
857 */
858 {IP_VS_SCTP_S_SHUT_SER /* IP_VS_SCTP_EVE_SHUT_SER */ },
859 /*
860 * client sent SHUDTDOWN_ACK, this should not happen let's close
861 * the connection.
862 */
863 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
864 /*
865 * Server resent SHUTDOWN ACK, stay in the same state
866 */
867 {IP_VS_SCTP_S_SHUT_ACK_SER /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
868 /*
869 * SHUTDOWN COM from client, this what we are expecting, let's close
870 * the connection
871 */
872 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
873 /*
874 * SHUTDOWN COMPLETE from server this should not happen.
875 */
876 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
877 },
878 /*
879 * State : IP_VS_SCTP_S_CLOSED
880 */
881 {{IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_CLI */ },
882 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_DATA_SER */ },
883 {IP_VS_SCTP_S_INIT_CLI /* IP_VS_SCTP_EVE_INIT_CLI */ },
884 {IP_VS_SCTP_S_INIT_SER /* IP_VS_SCTP_EVE_INIT_SER */ },
885 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_CLI */ },
886 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_INIT_ACK_SER */ },
887 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ECHO_CLI */ },
888 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ECHO_SER */ },
889 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_CLI */ },
890 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_COOKIE_ACK_SER */ },
891 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_CLI */ },
892 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_ABORT_SER */ },
893 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_CLI */ },
894 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_SER */ },
895 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_CLI */ },
896 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_ACK_SER */ },
897 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_CLI */ },
898 {IP_VS_SCTP_S_CLOSED /* IP_VS_SCTP_EVE_SHUT_COM_SER */ }
899 }
900};
901
902/*
903 * Timeout table[state]
904 */
905static int sctp_timeouts[IP_VS_SCTP_S_LAST + 1] = {
906 [IP_VS_SCTP_S_NONE] = 2 * HZ,
907 [IP_VS_SCTP_S_INIT_CLI] = 1 * 60 * HZ,
908 [IP_VS_SCTP_S_INIT_SER] = 1 * 60 * HZ,
909 [IP_VS_SCTP_S_INIT_ACK_CLI] = 1 * 60 * HZ,
910 [IP_VS_SCTP_S_INIT_ACK_SER] = 1 * 60 * HZ,
911 [IP_VS_SCTP_S_ECHO_CLI] = 1 * 60 * HZ,
912 [IP_VS_SCTP_S_ECHO_SER] = 1 * 60 * HZ,
913 [IP_VS_SCTP_S_ESTABLISHED] = 15 * 60 * HZ,
914 [IP_VS_SCTP_S_SHUT_CLI] = 1 * 60 * HZ,
915 [IP_VS_SCTP_S_SHUT_SER] = 1 * 60 * HZ,
916 [IP_VS_SCTP_S_SHUT_ACK_CLI] = 1 * 60 * HZ,
917 [IP_VS_SCTP_S_SHUT_ACK_SER] = 1 * 60 * HZ,
918 [IP_VS_SCTP_S_CLOSED] = 10 * HZ,
919 [IP_VS_SCTP_S_LAST] = 2 * HZ,
920};
921
922static const char *sctp_state_name_table[IP_VS_SCTP_S_LAST + 1] = {
923 [IP_VS_SCTP_S_NONE] = "NONE",
924 [IP_VS_SCTP_S_INIT_CLI] = "INIT_CLI",
925 [IP_VS_SCTP_S_INIT_SER] = "INIT_SER",
926 [IP_VS_SCTP_S_INIT_ACK_CLI] = "INIT_ACK_CLI",
927 [IP_VS_SCTP_S_INIT_ACK_SER] = "INIT_ACK_SER",
928 [IP_VS_SCTP_S_ECHO_CLI] = "COOKIE_ECHO_CLI",
929 [IP_VS_SCTP_S_ECHO_SER] = "COOKIE_ECHO_SER",
930 [IP_VS_SCTP_S_ESTABLISHED] = "ESTABISHED",
931 [IP_VS_SCTP_S_SHUT_CLI] = "SHUTDOWN_CLI",
932 [IP_VS_SCTP_S_SHUT_SER] = "SHUTDOWN_SER",
933 [IP_VS_SCTP_S_SHUT_ACK_CLI] = "SHUTDOWN_ACK_CLI",
934 [IP_VS_SCTP_S_SHUT_ACK_SER] = "SHUTDOWN_ACK_SER",
935 [IP_VS_SCTP_S_CLOSED] = "CLOSED",
936 [IP_VS_SCTP_S_LAST] = "BUG!"
937};
938
939
940static const char *sctp_state_name(int state)
941{
942 if (state >= IP_VS_SCTP_S_LAST)
943 return "ERR!";
944 if (sctp_state_name_table[state])
945 return sctp_state_name_table[state];
946 return "?";
947}
948
949static void sctp_timeout_change(struct ip_vs_protocol *pp, int flags)
950{
951}
952
953static int
954sctp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
955{
956
957return ip_vs_set_state_timeout(pp->timeout_table, IP_VS_SCTP_S_LAST,
958 sctp_state_name_table, sname, to);
959}
960
961static inline int
962set_sctp_state(struct ip_vs_protocol *pp, struct ip_vs_conn *cp,
963 int direction, const struct sk_buff *skb)
964{
965 sctp_chunkhdr_t _sctpch, *sch;
966 unsigned char chunk_type;
967 int event, next_state;
968 int ihl;
969
970#ifdef CONFIG_IP_VS_IPV6
971 ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
972#else
973 ihl = ip_hdrlen(skb);
974#endif
975
976 sch = skb_header_pointer(skb, ihl + sizeof(sctp_sctphdr_t),
977 sizeof(_sctpch), &_sctpch);
978 if (sch == NULL)
979 return 0;
980
981 chunk_type = sch->type;
982 /*
983 * Section 3: Multiple chunks can be bundled into one SCTP packet
984 * up to the MTU size, except for the INIT, INIT ACK, and
985 * SHUTDOWN COMPLETE chunks. These chunks MUST NOT be bundled with
986 * any other chunk in a packet.
987 *
988 * Section 3.3.7: DATA chunks MUST NOT be bundled with ABORT. Control
989 * chunks (except for INIT, INIT ACK, and SHUTDOWN COMPLETE) MAY be
990 * bundled with an ABORT, but they MUST be placed before the ABORT
991 * in the SCTP packet or they will be ignored by the receiver.
992 */
993 if ((sch->type == SCTP_CID_COOKIE_ECHO) ||
994 (sch->type == SCTP_CID_COOKIE_ACK)) {
995 sch = skb_header_pointer(skb, (ihl + sizeof(sctp_sctphdr_t) +
996 sch->length), sizeof(_sctpch), &_sctpch);
997 if (sch) {
998 if (sch->type == SCTP_CID_ABORT)
999 chunk_type = sch->type;
1000 }
1001 }
1002
1003 event = sctp_events[chunk_type];
1004
1005 /*
1006 * If the direction is IP_VS_DIR_OUTPUT, this event is from server
1007 */
1008 if (direction == IP_VS_DIR_OUTPUT)
1009 event++;
1010 /*
1011 * get next state
1012 */
1013 next_state = sctp_states_table[cp->state][event].next_state;
1014
1015 if (next_state != cp->state) {
1016 struct ip_vs_dest *dest = cp->dest;
1017
1018 IP_VS_DBG_BUF(8, "%s %s %s:%d->"
1019 "%s:%d state: %s->%s conn->refcnt:%d\n",
1020 pp->name,
1021 ((direction == IP_VS_DIR_OUTPUT) ?
1022 "output " : "input "),
1023 IP_VS_DBG_ADDR(cp->af, &cp->daddr),
1024 ntohs(cp->dport),
1025 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
1026 ntohs(cp->cport),
1027 sctp_state_name(cp->state),
1028 sctp_state_name(next_state),
1029 atomic_read(&cp->refcnt));
1030 if (dest) {
1031 if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
1032 (next_state != IP_VS_SCTP_S_ESTABLISHED)) {
1033 atomic_dec(&dest->activeconns);
1034 atomic_inc(&dest->inactconns);
1035 cp->flags |= IP_VS_CONN_F_INACTIVE;
1036 } else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
1037 (next_state == IP_VS_SCTP_S_ESTABLISHED)) {
1038 atomic_inc(&dest->activeconns);
1039 atomic_dec(&dest->inactconns);
1040 cp->flags &= ~IP_VS_CONN_F_INACTIVE;
1041 }
1042 }
1043 }
1044
1045 cp->timeout = pp->timeout_table[cp->state = next_state];
1046
1047 return 1;
1048}
1049
1050static int
1051sctp_state_transition(struct ip_vs_conn *cp, int direction,
1052 const struct sk_buff *skb, struct ip_vs_protocol *pp)
1053{
1054 int ret = 0;
1055
1056 spin_lock(&cp->lock);
1057 ret = set_sctp_state(pp, cp, direction, skb);
1058 spin_unlock(&cp->lock);
1059
1060 return ret;
1061}
1062
1063/*
1064 * Hash table for SCTP application incarnations
1065 */
1066#define SCTP_APP_TAB_BITS 4
1067#define SCTP_APP_TAB_SIZE (1 << SCTP_APP_TAB_BITS)
1068#define SCTP_APP_TAB_MASK (SCTP_APP_TAB_SIZE - 1)
1069
1070static struct list_head sctp_apps[SCTP_APP_TAB_SIZE];
1071static DEFINE_SPINLOCK(sctp_app_lock);
1072
1073static inline __u16 sctp_app_hashkey(__be16 port)
1074{
1075 return (((__force u16)port >> SCTP_APP_TAB_BITS) ^ (__force u16)port)
1076 & SCTP_APP_TAB_MASK;
1077}
1078
1079static int sctp_register_app(struct ip_vs_app *inc)
1080{
1081 struct ip_vs_app *i;
1082 __u16 hash;
1083 __be16 port = inc->port;
1084 int ret = 0;
1085
1086 hash = sctp_app_hashkey(port);
1087
1088 spin_lock_bh(&sctp_app_lock);
1089 list_for_each_entry(i, &sctp_apps[hash], p_list) {
1090 if (i->port == port) {
1091 ret = -EEXIST;
1092 goto out;
1093 }
1094 }
1095 list_add(&inc->p_list, &sctp_apps[hash]);
1096 atomic_inc(&ip_vs_protocol_sctp.appcnt);
1097out:
1098 spin_unlock_bh(&sctp_app_lock);
1099
1100 return ret;
1101}
1102
1103static void sctp_unregister_app(struct ip_vs_app *inc)
1104{
1105 spin_lock_bh(&sctp_app_lock);
1106 atomic_dec(&ip_vs_protocol_sctp.appcnt);
1107 list_del(&inc->p_list);
1108 spin_unlock_bh(&sctp_app_lock);
1109}
1110
1111static int sctp_app_conn_bind(struct ip_vs_conn *cp)
1112{
1113 int hash;
1114 struct ip_vs_app *inc;
1115 int result = 0;
1116
1117 /* Default binding: bind app only for NAT */
1118 if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
1119 return 0;
1120 /* Lookup application incarnations and bind the right one */
1121 hash = sctp_app_hashkey(cp->vport);
1122
1123 spin_lock(&sctp_app_lock);
1124 list_for_each_entry(inc, &sctp_apps[hash], p_list) {
1125 if (inc->port == cp->vport) {
1126 if (unlikely(!ip_vs_app_inc_get(inc)))
1127 break;
1128 spin_unlock(&sctp_app_lock);
1129
1130 IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
1131 "%s:%u to app %s on port %u\n",
1132 __func__,
1133 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
1134 ntohs(cp->cport),
1135 IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
1136 ntohs(cp->vport),
1137 inc->name, ntohs(inc->port));
1138 cp->app = inc;
1139 if (inc->init_conn)
1140 result = inc->init_conn(inc, cp);
1141 goto out;
1142 }
1143 }
1144 spin_unlock(&sctp_app_lock);
1145out:
1146 return result;
1147}
1148
1149static void ip_vs_sctp_init(struct ip_vs_protocol *pp)
1150{
1151 IP_VS_INIT_HASH_TABLE(sctp_apps);
1152 pp->timeout_table = sctp_timeouts;
1153}
1154
1155
1156static void ip_vs_sctp_exit(struct ip_vs_protocol *pp)
1157{
1158
1159}
1160
1161struct ip_vs_protocol ip_vs_protocol_sctp = {
1162 .name = "SCTP",
1163 .protocol = IPPROTO_SCTP,
1164 .num_states = IP_VS_SCTP_S_LAST,
1165 .dont_defrag = 0,
1166 .appcnt = ATOMIC_INIT(0),
1167 .init = ip_vs_sctp_init,
1168 .exit = ip_vs_sctp_exit,
1169 .register_app = sctp_register_app,
1170 .unregister_app = sctp_unregister_app,
1171 .conn_schedule = sctp_conn_schedule,
1172 .conn_in_get = sctp_conn_in_get,
1173 .conn_out_get = sctp_conn_out_get,
1174 .snat_handler = sctp_snat_handler,
1175 .dnat_handler = sctp_dnat_handler,
1176 .csum_check = sctp_csum_check,
1177 .state_name = sctp_state_name,
1178 .state_transition = sctp_state_transition,
1179 .app_conn_bind = sctp_app_conn_bind,
1180 .debug_packet = ip_vs_tcpudp_debug_packet,
1181 .timeout_change = sctp_timeout_change,
1182 .set_state_timeout = sctp_set_state_timeout,
1183};
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index e177f0dc208..8fb0ae61676 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -400,6 +400,11 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
400 flags |= IP_VS_CONN_F_INACTIVE; 400 flags |= IP_VS_CONN_F_INACTIVE;
401 else 401 else
402 flags &= ~IP_VS_CONN_F_INACTIVE; 402 flags &= ~IP_VS_CONN_F_INACTIVE;
403 } else if (s->protocol == IPPROTO_SCTP) {
404 if (state != IP_VS_SCTP_S_ESTABLISHED)
405 flags |= IP_VS_CONN_F_INACTIVE;
406 else
407 flags &= ~IP_VS_CONN_F_INACTIVE;
403 } 408 }
404 cp = ip_vs_conn_new(AF_INET, s->protocol, 409 cp = ip_vs_conn_new(AF_INET, s->protocol,
405 (union nf_inet_addr *)&s->caddr, 410 (union nf_inet_addr *)&s->caddr,
@@ -434,6 +439,15 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
434 atomic_dec(&dest->inactconns); 439 atomic_dec(&dest->inactconns);
435 cp->flags &= ~IP_VS_CONN_F_INACTIVE; 440 cp->flags &= ~IP_VS_CONN_F_INACTIVE;
436 } 441 }
442 } else if ((cp->dest) && (cp->protocol == IPPROTO_SCTP) &&
443 (cp->state != state)) {
444 dest = cp->dest;
445 if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
446 (state != IP_VS_SCTP_S_ESTABLISHED)) {
447 atomic_dec(&dest->activeconns);
448 atomic_inc(&dest->inactconns);
449 cp->flags &= ~IP_VS_CONN_F_INACTIVE;
450 }
437 } 451 }
438 452
439 if (opt) 453 if (opt)