diff options
Diffstat (limited to 'net/dccp/minisocks.c')
-rw-r--r-- | net/dccp/minisocks.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index e267e6f4c9a5..abd07a443219 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c | |||
@@ -142,6 +142,13 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, | |||
142 | struct dccp_request_sock *dreq = dccp_rsk(req); | 142 | struct dccp_request_sock *dreq = dccp_rsk(req); |
143 | bool own_req; | 143 | bool own_req; |
144 | 144 | ||
145 | /* TCP/DCCP listeners became lockless. | ||
146 | * DCCP stores complex state in its request_sock, so we need | ||
147 | * a protection for them, now this code runs without being protected | ||
148 | * by the parent (listener) lock. | ||
149 | */ | ||
150 | spin_lock_bh(&dreq->dreq_lock); | ||
151 | |||
145 | /* Check for retransmitted REQUEST */ | 152 | /* Check for retransmitted REQUEST */ |
146 | if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) { | 153 | if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) { |
147 | 154 | ||
@@ -156,7 +163,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, | |||
156 | inet_rtx_syn_ack(sk, req); | 163 | inet_rtx_syn_ack(sk, req); |
157 | } | 164 | } |
158 | /* Network Duplicate, discard packet */ | 165 | /* Network Duplicate, discard packet */ |
159 | return NULL; | 166 | goto out; |
160 | } | 167 | } |
161 | 168 | ||
162 | DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR; | 169 | DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR; |
@@ -182,20 +189,20 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, | |||
182 | 189 | ||
183 | child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, | 190 | child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, |
184 | req, &own_req); | 191 | req, &own_req); |
185 | if (!child) | 192 | if (child) { |
186 | goto listen_overflow; | 193 | child = inet_csk_complete_hashdance(sk, child, req, own_req); |
187 | 194 | goto out; | |
188 | return inet_csk_complete_hashdance(sk, child, req, own_req); | 195 | } |
189 | 196 | ||
190 | listen_overflow: | ||
191 | dccp_pr_debug("listen_overflow!\n"); | ||
192 | DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; | 197 | DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; |
193 | drop: | 198 | drop: |
194 | if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET) | 199 | if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET) |
195 | req->rsk_ops->send_reset(sk, skb); | 200 | req->rsk_ops->send_reset(sk, skb); |
196 | 201 | ||
197 | inet_csk_reqsk_queue_drop(sk, req); | 202 | inet_csk_reqsk_queue_drop(sk, req); |
198 | return NULL; | 203 | out: |
204 | spin_unlock_bh(&dreq->dreq_lock); | ||
205 | return child; | ||
199 | } | 206 | } |
200 | 207 | ||
201 | EXPORT_SYMBOL_GPL(dccp_check_req); | 208 | EXPORT_SYMBOL_GPL(dccp_check_req); |
@@ -246,6 +253,7 @@ int dccp_reqsk_init(struct request_sock *req, | |||
246 | { | 253 | { |
247 | struct dccp_request_sock *dreq = dccp_rsk(req); | 254 | struct dccp_request_sock *dreq = dccp_rsk(req); |
248 | 255 | ||
256 | spin_lock_init(&dreq->dreq_lock); | ||
249 | inet_rsk(req)->ir_rmt_port = dccp_hdr(skb)->dccph_sport; | 257 | inet_rsk(req)->ir_rmt_port = dccp_hdr(skb)->dccph_sport; |
250 | inet_rsk(req)->ir_num = ntohs(dccp_hdr(skb)->dccph_dport); | 258 | inet_rsk(req)->ir_num = ntohs(dccp_hdr(skb)->dccph_dport); |
251 | inet_rsk(req)->acked = 0; | 259 | inet_rsk(req)->acked = 0; |