- patches.suse/slab-handle-memoryless-nodes-v2a.patch: Refresh.
[linux-flexiantxendom0-3.2.10.git] / net / ipv6 / tcp_ipv6.c
index 30db570..35f2eac 100644 (file)
@@ -96,7 +96,7 @@ static void tcp_v6_hash(struct sock *sk)
                        return;
                }
                local_bh_disable();
-               __inet6_hash(sk);
+               __inet6_hash(sk, NULL);
                local_bh_enable();
        }
 }
@@ -226,10 +226,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 #endif
                        goto failure;
                } else {
-                       ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
-                                     inet->saddr);
-                       ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
-                                     inet->rcv_saddr);
+                       ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
+                       ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
+                                              &np->rcv_saddr);
                }
 
                return err;
@@ -243,8 +242,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        ipv6_addr_copy(&fl.fl6_src,
                       (saddr ? saddr : &np->saddr));
        fl.oif = sk->sk_bound_dev_if;
+       fl.mark = sk->sk_mark;
        fl.fl_ip_dport = usin->sin6_port;
-       fl.fl_ip_sport = inet->sport;
+       fl.fl_ip_sport = inet->inet_sport;
 
        if (np->opt && np->opt->srcrt) {
                struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
@@ -276,7 +276,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        /* set the source address */
        ipv6_addr_copy(&np->saddr, saddr);
-       inet->rcv_saddr = LOOPBACK4_IPV6;
+       inet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
        sk->sk_gso_type = SKB_GSO_TCPV6;
        __ip6_dst_store(sk, dst, NULL, NULL);
@@ -288,7 +288,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
-       inet->dport = usin->sin6_port;
+       inet->inet_dport = usin->sin6_port;
 
        tcp_set_state(sk, TCP_SYN_SENT);
        err = inet6_hash_connect(&tcp_death_row, sk);
@@ -298,8 +298,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        if (!tp->write_seq)
                tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
                                                             np->daddr.s6_addr32,
-                                                            inet->sport,
-                                                            inet->dport);
+                                                            inet->inet_sport,
+                                                            inet->inet_dport);
 
        err = tcp_connect(sk);
        if (err)
@@ -311,7 +311,7 @@ late_failure:
        tcp_set_state(sk, TCP_CLOSE);
        __sk_dst_reset(sk);
 failure:
-       inet->dport = 0;
+       inet->inet_dport = 0;
        sk->sk_route_caps = 0;
        return err;
 }
@@ -383,8 +383,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                        ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
                        ipv6_addr_copy(&fl.fl6_src, &np->saddr);
                        fl.oif = sk->sk_bound_dev_if;
-                       fl.fl_ip_dport = inet->dport;
-                       fl.fl_ip_sport = inet->sport;
+                       fl.mark = sk->sk_mark;
+                       fl.fl_ip_dport = inet->inet_dport;
+                       fl.fl_ip_sport = inet->inet_sport;
                        security_skb_classify_flow(skb, &fl);
 
                        if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
@@ -460,7 +461,8 @@ out:
 }
 
 
-static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
+static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
+                             struct request_values *rvp)
 {
        struct inet6_request_sock *treq = inet6_rsk(req);
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -477,6 +479,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
        ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
        fl.fl6_flowlabel = 0;
        fl.oif = treq->iif;
+       fl.mark = sk->sk_mark;
        fl.fl_ip_dport = inet_rsk(req)->rmt_port;
        fl.fl_ip_sport = inet_rsk(req)->loc_port;
        security_req_classify_flow(req, &fl);
@@ -497,7 +500,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
        if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
                goto done;
 
-       skb = tcp_make_synack(sk, dst, req);
+       skb = tcp_make_synack(sk, dst, req, rvp);
        if (skb) {
                struct tcphdr *th = tcp_hdr(skb);
 
@@ -1166,11 +1169,13 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
  */
 static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 {
+       struct tcp_extend_values tmp_ext;
+       struct tcp_options_received tmp_opt;
+       u8 *hash_location;
+       struct request_sock *req;
        struct inet6_request_sock *treq;
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct tcp_options_received tmp_opt;
        struct tcp_sock *tp = tcp_sk(sk);
-       struct request_sock *req = NULL;
        __u32 isn = TCP_SKB_CB(skb)->when;
 #ifdef CONFIG_SYN_COOKIES
        int want_cookie = 0;
@@ -1209,8 +1214,52 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        tcp_clear_options(&tmp_opt);
        tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
        tmp_opt.user_mss = tp->rx_opt.user_mss;
+       tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
+
+       if (tmp_opt.cookie_plus > 0 &&
+           tmp_opt.saw_tstamp &&
+           !tp->rx_opt.cookie_out_never &&
+           (sysctl_tcp_cookie_size > 0 ||
+            (tp->cookie_values != NULL &&
+             tp->cookie_values->cookie_desired > 0))) {
+               u8 *c;
+               u32 *d;
+               u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
+               int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
+
+               if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
+                       goto drop_and_free;
+
+               /* Secret recipe starts with IP addresses */
+               d = &ipv6_hdr(skb)->daddr.s6_addr32[0];
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               d = &ipv6_hdr(skb)->saddr.s6_addr32[0];
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+               *mess++ ^= *d++;
+
+               /* plus variable length Initiator Cookie */
+               c = (u8 *)mess;
+               while (l-- > 0)
+                       *c++ ^= *hash_location++;
 
-       tcp_parse_options(skb, &tmp_opt, 0);
+#ifdef CONFIG_SYN_COOKIES
+               want_cookie = 0;        /* not our kind of cookie */
+#endif
+               tmp_ext.cookie_out_never = 0; /* false */
+               tmp_ext.cookie_plus = tmp_opt.cookie_plus;
+       } else if (!tp->rx_opt.cookie_in_always) {
+               /* redundant indications, but ensure initialization. */
+               tmp_ext.cookie_out_never = 1; /* true */
+               tmp_ext.cookie_plus = 0;
+       } else {
+               goto drop_and_free;
+       }
+       tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
 
        if (want_cookie && !tmp_opt.saw_tstamp)
                tcp_clear_options(&tmp_opt);
@@ -1243,23 +1292,21 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 
                isn = tcp_v6_init_sequence(skb);
        }
-
        tcp_rsk(req)->snt_isn = isn;
 
        security_inet_conn_request(sk, skb, req);
 
-       if (tcp_v6_send_synack(sk, req))
-               goto drop;
+       if (tcp_v6_send_synack(sk, req,
+                              (struct request_values *)&tmp_ext) ||
+           want_cookie)
+               goto drop_and_free;
 
-       if (!want_cookie) {
-               inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
-               return 0;
-       }
+       inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
+       return 0;
 
+drop_and_free:
+       reqsk_free(req);
 drop:
-       if (req)
-               reqsk_free(req);
-
        return 0; /* don't send reset */
 }
 
@@ -1297,11 +1344,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
                memcpy(newnp, np, sizeof(struct ipv6_pinfo));
 
-               ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
-                             newinet->daddr);
+               ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
 
-               ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
-                             newinet->saddr);
+               ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
 
                ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
 
@@ -1352,6 +1397,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                }
                ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
                fl.oif = sk->sk_bound_dev_if;
+               fl.mark = sk->sk_mark;
                fl.fl_ip_dport = inet_rsk(req)->rmt_port;
                fl.fl_ip_sport = inet_rsk(req)->loc_port;
                security_req_classify_flow(req, &fl);
@@ -1438,7 +1484,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
        tcp_initialize_rcv_mss(newsk);
 
-       newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
+       newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
+       newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
 #ifdef CONFIG_TCP_MD5SIG
        /* Copy over the MD5 key from the original socket */
@@ -1455,7 +1502,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        }
 #endif
 
-       __inet6_hash(newsk);
+       __inet6_hash(newsk, NULL);
        __inet_inherit_port(sk, newsk);
 
        return newsk;
@@ -1855,7 +1902,7 @@ static int tcp_v6_init_sock(struct sock *sk)
         */
        tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
        tp->snd_cwnd_clamp = ~0;
-       tp->mss_cache = 536;
+       tp->mss_cache = TCP_MSS_DEFAULT;
 
        tp->reordering = sysctl_tcp_reordering;
 
@@ -1871,6 +1918,19 @@ static int tcp_v6_init_sock(struct sock *sk)
        tp->af_specific = &tcp_sock_ipv6_specific;
 #endif
 
+       /* TCP Cookie Transactions */
+       if (sysctl_tcp_cookie_size > 0) {
+               /* Default, cookies without s_data_payload. */
+               tp->cookie_values =
+                       kzalloc(sizeof(*tp->cookie_values),
+                               sk->sk_allocation);
+               if (tp->cookie_values != NULL)
+                       kref_init(&tp->cookie_values->kref);
+       }
+       /* Presumed zeroed, in order of appearance:
+        *      cookie_in_always, cookie_out_never,
+        *      s_data_constant, s_data_in, s_data_out
+        */
        sk->sk_sndbuf = sysctl_tcp_wmem[1];
        sk->sk_rcvbuf = sysctl_tcp_rmem[1];
 
@@ -1938,8 +1998,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
 
        dest  = &np->daddr;
        src   = &np->rcv_saddr;
-       destp = ntohs(inet->dport);
-       srcp  = ntohs(inet->sport);
+       destp = ntohs(inet->inet_dport);
+       srcp  = ntohs(inet->inet_sport);
 
        if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
                timer_active    = 1;
@@ -2116,7 +2176,6 @@ static struct inet_protosw tcpv6_protosw = {
        .protocol       =       IPPROTO_TCP,
        .prot           =       &tcpv6_prot,
        .ops            =       &inet6_stream_ops,
-       .capability     =       -1,
        .no_check       =       0,
        .flags          =       INET_PROTOSW_PERMANENT |
                                INET_PROTOSW_ICSK,
@@ -2131,12 +2190,17 @@ static int tcpv6_net_init(struct net *net)
 static void tcpv6_net_exit(struct net *net)
 {
        inet_ctl_sock_destroy(net->ipv6.tcp_sk);
-       inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET6);
+}
+
+static void tcpv6_net_exit_batch(struct list_head *net_exit_list)
+{
+       inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6);
 }
 
 static struct pernet_operations tcpv6_net_ops = {
-       .init = tcpv6_net_init,
-       .exit = tcpv6_net_exit,
+       .init       = tcpv6_net_init,
+       .exit       = tcpv6_net_exit,
+       .exit_batch = tcpv6_net_exit_batch,
 };
 
 int __init tcpv6_init(void)