diff options
-rw-r--r-- | include/net/request_sock.h | 5 | ||||
-rw-r--r-- | net/core/request_sock.c | 26 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 35 |
3 files changed, 40 insertions, 26 deletions
diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 72fd6f5e86b1..334717bf9ef6 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h | |||
@@ -89,6 +89,7 @@ struct listen_sock { | |||
89 | int qlen_young; | 89 | int qlen_young; |
90 | int clock_hand; | 90 | int clock_hand; |
91 | u32 hash_rnd; | 91 | u32 hash_rnd; |
92 | u32 nr_table_entries; | ||
92 | struct request_sock *syn_table[0]; | 93 | struct request_sock *syn_table[0]; |
93 | }; | 94 | }; |
94 | 95 | ||
@@ -129,11 +130,13 @@ static inline struct listen_sock *reqsk_queue_yank_listen_sk(struct request_sock | |||
129 | return lopt; | 130 | return lopt; |
130 | } | 131 | } |
131 | 132 | ||
132 | static inline void reqsk_queue_destroy(struct request_sock_queue *queue) | 133 | static inline void __reqsk_queue_destroy(struct request_sock_queue *queue) |
133 | { | 134 | { |
134 | kfree(reqsk_queue_yank_listen_sk(queue)); | 135 | kfree(reqsk_queue_yank_listen_sk(queue)); |
135 | } | 136 | } |
136 | 137 | ||
138 | extern void reqsk_queue_destroy(struct request_sock_queue *queue); | ||
139 | |||
137 | static inline struct request_sock * | 140 | static inline struct request_sock * |
138 | reqsk_queue_yank_acceptq(struct request_sock_queue *queue) | 141 | reqsk_queue_yank_acceptq(struct request_sock_queue *queue) |
139 | { | 142 | { |
diff --git a/net/core/request_sock.c b/net/core/request_sock.c index bb55675f0685..4e99ce5c08f2 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c | |||
@@ -53,6 +53,7 @@ int reqsk_queue_alloc(struct request_sock_queue *queue, | |||
53 | get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd)); | 53 | get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd)); |
54 | rwlock_init(&queue->syn_wait_lock); | 54 | rwlock_init(&queue->syn_wait_lock); |
55 | queue->rskq_accept_head = queue->rskq_accept_head = NULL; | 55 | queue->rskq_accept_head = queue->rskq_accept_head = NULL; |
56 | lopt->nr_table_entries = nr_table_entries; | ||
56 | 57 | ||
57 | write_lock_bh(&queue->syn_wait_lock); | 58 | write_lock_bh(&queue->syn_wait_lock); |
58 | queue->listen_opt = lopt; | 59 | queue->listen_opt = lopt; |
@@ -62,3 +63,28 @@ int reqsk_queue_alloc(struct request_sock_queue *queue, | |||
62 | } | 63 | } |
63 | 64 | ||
64 | EXPORT_SYMBOL(reqsk_queue_alloc); | 65 | EXPORT_SYMBOL(reqsk_queue_alloc); |
66 | |||
67 | void reqsk_queue_destroy(struct request_sock_queue *queue) | ||
68 | { | ||
69 | /* make all the listen_opt local to us */ | ||
70 | struct listen_sock *lopt = reqsk_queue_yank_listen_sk(queue); | ||
71 | |||
72 | if (lopt->qlen != 0) { | ||
73 | int i; | ||
74 | |||
75 | for (i = 0; i < lopt->nr_table_entries; i++) { | ||
76 | struct request_sock *req; | ||
77 | |||
78 | while ((req = lopt->syn_table[i]) != NULL) { | ||
79 | lopt->syn_table[i] = req->dl_next; | ||
80 | lopt->qlen--; | ||
81 | reqsk_free(req); | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | BUG_TRAP(lopt->qlen == 0); | ||
87 | kfree(lopt); | ||
88 | } | ||
89 | |||
90 | EXPORT_SYMBOL(reqsk_queue_destroy); | ||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index d2696af46c70..42a2e2ccd430 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -487,7 +487,7 @@ int tcp_listen_start(struct sock *sk) | |||
487 | } | 487 | } |
488 | 488 | ||
489 | sk->sk_state = TCP_CLOSE; | 489 | sk->sk_state = TCP_CLOSE; |
490 | reqsk_queue_destroy(&tp->accept_queue); | 490 | __reqsk_queue_destroy(&tp->accept_queue); |
491 | return -EADDRINUSE; | 491 | return -EADDRINUSE; |
492 | } | 492 | } |
493 | 493 | ||
@@ -499,38 +499,23 @@ int tcp_listen_start(struct sock *sk) | |||
499 | static void tcp_listen_stop (struct sock *sk) | 499 | static void tcp_listen_stop (struct sock *sk) |
500 | { | 500 | { |
501 | struct tcp_sock *tp = tcp_sk(sk); | 501 | struct tcp_sock *tp = tcp_sk(sk); |
502 | struct listen_sock *lopt; | ||
503 | struct request_sock *acc_req; | 502 | struct request_sock *acc_req; |
504 | struct request_sock *req; | 503 | struct request_sock *req; |
505 | int i; | ||
506 | 504 | ||
507 | tcp_delete_keepalive_timer(sk); | 505 | tcp_delete_keepalive_timer(sk); |
508 | 506 | ||
509 | /* make all the listen_opt local to us */ | 507 | /* make all the listen_opt local to us */ |
510 | lopt = reqsk_queue_yank_listen_sk(&tp->accept_queue); | ||
511 | acc_req = reqsk_queue_yank_acceptq(&tp->accept_queue); | 508 | acc_req = reqsk_queue_yank_acceptq(&tp->accept_queue); |
512 | 509 | ||
513 | if (lopt->qlen) { | 510 | /* Following specs, it would be better either to send FIN |
514 | for (i = 0; i < TCP_SYNQ_HSIZE; i++) { | 511 | * (and enter FIN-WAIT-1, it is normal close) |
515 | while ((req = lopt->syn_table[i]) != NULL) { | 512 | * or to send active reset (abort). |
516 | lopt->syn_table[i] = req->dl_next; | 513 | * Certainly, it is pretty dangerous while synflood, but it is |
517 | lopt->qlen--; | 514 | * bad justification for our negligence 8) |
518 | reqsk_free(req); | 515 | * To be honest, we are not able to make either |
519 | 516 | * of the variants now. --ANK | |
520 | /* Following specs, it would be better either to send FIN | 517 | */ |
521 | * (and enter FIN-WAIT-1, it is normal close) | 518 | reqsk_queue_destroy(&tp->accept_queue); |
522 | * or to send active reset (abort). | ||
523 | * Certainly, it is pretty dangerous while synflood, but it is | ||
524 | * bad justification for our negligence 8) | ||
525 | * To be honest, we are not able to make either | ||
526 | * of the variants now. --ANK | ||
527 | */ | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | BUG_TRAP(!lopt->qlen); | ||
532 | |||
533 | kfree(lopt); | ||
534 | 519 | ||
535 | while ((req = acc_req) != NULL) { | 520 | while ((req = acc_req) != NULL) { |
536 | struct sock *child = req->sk; | 521 | struct sock *child = req->sk; |