Merge remote-tracking branches 'asoc/fix/ad1980' and 'asoc/fix/isabelle' into asoc...
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / tcp_ipv6.c
index f67033b4bb6687621b7df4f9d3b691519c65f629..889079b2ea852f237dea495cc66a63c968037b6d 100644 (file)
@@ -164,12 +164,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
         *      connect() to INADDR_ANY means loopback (BSD'ism).
         */
 
-       if(ipv6_addr_any(&usin->sin6_addr))
+       if (ipv6_addr_any(&usin->sin6_addr))
                usin->sin6_addr.s6_addr[15] = 0x1;
 
        addr_type = ipv6_addr_type(&usin->sin6_addr);
 
-       if(addr_type & IPV6_ADDR_MULTICAST)
+       if (addr_type & IPV6_ADDR_MULTICAST)
                return -ENETUNREACH;
 
        if (addr_type&IPV6_ADDR_LINKLOCAL) {
@@ -257,7 +257,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-       dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
+       dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
        if (IS_ERR(dst)) {
                err = PTR_ERR(dst);
                goto failure;
@@ -336,7 +336,7 @@ static void tcp_v6_mtu_reduced(struct sock *sk)
 static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                u8 type, u8 code, int offset, __be32 info)
 {
-       const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data;
+       const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
        const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
        struct ipv6_pinfo *np;
        struct sock *sk;
@@ -397,6 +397,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                if (sk->sk_state == TCP_LISTEN)
                        goto out;
 
+               if (!ip6_sk_accept_pmtu(sk))
+                       goto out;
+
                tp->mtu_info = ntohl(info);
                if (!sock_owned_by_user(sk))
                        tcp_v6_mtu_reduced(sk);
@@ -466,7 +469,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
 {
        struct inet_request_sock *ireq = inet_rsk(req);
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct sk_buff * skb;
+       struct sk_buff *skb;
        int err = -ENOMEM;
 
        /* First, grab a route. */
@@ -480,6 +483,9 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
                                    &ireq->ir_v6_rmt_addr);
 
                fl6->daddr = ireq->ir_v6_rmt_addr;
+               if (np->repflow && (ireq->pktopts != NULL))
+                       fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
+
                skb_set_queue_mapping(skb, queue_mapping);
                err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
                err = net_xmit_eval(err);
@@ -721,7 +727,8 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
 
 static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
                                 u32 tsval, u32 tsecr,
-                                struct tcp_md5sig_key *key, int rst, u8 tclass)
+                                struct tcp_md5sig_key *key, int rst, u8 tclass,
+                                u32 label)
 {
        const struct tcphdr *th = tcp_hdr(skb);
        struct tcphdr *t1;
@@ -783,6 +790,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
        memset(&fl6, 0, sizeof(fl6));
        fl6.daddr = ipv6_hdr(skb)->saddr;
        fl6.saddr = ipv6_hdr(skb)->daddr;
+       fl6.flowlabel = label;
 
        buff->ip_summed = CHECKSUM_PARTIAL;
        buff->csum = 0;
@@ -800,7 +808,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
         * Underlying function will use this to retrieve the network
         * namespace
         */
-       dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
+       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);
@@ -868,7 +876,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
                ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
                          (th->doff << 2);
 
-       tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, key, 1, 0);
+       tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, key, 1, 0, 0);
 
 #ifdef CONFIG_TCP_MD5SIG
 release_sk1:
@@ -881,9 +889,11 @@ release_sk1:
 
 static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
                            u32 win, u32 tsval, u32 tsecr,
-                           struct tcp_md5sig_key *key, u8 tclass)
+                           struct tcp_md5sig_key *key, u8 tclass,
+                           u32 label)
 {
-       tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, key, 0, tclass);
+       tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, key, 0, tclass,
+                            label);
 }
 
 static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
@@ -895,7 +905,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
                        tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
                        tcp_time_stamp + tcptw->tw_ts_offset,
                        tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw),
-                       tw->tw_tclass);
+                       tw->tw_tclass, (tw->tw_flowlabel << 12));
 
        inet_twsk_put(tw);
 }
@@ -905,11 +915,12 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 {
        tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1,
                        req->rcv_wnd, tcp_time_stamp, req->ts_recent,
-                       tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0);
+                       tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
+                       0, 0);
 }
 
 
-static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
+static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
 {
        struct request_sock *req, **prev;
        const struct tcphdr *th = tcp_hdr(skb);
@@ -1010,7 +1021,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        if (!isn) {
                if (ipv6_opt_accepted(sk, skb) ||
                    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
-                   np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
+                   np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim ||
+                   np->repflow) {
                        atomic_inc(&skb->users);
                        ireq->pktopts = skb;
                }
@@ -1082,9 +1094,9 @@ drop:
        return 0; /* don't send reset */
 }
 
-static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
-                                         struct request_sock *req,
-                                         struct dst_entry *dst)
+static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+                                        struct request_sock *req,
+                                        struct dst_entry *dst)
 {
        struct inet_request_sock *ireq;
        struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
@@ -1134,7 +1146,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                newnp->opt         = NULL;
                newnp->mcast_oif   = inet6_iif(skb);
                newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit;
-               newnp->rcv_tclass  = ipv6_get_dsfield(ipv6_hdr(skb));
+               newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
+               if (np->repflow)
+                       newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb));
 
                /*
                 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
@@ -1214,7 +1228,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newnp->opt        = NULL;
        newnp->mcast_oif  = inet6_iif(skb);
        newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
-       newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb));
+       newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
+       if (np->repflow)
+               newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb));
 
        /* Clone native IPv6 options from listening socket (if any)
 
@@ -1230,7 +1246,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
                                                     newnp->opt->opt_flen);
 
-       tcp_mtup_init(newsk);
        tcp_sync_mss(newsk, dst_mtu(dst));
        newtp->advmss = dst_metric_advmss(dst);
        if (tcp_sk(sk)->rx_opt.user_mss &&
@@ -1379,7 +1394,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                 * otherwise we just shortcircuit this and continue with
                 * the new socket..
                 */
-               if(nsk != sk) {
+               if (nsk != sk) {
                        sock_rps_save_rxhash(nsk, skb);
                        if (tcp_child_process(sk, nsk, skb))
                                goto reset;
@@ -1424,8 +1439,10 @@ ipv6_pktoptions:
                        np->mcast_oif = inet6_iif(opt_skb);
                if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
                        np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
-               if (np->rxopt.bits.rxtclass)
-                       np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(opt_skb));
+               if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
+                       np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
+               if (np->repflow)
+                       np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
                if (ipv6_opt_accepted(sk, opt_skb)) {
                        skb_set_owner_r(opt_skb, sk);
                        opt_skb = xchg(&np->pktoptions, opt_skb);
@@ -1739,7 +1756,7 @@ static void get_openreq6(struct seq_file *seq,
                   dest->s6_addr32[2], dest->s6_addr32[3],
                   ntohs(inet_rsk(req)->ir_rmt_port),
                   TCP_SYN_RECV,
-                  0,0, /* could print option size, but that is af dependent. */
+                  0, 0, /* could print option size, but that is af dependent. */
                   1,   /* timers active (only the expire timer) */
                   jiffies_to_clock_t(ttd),
                   req->num_timeout,
@@ -1798,7 +1815,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
                   atomic_read(&sp->sk_refcnt), sp,
                   jiffies_to_clock_t(icsk->icsk_rto),
                   jiffies_to_clock_t(icsk->icsk_ack.ato),
-                  (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
+                  (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
                   tp->snd_cwnd,
                   tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh
                   );