This source file includes following definitions.
- sctp_conn_schedule
- sctp_nat_csum
- sctp_snat_handler
- sctp_dnat_handler
- sctp_csum_check
- sctp_state_name
- set_sctp_state
- sctp_state_transition
- sctp_app_hashkey
- sctp_register_app
- sctp_unregister_app
- sctp_app_conn_bind
- __ip_vs_sctp_init
- __ip_vs_sctp_exit
1
2 #include <linux/kernel.h>
3 #include <linux/ip.h>
4 #include <linux/sctp.h>
5 #include <net/ip.h>
6 #include <net/ip6_checksum.h>
7 #include <linux/netfilter.h>
8 #include <linux/netfilter_ipv4.h>
9 #include <net/sctp/checksum.h>
10 #include <net/ip_vs.h>
11
12 static int
13 sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
14
15 static int
16 sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
17 struct ip_vs_proto_data *pd,
18 int *verdict, struct ip_vs_conn **cpp,
19 struct ip_vs_iphdr *iph)
20 {
21 struct ip_vs_service *svc;
22 struct sctp_chunkhdr _schunkh, *sch;
23 struct sctphdr *sh, _sctph;
24 __be16 _ports[2], *ports = NULL;
25
26 if (likely(!ip_vs_iph_icmp(iph))) {
27 sh = skb_header_pointer(skb, iph->len, sizeof(_sctph), &_sctph);
28 if (sh) {
29 sch = skb_header_pointer(skb, iph->len + sizeof(_sctph),
30 sizeof(_schunkh), &_schunkh);
31 if (sch) {
32 if (sch->type == SCTP_CID_ABORT ||
33 !(sysctl_sloppy_sctp(ipvs) ||
34 sch->type == SCTP_CID_INIT))
35 return 1;
36 ports = &sh->source;
37 }
38 }
39 } else {
40 ports = skb_header_pointer(
41 skb, iph->len, sizeof(_ports), &_ports);
42 }
43
44 if (!ports) {
45 *verdict = NF_DROP;
46 return 0;
47 }
48
49 if (likely(!ip_vs_iph_inverse(iph)))
50 svc = ip_vs_service_find(ipvs, af, skb->mark, iph->protocol,
51 &iph->daddr, ports[1]);
52 else
53 svc = ip_vs_service_find(ipvs, af, skb->mark, iph->protocol,
54 &iph->saddr, ports[0]);
55 if (svc) {
56 int ignored;
57
58 if (ip_vs_todrop(ipvs)) {
59
60
61
62
63 *verdict = NF_DROP;
64 return 0;
65 }
66
67
68
69
70 *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph);
71 if (!*cpp && ignored <= 0) {
72 if (!ignored)
73 *verdict = ip_vs_leave(svc, skb, pd, iph);
74 else
75 *verdict = NF_DROP;
76 return 0;
77 }
78 }
79
80 return 1;
81 }
82
83 static void sctp_nat_csum(struct sk_buff *skb, struct sctphdr *sctph,
84 unsigned int sctphoff)
85 {
86 sctph->checksum = sctp_compute_cksum(skb, sctphoff);
87 skb->ip_summed = CHECKSUM_UNNECESSARY;
88 }
89
90 static int
91 sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
92 struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
93 {
94 struct sctphdr *sctph;
95 unsigned int sctphoff = iph->len;
96 bool payload_csum = false;
97
98 #ifdef CONFIG_IP_VS_IPV6
99 if (cp->af == AF_INET6 && iph->fragoffs)
100 return 1;
101 #endif
102
103
104 if (skb_ensure_writable(skb, sctphoff + sizeof(*sctph)))
105 return 0;
106
107 if (unlikely(cp->app != NULL)) {
108 int ret;
109
110
111 if (!sctp_csum_check(cp->af, skb, pp))
112 return 0;
113
114
115 ret = ip_vs_app_pkt_out(cp, skb, iph);
116 if (ret == 0)
117 return 0;
118
119 if (ret == 2)
120 payload_csum = true;
121 }
122
123 sctph = (void *) skb_network_header(skb) + sctphoff;
124
125
126 if (sctph->source != cp->vport || payload_csum ||
127 skb->ip_summed == CHECKSUM_PARTIAL) {
128 sctph->source = cp->vport;
129 sctp_nat_csum(skb, sctph, sctphoff);
130 } else {
131 skb->ip_summed = CHECKSUM_UNNECESSARY;
132 }
133
134 return 1;
135 }
136
137 static int
138 sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
139 struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
140 {
141 struct sctphdr *sctph;
142 unsigned int sctphoff = iph->len;
143 bool payload_csum = false;
144
145 #ifdef CONFIG_IP_VS_IPV6
146 if (cp->af == AF_INET6 && iph->fragoffs)
147 return 1;
148 #endif
149
150
151 if (skb_ensure_writable(skb, sctphoff + sizeof(*sctph)))
152 return 0;
153
154 if (unlikely(cp->app != NULL)) {
155 int ret;
156
157
158 if (!sctp_csum_check(cp->af, skb, pp))
159 return 0;
160
161
162 ret = ip_vs_app_pkt_in(cp, skb, iph);
163 if (ret == 0)
164 return 0;
165
166 if (ret == 2)
167 payload_csum = true;
168 }
169
170 sctph = (void *) skb_network_header(skb) + sctphoff;
171
172
173 if (sctph->dest != cp->dport || payload_csum ||
174 (skb->ip_summed == CHECKSUM_PARTIAL &&
175 !(skb_dst(skb)->dev->features & NETIF_F_SCTP_CRC))) {
176 sctph->dest = cp->dport;
177 sctp_nat_csum(skb, sctph, sctphoff);
178 } else if (skb->ip_summed != CHECKSUM_PARTIAL) {
179 skb->ip_summed = CHECKSUM_UNNECESSARY;
180 }
181
182 return 1;
183 }
184
185 static int
186 sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
187 {
188 unsigned int sctphoff;
189 struct sctphdr *sh;
190 __le32 cmp, val;
191
192 #ifdef CONFIG_IP_VS_IPV6
193 if (af == AF_INET6)
194 sctphoff = sizeof(struct ipv6hdr);
195 else
196 #endif
197 sctphoff = ip_hdrlen(skb);
198
199 sh = (struct sctphdr *)(skb->data + sctphoff);
200 cmp = sh->checksum;
201 val = sctp_compute_cksum(skb, sctphoff);
202
203 if (val != cmp) {
204
205 IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
206 "Failed checksum for");
207 return 0;
208 }
209 return 1;
210 }
211
212 enum ipvs_sctp_event_t {
213 IP_VS_SCTP_DATA = 0,
214 IP_VS_SCTP_INIT,
215 IP_VS_SCTP_INIT_ACK,
216 IP_VS_SCTP_COOKIE_ECHO,
217 IP_VS_SCTP_COOKIE_ACK,
218 IP_VS_SCTP_SHUTDOWN,
219 IP_VS_SCTP_SHUTDOWN_ACK,
220 IP_VS_SCTP_SHUTDOWN_COMPLETE,
221 IP_VS_SCTP_ERROR,
222 IP_VS_SCTP_ABORT,
223 IP_VS_SCTP_EVENT_LAST
224 };
225
226
227 static __u8 sctp_events[] = {
228 [SCTP_CID_DATA] = IP_VS_SCTP_DATA,
229 [SCTP_CID_INIT] = IP_VS_SCTP_INIT,
230 [SCTP_CID_INIT_ACK] = IP_VS_SCTP_INIT_ACK,
231 [SCTP_CID_SACK] = IP_VS_SCTP_DATA,
232 [SCTP_CID_HEARTBEAT] = IP_VS_SCTP_DATA,
233 [SCTP_CID_HEARTBEAT_ACK] = IP_VS_SCTP_DATA,
234 [SCTP_CID_ABORT] = IP_VS_SCTP_ABORT,
235 [SCTP_CID_SHUTDOWN] = IP_VS_SCTP_SHUTDOWN,
236 [SCTP_CID_SHUTDOWN_ACK] = IP_VS_SCTP_SHUTDOWN_ACK,
237 [SCTP_CID_ERROR] = IP_VS_SCTP_ERROR,
238 [SCTP_CID_COOKIE_ECHO] = IP_VS_SCTP_COOKIE_ECHO,
239 [SCTP_CID_COOKIE_ACK] = IP_VS_SCTP_COOKIE_ACK,
240 [SCTP_CID_ECN_ECNE] = IP_VS_SCTP_DATA,
241 [SCTP_CID_ECN_CWR] = IP_VS_SCTP_DATA,
242 [SCTP_CID_SHUTDOWN_COMPLETE] = IP_VS_SCTP_SHUTDOWN_COMPLETE,
243 };
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270 #define sNO IP_VS_SCTP_S_NONE
271 #define sI1 IP_VS_SCTP_S_INIT1
272 #define sIN IP_VS_SCTP_S_INIT
273 #define sCS IP_VS_SCTP_S_COOKIE_SENT
274 #define sCR IP_VS_SCTP_S_COOKIE_REPLIED
275 #define sCW IP_VS_SCTP_S_COOKIE_WAIT
276 #define sCO IP_VS_SCTP_S_COOKIE
277 #define sCE IP_VS_SCTP_S_COOKIE_ECHOED
278 #define sES IP_VS_SCTP_S_ESTABLISHED
279 #define sSS IP_VS_SCTP_S_SHUTDOWN_SENT
280 #define sSR IP_VS_SCTP_S_SHUTDOWN_RECEIVED
281 #define sSA IP_VS_SCTP_S_SHUTDOWN_ACK_SENT
282 #define sRJ IP_VS_SCTP_S_REJECTED
283 #define sCL IP_VS_SCTP_S_CLOSED
284
285 static const __u8 sctp_states
286 [IP_VS_DIR_LAST][IP_VS_SCTP_EVENT_LAST][IP_VS_SCTP_S_LAST] = {
287 {
288
289 {sES, sI1, sIN, sCS, sCR, sCW, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
290 {sI1, sIN, sIN, sCS, sCR, sCW, sCO, sCE, sES, sSS, sSR, sSA, sIN, sIN},
291 {sCW, sCW, sCW, sCS, sCR, sCO, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
292 {sCR, sIN, sIN, sCR, sCR, sCW, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
293 {sES, sI1, sIN, sCS, sCR, sCW, sCO, sES, sES, sSS, sSR, sSA, sRJ, sCL},
294 {sSR, sI1, sIN, sCS, sCR, sCW, sCO, sCE, sSR, sSS, sSR, sSA, sRJ, sCL},
295 {sCL, sIN, sIN, sCS, sCR, sCW, sCO, sCE, sES, sCL, sSR, sCL, sRJ, sCL},
296 {sCL, sCL, sCL, sCS, sCR, sCW, sCO, sCE, sES, sSS, sSR, sCL, sRJ, sCL},
297 {sCL, sI1, sIN, sCS, sCR, sCW, sCO, sCL, sES, sSS, sSR, sSA, sRJ, sCL},
298 {sCL, sCL, sCL, sCL, sCL, sRJ, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
299 },
300 {
301
302 {sES, sI1, sIN, sCS, sCR, sCW, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
303 {sCW, sCW, sCW, sCW, sCW, sCW, sCW, sCW, sES, sCW, sCW, sCW, sCW, sCW},
304 {sCS, sCS, sCS, sCS, sCR, sCW, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
305 {sCE, sCE, sCE, sCE, sCE, sCE, sCE, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
306 {sES, sES, sES, sES, sES, sES, sES, sES, sES, sSS, sSR, sSA, sRJ, sCL},
307 {sSS, sSS, sSS, sSS, sSS, sSS, sSS, sSS, sSS, sSS, sSR, sSA, sRJ, sCL},
308 {sSA, sSA, sSA, sSA, sSA, sCW, sCO, sCE, sES, sSA, sSA, sSA, sRJ, sCL},
309 {sCL, sI1, sIN, sCS, sCR, sCW, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
310 {sCL, sCL, sCL, sCL, sCL, sCW, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
311 {sCL, sRJ, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
312 },
313 {
314
315 {sES, sI1, sIN, sCS, sCR, sES, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
316 {sI1, sIN, sIN, sIN, sIN, sIN, sCO, sCE, sES, sSS, sSR, sSA, sIN, sIN},
317 {sCE, sCE, sCE, sCE, sCE, sCE, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
318 {sES, sES, sES, sES, sES, sES, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
319 {sES, sI1, sIN, sES, sES, sCW, sES, sES, sES, sSS, sSR, sSA, sRJ, sCL},
320 {sSR, sI1, sIN, sCS, sCR, sCW, sCO, sCE, sSR, sSS, sSR, sSA, sRJ, sCL},
321 {sCL, sIN, sIN, sCS, sCR, sCW, sCO, sCE, sCL, sCL, sSR, sCL, sRJ, sCL},
322 {sCL, sCL, sCL, sCL, sCL, sCW, sCO, sCE, sES, sSS, sCL, sCL, sRJ, sCL},
323 {sCL, sI1, sIN, sCS, sCR, sCW, sCO, sCE, sES, sSS, sSR, sSA, sRJ, sCL},
324 {sCL, sCL, sCL, sCL, sCL, sRJ, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
325 },
326 };
327
328 #define IP_VS_SCTP_MAX_RTO ((60 + 1) * HZ)
329
330
331 static const int sctp_timeouts[IP_VS_SCTP_S_LAST + 1] = {
332 [IP_VS_SCTP_S_NONE] = 2 * HZ,
333 [IP_VS_SCTP_S_INIT1] = (0 + 3 + 1) * HZ,
334 [IP_VS_SCTP_S_INIT] = IP_VS_SCTP_MAX_RTO,
335 [IP_VS_SCTP_S_COOKIE_SENT] = IP_VS_SCTP_MAX_RTO,
336 [IP_VS_SCTP_S_COOKIE_REPLIED] = IP_VS_SCTP_MAX_RTO,
337 [IP_VS_SCTP_S_COOKIE_WAIT] = IP_VS_SCTP_MAX_RTO,
338 [IP_VS_SCTP_S_COOKIE] = IP_VS_SCTP_MAX_RTO,
339 [IP_VS_SCTP_S_COOKIE_ECHOED] = IP_VS_SCTP_MAX_RTO,
340 [IP_VS_SCTP_S_ESTABLISHED] = 15 * 60 * HZ,
341 [IP_VS_SCTP_S_SHUTDOWN_SENT] = IP_VS_SCTP_MAX_RTO,
342 [IP_VS_SCTP_S_SHUTDOWN_RECEIVED] = IP_VS_SCTP_MAX_RTO,
343 [IP_VS_SCTP_S_SHUTDOWN_ACK_SENT] = IP_VS_SCTP_MAX_RTO,
344 [IP_VS_SCTP_S_REJECTED] = (0 + 3 + 1) * HZ,
345 [IP_VS_SCTP_S_CLOSED] = IP_VS_SCTP_MAX_RTO,
346 [IP_VS_SCTP_S_LAST] = 2 * HZ,
347 };
348
349 static const char *sctp_state_name_table[IP_VS_SCTP_S_LAST + 1] = {
350 [IP_VS_SCTP_S_NONE] = "NONE",
351 [IP_VS_SCTP_S_INIT1] = "INIT1",
352 [IP_VS_SCTP_S_INIT] = "INIT",
353 [IP_VS_SCTP_S_COOKIE_SENT] = "C-SENT",
354 [IP_VS_SCTP_S_COOKIE_REPLIED] = "C-REPLIED",
355 [IP_VS_SCTP_S_COOKIE_WAIT] = "C-WAIT",
356 [IP_VS_SCTP_S_COOKIE] = "COOKIE",
357 [IP_VS_SCTP_S_COOKIE_ECHOED] = "C-ECHOED",
358 [IP_VS_SCTP_S_ESTABLISHED] = "ESTABLISHED",
359 [IP_VS_SCTP_S_SHUTDOWN_SENT] = "S-SENT",
360 [IP_VS_SCTP_S_SHUTDOWN_RECEIVED] = "S-RECEIVED",
361 [IP_VS_SCTP_S_SHUTDOWN_ACK_SENT] = "S-ACK-SENT",
362 [IP_VS_SCTP_S_REJECTED] = "REJECTED",
363 [IP_VS_SCTP_S_CLOSED] = "CLOSED",
364 [IP_VS_SCTP_S_LAST] = "BUG!",
365 };
366
367
368 static const char *sctp_state_name(int state)
369 {
370 if (state >= IP_VS_SCTP_S_LAST)
371 return "ERR!";
372 if (sctp_state_name_table[state])
373 return sctp_state_name_table[state];
374 return "?";
375 }
376
377 static inline void
378 set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
379 int direction, const struct sk_buff *skb)
380 {
381 struct sctp_chunkhdr _sctpch, *sch;
382 unsigned char chunk_type;
383 int event, next_state;
384 int ihl, cofs;
385
386 #ifdef CONFIG_IP_VS_IPV6
387 ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
388 #else
389 ihl = ip_hdrlen(skb);
390 #endif
391
392 cofs = ihl + sizeof(struct sctphdr);
393 sch = skb_header_pointer(skb, cofs, sizeof(_sctpch), &_sctpch);
394 if (sch == NULL)
395 return;
396
397 chunk_type = sch->type;
398
399
400
401
402
403
404
405
406
407
408
409 if ((sch->type == SCTP_CID_COOKIE_ECHO) ||
410 (sch->type == SCTP_CID_COOKIE_ACK)) {
411 int clen = ntohs(sch->length);
412
413 if (clen >= sizeof(_sctpch)) {
414 sch = skb_header_pointer(skb, cofs + ALIGN(clen, 4),
415 sizeof(_sctpch), &_sctpch);
416 if (sch && sch->type == SCTP_CID_ABORT)
417 chunk_type = sch->type;
418 }
419 }
420
421 event = (chunk_type < sizeof(sctp_events)) ?
422 sctp_events[chunk_type] : IP_VS_SCTP_DATA;
423
424
425
426
427 if (cp->flags & IP_VS_CONN_F_NOOUTPUT) {
428 if (direction == IP_VS_DIR_OUTPUT)
429 cp->flags &= ~IP_VS_CONN_F_NOOUTPUT;
430 else
431 direction = IP_VS_DIR_INPUT_ONLY;
432 }
433
434 next_state = sctp_states[direction][event][cp->state];
435
436 if (next_state != cp->state) {
437 struct ip_vs_dest *dest = cp->dest;
438
439 IP_VS_DBG_BUF(8, "%s %s %s:%d->"
440 "%s:%d state: %s->%s conn->refcnt:%d\n",
441 pd->pp->name,
442 ((direction == IP_VS_DIR_OUTPUT) ?
443 "output " : "input "),
444 IP_VS_DBG_ADDR(cp->daf, &cp->daddr),
445 ntohs(cp->dport),
446 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
447 ntohs(cp->cport),
448 sctp_state_name(cp->state),
449 sctp_state_name(next_state),
450 refcount_read(&cp->refcnt));
451 if (dest) {
452 if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
453 (next_state != IP_VS_SCTP_S_ESTABLISHED)) {
454 atomic_dec(&dest->activeconns);
455 atomic_inc(&dest->inactconns);
456 cp->flags |= IP_VS_CONN_F_INACTIVE;
457 } else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
458 (next_state == IP_VS_SCTP_S_ESTABLISHED)) {
459 atomic_inc(&dest->activeconns);
460 atomic_dec(&dest->inactconns);
461 cp->flags &= ~IP_VS_CONN_F_INACTIVE;
462 }
463 }
464 if (next_state == IP_VS_SCTP_S_ESTABLISHED)
465 ip_vs_control_assure_ct(cp);
466 }
467 if (likely(pd))
468 cp->timeout = pd->timeout_table[cp->state = next_state];
469 else
470 cp->timeout = sctp_timeouts[cp->state = next_state];
471 }
472
473 static void
474 sctp_state_transition(struct ip_vs_conn *cp, int direction,
475 const struct sk_buff *skb, struct ip_vs_proto_data *pd)
476 {
477 spin_lock_bh(&cp->lock);
478 set_sctp_state(pd, cp, direction, skb);
479 spin_unlock_bh(&cp->lock);
480 }
481
482 static inline __u16 sctp_app_hashkey(__be16 port)
483 {
484 return (((__force u16)port >> SCTP_APP_TAB_BITS) ^ (__force u16)port)
485 & SCTP_APP_TAB_MASK;
486 }
487
488 static int sctp_register_app(struct netns_ipvs *ipvs, struct ip_vs_app *inc)
489 {
490 struct ip_vs_app *i;
491 __u16 hash;
492 __be16 port = inc->port;
493 int ret = 0;
494 struct ip_vs_proto_data *pd = ip_vs_proto_data_get(ipvs, IPPROTO_SCTP);
495
496 hash = sctp_app_hashkey(port);
497
498 list_for_each_entry(i, &ipvs->sctp_apps[hash], p_list) {
499 if (i->port == port) {
500 ret = -EEXIST;
501 goto out;
502 }
503 }
504 list_add_rcu(&inc->p_list, &ipvs->sctp_apps[hash]);
505 atomic_inc(&pd->appcnt);
506 out:
507
508 return ret;
509 }
510
511 static void sctp_unregister_app(struct netns_ipvs *ipvs, struct ip_vs_app *inc)
512 {
513 struct ip_vs_proto_data *pd = ip_vs_proto_data_get(ipvs, IPPROTO_SCTP);
514
515 atomic_dec(&pd->appcnt);
516 list_del_rcu(&inc->p_list);
517 }
518
519 static int sctp_app_conn_bind(struct ip_vs_conn *cp)
520 {
521 struct netns_ipvs *ipvs = cp->ipvs;
522 int hash;
523 struct ip_vs_app *inc;
524 int result = 0;
525
526
527 if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
528 return 0;
529
530 hash = sctp_app_hashkey(cp->vport);
531
532 list_for_each_entry_rcu(inc, &ipvs->sctp_apps[hash], p_list) {
533 if (inc->port == cp->vport) {
534 if (unlikely(!ip_vs_app_inc_get(inc)))
535 break;
536
537 IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
538 "%s:%u to app %s on port %u\n",
539 __func__,
540 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
541 ntohs(cp->cport),
542 IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
543 ntohs(cp->vport),
544 inc->name, ntohs(inc->port));
545 cp->app = inc;
546 if (inc->init_conn)
547 result = inc->init_conn(inc, cp);
548 break;
549 }
550 }
551
552 return result;
553 }
554
555
556
557
558
559 static int __ip_vs_sctp_init(struct netns_ipvs *ipvs, struct ip_vs_proto_data *pd)
560 {
561 ip_vs_init_hash_table(ipvs->sctp_apps, SCTP_APP_TAB_SIZE);
562 pd->timeout_table = ip_vs_create_timeout_table((int *)sctp_timeouts,
563 sizeof(sctp_timeouts));
564 if (!pd->timeout_table)
565 return -ENOMEM;
566 return 0;
567 }
568
569 static void __ip_vs_sctp_exit(struct netns_ipvs *ipvs, struct ip_vs_proto_data *pd)
570 {
571 kfree(pd->timeout_table);
572 }
573
574 struct ip_vs_protocol ip_vs_protocol_sctp = {
575 .name = "SCTP",
576 .protocol = IPPROTO_SCTP,
577 .num_states = IP_VS_SCTP_S_LAST,
578 .dont_defrag = 0,
579 .init = NULL,
580 .exit = NULL,
581 .init_netns = __ip_vs_sctp_init,
582 .exit_netns = __ip_vs_sctp_exit,
583 .register_app = sctp_register_app,
584 .unregister_app = sctp_unregister_app,
585 .conn_schedule = sctp_conn_schedule,
586 .conn_in_get = ip_vs_conn_in_get_proto,
587 .conn_out_get = ip_vs_conn_out_get_proto,
588 .snat_handler = sctp_snat_handler,
589 .dnat_handler = sctp_dnat_handler,
590 .state_name = sctp_state_name,
591 .state_transition = sctp_state_transition,
592 .app_conn_bind = sctp_app_conn_bind,
593 .debug_packet = ip_vs_tcpudp_debug_packet,
594 .timeout_change = NULL,
595 };