diff options
-rw-r--r-- | include/net/tcp.h | 1 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 69 |
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 | ||
448 | void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); | 448 | void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); |
449 | void tcp_v4_mtu_reduced(struct sock *sk); | 449 | void tcp_v4_mtu_reduced(struct sock *sk); |
450 | void tcp_req_err(struct sock *sk, u32 seq); | ||
450 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); | 451 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); |
451 | struct sock *tcp_create_openreq_child(struct sock *sk, | 452 | struct 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 */ | ||
315 | void 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 | } | ||
339 | EXPORT_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 |