]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - net/ipv6/tcp_ipv6.c
Merge tag 'dmaengine-fix-4.10-rc7' of git://git.infradead.org/users/vkoul/slave-dma
[mirror_ubuntu-zesty-kernel.git] / net / ipv6 / tcp_ipv6.c
index 94f4f89d73e791ba2ae7bdc7e7ac5bd7bc66a8d4..cb8929681dc7597eebcc46026e4b6548f4bedadb 100644 (file)
@@ -101,12 +101,12 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
        }
 }
 
-static __u32 tcp_v6_init_sequence(const struct sk_buff *skb)
+static u32 tcp_v6_init_sequence(const struct sk_buff *skb, u32 *tsoff)
 {
        return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
                                            ipv6_hdr(skb)->saddr.s6_addr32,
                                            tcp_hdr(skb)->dest,
-                                           tcp_hdr(skb)->source);
+                                           tcp_hdr(skb)->source, tsoff);
 }
 
 static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
@@ -233,6 +233,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        fl6.flowi6_mark = sk->sk_mark;
        fl6.fl6_dport = usin->sin6_port;
        fl6.fl6_sport = inet->inet_sport;
+       fl6.flowi6_uid = sk->sk_uid;
 
        opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
        final_p = fl6_update_dst(&fl6, opt, &final);
@@ -282,7 +283,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
                                                             sk->sk_v6_daddr.s6_addr32,
                                                             inet->inet_sport,
-                                                            inet->inet_dport);
+                                                            inet->inet_dport,
+                                                            &tp->tsoffset);
 
        err = tcp_connect(sk);
        if (err)
@@ -397,7 +399,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                if (!sock_owned_by_user(sk))
                        tcp_v6_mtu_reduced(sk);
                else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED,
-                                          &tp->tsq_flags))
+                                          &sk->sk_tsq_flags))
                        sock_hold(sk);
                goto out;
        }
@@ -467,7 +469,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
                opt = ireq->ipv6_opt;
                if (!opt)
                        opt = rcu_dereference(np->opt);
-               err = ip6_xmit(sk, skb, fl6, opt, np->tclass);
+               err = ip6_xmit(sk, skb, fl6, sk->sk_mark, opt, np->tclass);
                rcu_read_unlock();
                err = net_xmit_eval(err);
        }
@@ -671,6 +673,7 @@ static bool tcp_v6_inbound_md5_hash(const struct sock *sk,
                                      NULL, skb);
 
        if (genhash || memcmp(hash_location, newhash, 16) != 0) {
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE);
                net_info_ratelimited("MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n",
                                     genhash ? "failed" : "mismatch",
                                     &ip6h->saddr, ntohs(th->source),
@@ -827,6 +830,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
        fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark);
        fl6.fl6_dport = t1->dest;
        fl6.fl6_sport = t1->source;
+       fl6.flowi6_uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL);
        security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
 
        /* Pass a socket to ip6_dst_lookup either it is for RST
@@ -836,7 +840,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
        dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
        if (!IS_ERR(dst)) {
                skb_dst_set(buff, dst);
-               ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
+               ip6_xmit(ctl_sk, buff, &fl6, fl6.flowi6_mark, NULL, tclass);
                TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
                if (rst)
                        TCP_INC_STATS(net, TCP_MIB_OUTRSTS);
@@ -953,7 +957,8 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
                        tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
                        tcp_rsk(req)->rcv_nxt,
                        req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
-                       tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if,
+                       tcp_time_stamp + tcp_rsk(req)->ts_off,
+                       req->ts_recent, sk->sk_bound_dev_if,
                        tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
                        0, 0);
 }
@@ -1193,6 +1198,16 @@ out:
        return NULL;
 }
 
+static void tcp_v6_restore_cb(struct sk_buff *skb)
+{
+       /* We need to move header back to the beginning if xfrm6_policy_check()
+        * and tcp_v6_fill_cb() are going to be called again.
+        * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
+        */
+       memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
+               sizeof(struct inet6_skb_parm));
+}
+
 /* The socket must have it's spinlock held when we get
  * here, unless it is a TCP_LISTEN socket.
  *
@@ -1218,7 +1233,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
        if (skb->protocol == htons(ETH_P_IP))
                return tcp_v4_do_rcv(sk, skb);
 
-       if (sk_filter(sk, skb))
+       if (tcp_filter(sk, skb))
                goto discard;
 
        /*
@@ -1322,6 +1337,7 @@ ipv6_pktoptions:
                        np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
                if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) {
                        skb_set_owner_r(opt_skb, sk);
+                       tcp_v6_restore_cb(opt_skb);
                        opt_skb = xchg(&np->pktoptions, opt_skb);
                } else {
                        __kfree_skb(opt_skb);
@@ -1355,15 +1371,6 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,
        TCP_SKB_CB(skb)->sacked = 0;
 }
 
-static void tcp_v6_restore_cb(struct sk_buff *skb)
-{
-       /* We need to move header back to the beginning if xfrm6_policy_check()
-        * and tcp_v6_fill_cb() are going to be called again.
-        */
-       memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
-               sizeof(struct inet6_skb_parm));
-}
-
 static int tcp_v6_rcv(struct sk_buff *skb)
 {
        const struct tcphdr *th;
@@ -1415,6 +1422,7 @@ process:
                sk = req->rsk_listener;
                tcp_v6_fill_cb(skb, hdr, th);
                if (tcp_v6_inbound_md5_hash(sk, skb)) {
+                       sk_drops_add(sk, skb);
                        reqsk_put(req);
                        goto discard_it;
                }
@@ -1453,8 +1461,10 @@ process:
        if (tcp_v6_inbound_md5_hash(sk, skb))
                goto discard_and_relse;
 
-       if (sk_filter(sk, skb))
+       if (tcp_filter(sk, skb))
                goto discard_and_relse;
+       th = (const struct tcphdr *)skb->data;
+       hdr = ipv6_hdr(skb);
 
        skb->dev = NULL;
 
@@ -1471,10 +1481,7 @@ process:
        if (!sock_owned_by_user(sk)) {
                if (!tcp_prequeue(sk, skb))
                        ret = tcp_v6_do_rcv(sk, skb);
-       } else if (unlikely(sk_add_backlog(sk, skb,
-                                          sk->sk_rcvbuf + sk->sk_sndbuf))) {
-               bh_unlock_sock(sk);
-               __NET_INC_STATS(net, LINUX_MIB_TCPBACKLOGDROP);
+       } else if (tcp_add_backlog(sk, skb)) {
                goto discard_and_relse;
        }
        bh_unlock_sock(sk);
@@ -1868,17 +1875,6 @@ void tcp6_proc_exit(struct net *net)
 }
 #endif
 
-static void tcp_v6_clear_sk(struct sock *sk, int size)
-{
-       struct inet_sock *inet = inet_sk(sk);
-
-       /* we do not want to clear pinet6 field, because of RCU lookups */
-       sk_prot_clear_nulls(sk, offsetof(struct inet_sock, pinet6));
-
-       size -= offsetof(struct inet_sock, pinet6) + sizeof(inet->pinet6);
-       memset(&inet->pinet6 + 1, 0, size);
-}
-
 struct proto tcpv6_prot = {
        .name                   = "TCPv6",
        .owner                  = THIS_MODULE,
@@ -1920,7 +1916,6 @@ struct proto tcpv6_prot = {
        .compat_setsockopt      = compat_tcp_setsockopt,
        .compat_getsockopt      = compat_tcp_getsockopt,
 #endif
-       .clear_sk               = tcp_v6_clear_sk,
        .diag_destroy           = tcp_abort,
 };