summaryrefslogtreecommitdiff
path: root/net/dccp/ipv4.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/ipv4.c')
-rw-r--r--net/dccp/ipv4.c70
1 files changed, 34 insertions, 36 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 1f7161e05403..6310b8b19598 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -195,6 +195,32 @@ static void dccp_do_redirect(struct sk_buff *skb, struct sock *sk)
dst->ops->redirect(dst, sk, skb);
}
+void dccp_req_err(struct sock *sk, u64 seq)
+ {
+ struct request_sock *req = inet_reqsk(sk);
+ struct net *net = sock_net(sk);
+
+ /*
+ * ICMPs are not backlogged, hence we cannot get an established
+ * socket here.
+ */
+ WARN_ON(req->sk);
+
+ if (!between48(seq, dccp_rsk(req)->dreq_iss, dccp_rsk(req)->dreq_gss)) {
+ NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
+ } else {
+ /*
+ * Still in RESPOND, just remove it silently.
+ * There is no good way to pass the error to the newly
+ * created socket, and POSIX does not want network
+ * errors returned from accept().
+ */
+ inet_csk_reqsk_queue_drop(req->rsk_listener, req);
+ }
+ reqsk_put(req);
+}
+EXPORT_SYMBOL(dccp_req_err);
+
/*
* This routine is called by the ICMP module when it gets some sort of error
* condition. If err < 0 then the socket should be closed and the error
@@ -227,10 +253,11 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
return;
}
- sk = inet_lookup(net, &dccp_hashinfo,
- iph->daddr, dh->dccph_dport,
- iph->saddr, dh->dccph_sport, inet_iif(skb));
- if (sk == NULL) {
+ sk = __inet_lookup_established(net, &dccp_hashinfo,
+ iph->daddr, dh->dccph_dport,
+ iph->saddr, ntohs(dh->dccph_sport),
+ inet_iif(skb));
+ if (!sk) {
ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
return;
}
@@ -239,6 +266,9 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
inet_twsk_put(inet_twsk(sk));
return;
}
+ seq = dccp_hdr_seq(dh);
+ if (sk->sk_state == DCCP_NEW_SYN_RECV)
+ return dccp_req_err(sk, seq);
bh_lock_sock(sk);
/* If too many ICMPs get dropped on busy
@@ -251,7 +281,6 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
goto out;
dp = dccp_sk(sk);
- seq = dccp_hdr_seq(dh);
if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
!between48(seq, dp->dccps_awl, dp->dccps_awh)) {
NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
@@ -288,37 +317,6 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
}
switch (sk->sk_state) {
- struct request_sock *req;
- case DCCP_LISTEN:
- if (sock_owned_by_user(sk))
- goto out;
- req = inet_csk_search_req(sk, dh->dccph_dport,
- iph->daddr, iph->saddr);
- if (!req)
- goto out;
-
- /*
- * ICMPs are not backlogged, hence we cannot get an established
- * socket here.
- */
- WARN_ON(req->sk);
-
- if (!between48(seq, dccp_rsk(req)->dreq_iss,
- dccp_rsk(req)->dreq_gss)) {
- NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
- reqsk_put(req);
- goto out;
- }
- /*
- * Still in RESPOND, just remove it silently.
- * There is no good way to pass the error to the newly
- * created socket, and POSIX does not want network
- * errors returned from accept().
- */
- inet_csk_reqsk_queue_drop(sk, req);
- reqsk_put(req);
- goto out;
-
case DCCP_REQUESTING:
case DCCP_RESPOND:
if (!sock_owned_by_user(sk)) {