aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/tcp.h1
-rw-r--r--net/ipv4/tcp_ipv4.c69
2 files changed, 35 insertions, 35 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 1876262afd59..fe60e00e1919 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -447,6 +447,7 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
447 447
448void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); 448void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb);
449void tcp_v4_mtu_reduced(struct sock *sk); 449void tcp_v4_mtu_reduced(struct sock *sk);
450void tcp_req_err(struct sock *sk, u32 seq);
450int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); 451int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
451struct sock *tcp_create_openreq_child(struct sock *sk, 452struct sock *tcp_create_openreq_child(struct sock *sk,
452 struct request_sock *req, 453 struct request_sock *req,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 8028ad5920a4..a57615062b66 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -310,6 +310,34 @@ static void do_redirect(struct sk_buff *skb, struct sock *sk)
310 dst->ops->redirect(dst, sk, skb); 310 dst->ops->redirect(dst, sk, skb);
311} 311}
312 312
313
314/* handle ICMP messages on TCP_NEW_SYN_RECV request sockets */
315void tcp_req_err(struct sock *sk, u32 seq)
316{
317 struct request_sock *req = inet_reqsk(sk);
318 struct net *net = sock_net(sk);
319
320 /* ICMPs are not backlogged, hence we cannot get
321 * an established socket here.
322 */
323 WARN_ON(req->sk);
324
325 if (seq != tcp_rsk(req)->snt_isn) {
326 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
327 } else {
328 /*
329 * Still in SYN_RECV, just remove it silently.
330 * There is no good way to pass the error to the newly
331 * created socket, and POSIX does not want network
332 * errors returned from accept().
333 */
334 inet_csk_reqsk_queue_drop(req->rsk_listener, req);
335 NET_INC_STATS_BH(net, LINUX_MIB_LISTENDROPS);
336 }
337 reqsk_put(req);
338}
339EXPORT_SYMBOL(tcp_req_err);
340
313/* 341/*
314 * This routine is called by the ICMP module when it gets some 342 * This routine is called by the ICMP module when it gets some
315 * sort of error condition. If err < 0 then the socket should 343 * sort of error condition. If err < 0 then the socket should
@@ -343,8 +371,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
343 int err; 371 int err;
344 struct net *net = dev_net(icmp_skb->dev); 372 struct net *net = dev_net(icmp_skb->dev);
345 373
346 sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest, 374 sk = __inet_lookup_established(net, &tcp_hashinfo, iph->daddr,
347 iph->saddr, th->source, inet_iif(icmp_skb)); 375 th->dest, iph->saddr, ntohs(th->source),
376 inet_iif(icmp_skb));
348 if (!sk) { 377 if (!sk) {
349 ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); 378 ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
350 return; 379 return;
@@ -353,6 +382,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
353 inet_twsk_put(inet_twsk(sk)); 382 inet_twsk_put(inet_twsk(sk));
354 return; 383 return;
355 } 384 }
385 seq = ntohl(th->seq);
386 if (sk->sk_state == TCP_NEW_SYN_RECV)
387 return tcp_req_err(sk, seq);
356 388
357 bh_lock_sock(sk); 389 bh_lock_sock(sk);
358 /* If too many ICMPs get dropped on busy 390 /* If too many ICMPs get dropped on busy
@@ -374,7 +406,6 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
374 406
375 icsk = inet_csk(sk); 407 icsk = inet_csk(sk);
376 tp = tcp_sk(sk); 408 tp = tcp_sk(sk);
377 seq = ntohl(th->seq);
378 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ 409 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */
379 fastopen = tp->fastopen_rsk; 410 fastopen = tp->fastopen_rsk;
380 snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; 411 snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una;
@@ -458,38 +489,6 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
458 } 489 }
459 490
460 switch (sk->sk_state) { 491 switch (sk->sk_state) {
461 struct request_sock *req;
462 case TCP_LISTEN:
463 if (sock_owned_by_user(sk))
464 goto out;
465
466 req = inet_csk_search_req(sk, th->dest,
467 iph->daddr, iph->saddr);
468 if (!req)
469 goto out;
470
471 /* ICMPs are not backlogged, hence we cannot get
472 an established socket here.
473 */
474 WARN_ON(req->sk);
475
476 if (seq != tcp_rsk(req)->snt_isn) {
477 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
478 reqsk_put(req);
479 goto out;
480 }
481
482 /*
483 * Still in SYN_RECV, just remove it silently.
484 * There is no good way to pass the error to the newly
485 * created socket, and POSIX does not want network
486 * errors returned from accept().
487 */
488 inet_csk_reqsk_queue_drop(sk, req);
489 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
490 reqsk_put(req);
491 goto out;
492
493 case TCP_SYN_SENT: 492 case TCP_SYN_SENT:
494 case TCP_SYN_RECV: 493 case TCP_SYN_RECV:
495 /* Only in fast or simultaneous open. If a fast open socket is 494 /* Only in fast or simultaneous open. If a fast open socket is