|
@@ -1674,6 +1674,43 @@ do_time_wait:
|
|
|
goto discard_it;
|
|
|
}
|
|
|
|
|
|
+static void tcp_v6_early_demux(struct sk_buff *skb)
|
|
|
+{
|
|
|
+ const struct ipv6hdr *hdr;
|
|
|
+ const struct tcphdr *th;
|
|
|
+ struct sock *sk;
|
|
|
+
|
|
|
+ if (skb->pkt_type != PACKET_HOST)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr)))
|
|
|
+ return;
|
|
|
+
|
|
|
+ hdr = ipv6_hdr(skb);
|
|
|
+ th = tcp_hdr(skb);
|
|
|
+
|
|
|
+ if (th->doff < sizeof(struct tcphdr) / 4)
|
|
|
+ return;
|
|
|
+
|
|
|
+ sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
|
|
|
+ &hdr->saddr, th->source,
|
|
|
+ &hdr->daddr, ntohs(th->dest),
|
|
|
+ inet6_iif(skb));
|
|
|
+ if (sk) {
|
|
|
+ skb->sk = sk;
|
|
|
+ skb->destructor = sock_edemux;
|
|
|
+ if (sk->sk_state != TCP_TIME_WAIT) {
|
|
|
+ struct dst_entry *dst = sk->sk_rx_dst;
|
|
|
+ struct inet_sock *icsk = inet_sk(sk);
|
|
|
+ if (dst)
|
|
|
+ dst = dst_check(dst, 0);
|
|
|
+ if (dst &&
|
|
|
+ icsk->rx_dst_ifindex == inet6_iif(skb))
|
|
|
+ skb_dst_set_noref(skb, dst);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static struct timewait_sock_ops tcp6_timewait_sock_ops = {
|
|
|
.twsk_obj_size = sizeof(struct tcp6_timewait_sock),
|
|
|
.twsk_unique = tcp_twsk_unique,
|
|
@@ -1984,6 +2021,7 @@ struct proto tcpv6_prot = {
|
|
|
};
|
|
|
|
|
|
static const struct inet6_protocol tcpv6_protocol = {
|
|
|
+ .early_demux = tcp_v6_early_demux,
|
|
|
.handler = tcp_v6_rcv,
|
|
|
.err_handler = tcp_v6_err,
|
|
|
.gso_send_check = tcp_v6_gso_send_check,
|