net: l3mdev: remove redundant calls
[cascardo/linux.git] / net / ipv6 / tcp_ipv6.c
index 2255d2b..54cf719 100644 (file)
@@ -443,6 +443,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
 {
        struct inet_request_sock *ireq = inet_rsk(req);
        struct ipv6_pinfo *np = inet6_sk(sk);
+       struct ipv6_txoptions *opt;
        struct flowi6 *fl6 = &fl->u.ip6;
        struct sk_buff *skb;
        int err = -ENOMEM;
@@ -463,8 +464,10 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
                        fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
 
                rcu_read_lock();
-               err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
-                              np->tclass);
+               opt = ireq->ipv6_opt;
+               if (!opt)
+                       opt = rcu_dereference(np->opt);
+               err = ip6_xmit(sk, skb, fl6, opt, np->tclass);
                rcu_read_unlock();
                err = net_xmit_eval(err);
        }
@@ -476,6 +479,7 @@ done:
 
 static void tcp_v6_reqsk_destructor(struct request_sock *req)
 {
+       kfree(inet_rsk(req)->ipv6_opt);
        kfree_skb(inet_rsk(req)->pktopts);
 }
 
@@ -526,26 +530,33 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval,
                              AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
 }
 
-static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
-                                       const struct in6_addr *daddr,
-                                       const struct in6_addr *saddr, int nbytes)
+static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,
+                                  const struct in6_addr *daddr,
+                                  const struct in6_addr *saddr,
+                                  const struct tcphdr *th, int nbytes)
 {
        struct tcp6_pseudohdr *bp;
        struct scatterlist sg;
+       struct tcphdr *_th;
 
-       bp = &hp->md5_blk.ip6;
+       bp = hp->scratch;
        /* 1. TCP pseudo-header (RFC2460) */
        bp->saddr = *saddr;
        bp->daddr = *daddr;
        bp->protocol = cpu_to_be32(IPPROTO_TCP);
        bp->len = cpu_to_be32(nbytes);
 
-       sg_init_one(&sg, bp, sizeof(*bp));
-       ahash_request_set_crypt(hp->md5_req, &sg, NULL, sizeof(*bp));
+       _th = (struct tcphdr *)(bp + 1);
+       memcpy(_th, th, sizeof(*th));
+       _th->check = 0;
+
+       sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
+       ahash_request_set_crypt(hp->md5_req, &sg, NULL,
+                               sizeof(*bp) + sizeof(*th));
        return crypto_ahash_update(hp->md5_req);
 }
 
-static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
+static int tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
                               const struct in6_addr *daddr, struct in6_addr *saddr,
                               const struct tcphdr *th)
 {
@@ -559,9 +570,7 @@ static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
 
        if (crypto_ahash_init(req))
                goto clear_hash;
-       if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
-               goto clear_hash;
-       if (tcp_md5_hash_header(hp, th))
+       if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
                goto clear_hash;
        if (tcp_md5_hash_key(hp, key))
                goto clear_hash;
@@ -606,9 +615,7 @@ static int tcp_v6_md5_hash_skb(char *md5_hash,
        if (crypto_ahash_init(req))
                goto clear_hash;
 
-       if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
-               goto clear_hash;
-       if (tcp_md5_hash_header(hp, th))
+       if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, skb->len))
                goto clear_hash;
        if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
                goto clear_hash;
@@ -664,6 +671,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),
@@ -810,12 +818,8 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
        fl6.flowi6_proto = IPPROTO_TCP;
        if (rt6_need_strict(&fl6.daddr) && !oif)
                fl6.flowi6_oif = tcp_v6_iif(skb);
-       else {
-               if (!oif && netif_index_is_l3_master(net, skb->skb_iif))
-                       oif = skb->skb_iif;
-
-               fl6.flowi6_oif = oif;
-       }
+       else
+               fl6.flowi6_oif = oif ? : skb->skb_iif;
 
        fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark);
        fl6.fl6_dport = t1->dest;
@@ -937,9 +941,15 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
        /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
         * sk->sk_state == TCP_SYN_RECV -> for Fast Open.
         */
+       /* RFC 7323 2.3
+        * The window field (SEG.WND) of every outgoing segment, with the
+        * exception of <SYN> segments, MUST be right-shifted by
+        * Rcv.Wind.Shift bits:
+        */
        tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ?
                        tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
-                       tcp_rsk(req)->rcv_nxt, req->rsk_rcv_wnd,
+                       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_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
                        0, 0);
@@ -1109,7 +1119,9 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
           but we make one more one thing there: reattach optmem
           to newsk.
         */
-       opt = rcu_dereference(np->opt);
+       opt = ireq->ipv6_opt;
+       if (!opt)
+               opt = rcu_dereference(np->opt);
        if (opt) {
                opt = ipv6_dup_options(newsk, opt);
                RCU_INIT_POINTER(newnp->opt, opt);
@@ -1400,6 +1412,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;
                }
@@ -1456,10 +1469,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);
@@ -1853,17 +1863,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,
@@ -1905,7 +1904,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,
 };