diff options
-rw-r--r-- | include/linux/dccp.h | 1 | ||||
-rw-r--r-- | net/dccp/minisocks.c | 24 |
2 files changed, 17 insertions, 8 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 61d042bbbf60..68449293c4b6 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -163,6 +163,7 @@ struct dccp_request_sock { | |||
163 | __u64 dreq_isr; | 163 | __u64 dreq_isr; |
164 | __u64 dreq_gsr; | 164 | __u64 dreq_gsr; |
165 | __be32 dreq_service; | 165 | __be32 dreq_service; |
166 | spinlock_t dreq_lock; | ||
166 | struct list_head dreq_featneg; | 167 | struct list_head dreq_featneg; |
167 | __u32 dreq_timestamp_echo; | 168 | __u32 dreq_timestamp_echo; |
168 | __u32 dreq_timestamp_time; | 169 | __u32 dreq_timestamp_time; |
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; |