TCPCT part 1b: generate Responder Cookie secret
[safe/jmp/linux-2.6] / net / ipv6 / inet6_connection_sock.c
index 5c950cc..3516e6f 100644 (file)
@@ -33,6 +33,10 @@ int inet6_csk_bind_conflict(const struct sock *sk,
        const struct hlist_node *node;
 
        /* We must walk the whole port owner list in this case. -DaveM */
+       /*
+        * See comment in inet_csk_bind_conflict about sock lookup
+        * vs net namespaces issues.
+        */
        sk_for_each_bound(sk2, node, &tb->owners) {
                if (sk != sk2 &&
                    (!sk->sk_bound_dev_if ||
@@ -52,20 +56,20 @@ EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
 /*
  * request_sock (formerly open request) hash tables.
  */
-static u32 inet6_synq_hash(const struct in6_addr *raddr, const u16 rport,
+static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport,
                           const u32 rnd, const u16 synq_hsize)
 {
-       u32 a = raddr->s6_addr32[0];
-       u32 b = raddr->s6_addr32[1];
-       u32 c = raddr->s6_addr32[2];
+       u32 a = (__force u32)raddr->s6_addr32[0];
+       u32 b = (__force u32)raddr->s6_addr32[1];
+       u32 c = (__force u32)raddr->s6_addr32[2];
 
        a += JHASH_GOLDEN_RATIO;
        b += JHASH_GOLDEN_RATIO;
        c += rnd;
        __jhash_mix(a, b, c);
 
-       a += raddr->s6_addr32[3];
-       b += (u32)rport;
+       a += (__force u32)raddr->s6_addr32[3];
+       b += (__force u32)rport;
        __jhash_mix(a, b, c);
 
        return c & (synq_hsize - 1);
@@ -73,7 +77,7 @@ static u32 inet6_synq_hash(const struct in6_addr *raddr, const u16 rport,
 
 struct request_sock *inet6_csk_search_req(const struct sock *sk,
                                          struct request_sock ***prevp,
-                                         const __u16 rport,
+                                         const __be16 rport,
                                          const struct in6_addr *raddr,
                                          const struct in6_addr *laddr,
                                          const int iif)
@@ -94,7 +98,7 @@ struct request_sock *inet6_csk_search_req(const struct sock *sk,
                    ipv6_addr_equal(&treq->rmt_addr, raddr) &&
                    ipv6_addr_equal(&treq->loc_addr, laddr) &&
                    (!treq->iif || treq->iif == iif)) {
-                       BUG_TRAP(req->sk == NULL);
+                       WARN_ON(req->sk != NULL);
                        *prevp = prev;
                        return req;
                }
@@ -128,7 +132,7 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
 
        sin6->sin6_family = AF_INET6;
        ipv6_addr_copy(&sin6->sin6_addr, &np->daddr);
-       sin6->sin6_port = inet_sk(sk)->dport;
+       sin6->sin6_port = inet_sk(sk)->inet_dport;
        /* We do not store received flowlabel for TCP */
        sin6->sin6_flowinfo = 0;
        sin6->sin6_scope_id = 0;
@@ -139,6 +143,40 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
 
 EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
 
+static inline
+void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
+                          struct in6_addr *daddr, struct in6_addr *saddr)
+{
+       __ip6_dst_store(sk, dst, daddr, saddr);
+
+#ifdef CONFIG_XFRM
+       {
+               struct rt6_info *rt = (struct rt6_info  *)dst;
+               rt->rt6i_flow_cache_genid = atomic_read(&flow_cache_genid);
+       }
+#endif
+}
+
+static inline
+struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
+{
+       struct dst_entry *dst;
+
+       dst = __sk_dst_check(sk, cookie);
+
+#ifdef CONFIG_XFRM
+       if (dst) {
+               struct rt6_info *rt = (struct rt6_info *)dst;
+               if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) {
+                       __sk_dst_reset(sk);
+                       dst = NULL;
+               }
+       }
+#endif
+
+       return dst;
+}
+
 int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
 {
        struct sock *sk = skb->sk;
@@ -155,8 +193,10 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
        fl.fl6_flowlabel = np->flow_label;
        IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
        fl.oif = sk->sk_bound_dev_if;
-       fl.fl_ip_sport = inet->sport;
-       fl.fl_ip_dport = inet->dport;
+       fl.mark = sk->sk_mark;
+       fl.fl_ip_sport = inet->inet_sport;
+       fl.fl_ip_dport = inet->inet_dport;
+       security_sk_classify_flow(sk, &fl);
 
        if (np->opt && np->opt->srcrt) {
                struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
@@ -165,7 +205,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
                final_p = &final;
        }
 
-       dst = __sk_dst_check(sk, np->dst_cookie);
+       dst = __inet6_csk_dst_check(sk, np->dst_cookie);
 
        if (dst == NULL) {
                int err = ip6_dst_lookup(sk, &dst, &fl);
@@ -179,16 +219,16 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
                if (final_p)
                        ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-               if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+               if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) {
                        sk->sk_route_caps = 0;
                        kfree_skb(skb);
                        return err;
                }
 
-               ip6_dst_store(sk, dst, NULL);
+               __inet6_csk_dst_store(sk, dst, NULL, NULL);
        }
 
-       skb->dst = dst_clone(dst);
+       skb_dst_set(skb, dst_clone(dst));
 
        /* Restore final destination back after routing done */
        ipv6_addr_copy(&fl.fl6_dst, &np->daddr);