diff options
| -rw-r--r-- | include/net/inet6_hashtables.h | 13 | ||||
| -rw-r--r-- | include/net/protocol.h | 2 | ||||
| -rw-r--r-- | net/ipv4/ip_input.c | 1 | ||||
| -rw-r--r-- | net/ipv6/ip6_input.c | 13 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 38 |
5 files changed, 59 insertions, 8 deletions
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index 00cbb4384c79..9e34c877a770 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h | |||
| @@ -96,14 +96,15 @@ static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo, | |||
| 96 | const __be16 sport, | 96 | const __be16 sport, |
| 97 | const __be16 dport) | 97 | const __be16 dport) |
| 98 | { | 98 | { |
| 99 | struct sock *sk; | 99 | struct sock *sk = skb_steal_sock(skb); |
| 100 | 100 | ||
| 101 | if (unlikely(sk = skb_steal_sock(skb))) | 101 | if (sk) |
| 102 | return sk; | 102 | return sk; |
| 103 | else return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, | 103 | |
| 104 | &ipv6_hdr(skb)->saddr, sport, | 104 | return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, |
| 105 | &ipv6_hdr(skb)->daddr, ntohs(dport), | 105 | &ipv6_hdr(skb)->saddr, sport, |
| 106 | inet6_iif(skb)); | 106 | &ipv6_hdr(skb)->daddr, ntohs(dport), |
| 107 | inet6_iif(skb)); | ||
| 107 | } | 108 | } |
| 108 | 109 | ||
| 109 | extern struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, | 110 | extern struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, |
diff --git a/include/net/protocol.h b/include/net/protocol.h index 057f2d315567..929528c73fe8 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h | |||
| @@ -52,6 +52,8 @@ struct net_protocol { | |||
| 52 | 52 | ||
| 53 | #if IS_ENABLED(CONFIG_IPV6) | 53 | #if IS_ENABLED(CONFIG_IPV6) |
| 54 | struct inet6_protocol { | 54 | struct inet6_protocol { |
| 55 | void (*early_demux)(struct sk_buff *skb); | ||
| 56 | |||
| 55 | int (*handler)(struct sk_buff *skb); | 57 | int (*handler)(struct sk_buff *skb); |
| 56 | 58 | ||
| 57 | void (*err_handler)(struct sk_buff *skb, | 59 | void (*err_handler)(struct sk_buff *skb, |
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index bda8cac2ae91..981ff1eef28c 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c | |||
| @@ -314,6 +314,7 @@ drop: | |||
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | int sysctl_ip_early_demux __read_mostly = 1; | 316 | int sysctl_ip_early_demux __read_mostly = 1; |
| 317 | EXPORT_SYMBOL(sysctl_ip_early_demux); | ||
| 317 | 318 | ||
| 318 | static int ip_rcv_finish(struct sk_buff *skb) | 319 | static int ip_rcv_finish(struct sk_buff *skb) |
| 319 | { | 320 | { |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 5ab923e51af3..47975e363fcd 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
| @@ -47,9 +47,18 @@ | |||
| 47 | 47 | ||
| 48 | 48 | ||
| 49 | 49 | ||
| 50 | inline int ip6_rcv_finish( struct sk_buff *skb) | 50 | int ip6_rcv_finish(struct sk_buff *skb) |
| 51 | { | 51 | { |
| 52 | if (skb_dst(skb) == NULL) | 52 | if (sysctl_ip_early_demux && !skb_dst(skb)) { |
| 53 | const struct inet6_protocol *ipprot; | ||
| 54 | |||
| 55 | rcu_read_lock(); | ||
| 56 | ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]); | ||
| 57 | if (ipprot && ipprot->early_demux) | ||
| 58 | ipprot->early_demux(skb); | ||
| 59 | rcu_read_unlock(); | ||
| 60 | } | ||
| 61 | if (!skb_dst(skb)) | ||
| 53 | ip6_route_input(skb); | 62 | ip6_route_input(skb); |
| 54 | 63 | ||
| 55 | return dst_input(skb); | 64 | return dst_input(skb); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f49476e2d884..221224e72507 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -1674,6 +1674,43 @@ do_time_wait: | |||
| 1674 | goto discard_it; | 1674 | goto discard_it; |
| 1675 | } | 1675 | } |
| 1676 | 1676 | ||
| 1677 | static void tcp_v6_early_demux(struct sk_buff *skb) | ||
| 1678 | { | ||
| 1679 | const struct ipv6hdr *hdr; | ||
| 1680 | const struct tcphdr *th; | ||
| 1681 | struct sock *sk; | ||
| 1682 | |||
| 1683 | if (skb->pkt_type != PACKET_HOST) | ||
| 1684 | return; | ||
| 1685 | |||
| 1686 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr))) | ||
| 1687 | return; | ||
| 1688 | |||
| 1689 | hdr = ipv6_hdr(skb); | ||
| 1690 | th = tcp_hdr(skb); | ||
| 1691 | |||
| 1692 | if (th->doff < sizeof(struct tcphdr) / 4) | ||
| 1693 | return; | ||
| 1694 | |||
| 1695 | sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo, | ||
| 1696 | &hdr->saddr, th->source, | ||
| 1697 | &hdr->daddr, ntohs(th->dest), | ||
| 1698 | inet6_iif(skb)); | ||
| 1699 | if (sk) { | ||
| 1700 | skb->sk = sk; | ||
| 1701 | skb->destructor = sock_edemux; | ||
| 1702 | if (sk->sk_state != TCP_TIME_WAIT) { | ||
| 1703 | struct dst_entry *dst = sk->sk_rx_dst; | ||
| 1704 | struct inet_sock *icsk = inet_sk(sk); | ||
| 1705 | if (dst) | ||
| 1706 | dst = dst_check(dst, 0); | ||
| 1707 | if (dst && | ||
| 1708 | icsk->rx_dst_ifindex == inet6_iif(skb)) | ||
| 1709 | skb_dst_set_noref(skb, dst); | ||
| 1710 | } | ||
| 1711 | } | ||
| 1712 | } | ||
| 1713 | |||
| 1677 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { | 1714 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { |
| 1678 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | 1715 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), |
| 1679 | .twsk_unique = tcp_twsk_unique, | 1716 | .twsk_unique = tcp_twsk_unique, |
| @@ -1984,6 +2021,7 @@ struct proto tcpv6_prot = { | |||
| 1984 | }; | 2021 | }; |
| 1985 | 2022 | ||
| 1986 | static const struct inet6_protocol tcpv6_protocol = { | 2023 | static const struct inet6_protocol tcpv6_protocol = { |
| 2024 | .early_demux = tcp_v6_early_demux, | ||
| 1987 | .handler = tcp_v6_rcv, | 2025 | .handler = tcp_v6_rcv, |
| 1988 | .err_handler = tcp_v6_err, | 2026 | .err_handler = tcp_v6_err, |
| 1989 | .gso_send_check = tcp_v6_gso_send_check, | 2027 | .gso_send_check = tcp_v6_gso_send_check, |
