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