]> git.karo-electronics.de Git - linux-beck.git/blobdiff - net/ipv6/tcp_ipv6.c
Merge git://git.skbuff.net/gitroot/yoshfuji/linux-2.6.14+advapi-fix/
[linux-beck.git] / net / ipv6 / tcp_ipv6.c
index 794734f1d230b3b5a5449eb013f4d0545bcb7871..62c0e5bd931c7aa458083b00e2d81850f8c1b4e0 100644 (file)
@@ -114,16 +114,9 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
                int low = sysctl_local_port_range[0];
                int high = sysctl_local_port_range[1];
                int remaining = (high - low) + 1;
-               int rover;
+               int rover = net_random() % (high - low) + low;
 
-               spin_lock(&tcp_hashinfo.portalloc_lock);
-               if (tcp_hashinfo.port_rover < low)
-                       rover = low;
-               else
-                       rover = tcp_hashinfo.port_rover;
-               do {    rover++;
-                       if (rover > high)
-                               rover = low;
+               do {
                        head = &tcp_hashinfo.bhash[inet_bhashfn(rover, tcp_hashinfo.bhash_size)];
                        spin_lock(&head->lock);
                        inet_bind_bucket_for_each(tb, node, &head->chain)
@@ -132,9 +125,9 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
                        break;
                next:
                        spin_unlock(&head->lock);
+                       if (++rover > high)
+                               rover = low;
                } while (--remaining > 0);
-               tcp_hashinfo.port_rover = rover;
-               spin_unlock(&tcp_hashinfo.portalloc_lock);
 
                /* Exhausted local port range during search?  It is not
                 * possible for us to be holding one of the bind hash
@@ -209,9 +202,11 @@ static __inline__ void __tcp_v6_hash(struct sock *sk)
                lock = &tcp_hashinfo.lhash_lock;
                inet_listen_wlock(&tcp_hashinfo);
        } else {
-               sk->sk_hashent = inet6_sk_ehashfn(sk, tcp_hashinfo.ehash_size);
-               list = &tcp_hashinfo.ehash[sk->sk_hashent].chain;
-               lock = &tcp_hashinfo.ehash[sk->sk_hashent].lock;
+               unsigned int hash;
+               sk->sk_hash = hash = inet6_sk_ehashfn(sk);
+               hash &= (tcp_hashinfo.ehash_size - 1);
+               list = &tcp_hashinfo.ehash[hash].chain;
+               lock = &tcp_hashinfo.ehash[hash].lock;
                write_lock(lock);
        }
 
@@ -322,13 +317,13 @@ static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
        const struct in6_addr *saddr = &np->daddr;
        const int dif = sk->sk_bound_dev_if;
        const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
-       const int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport,
-                                      tcp_hashinfo.ehash_size);
-       struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash];
+       unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport);
+       struct inet_ehash_bucket *head = inet_ehash_bucket(&tcp_hashinfo, hash);
        struct sock *sk2;
        const struct hlist_node *node;
        struct inet_timewait_sock *tw;
 
+       prefetch(head->chain.first);
        write_lock(&head->lock);
 
        /* Check TIME-WAIT sockets first. */
@@ -365,14 +360,14 @@ static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
 
        /* And established part... */
        sk_for_each(sk2, node, &head->chain) {
-               if (INET6_MATCH(sk2, saddr, daddr, ports, dif))
+               if (INET6_MATCH(sk2, hash, saddr, daddr, ports, dif))
                        goto not_unique;
        }
 
 unique:
        BUG_TRAP(sk_unhashed(sk));
        __sk_add_node(sk, &head->chain);
-       sk->sk_hashent = hash;
+       sk->sk_hash = hash;
        sock_prot_inc_use(sk->sk_prot);
        write_unlock(&head->lock);
 
@@ -632,10 +627,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        if (final_p)
                ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-       if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
-               dst_release(dst);
+       if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
                goto failure;
-       }
 
        if (saddr == NULL) {
                saddr = &fl.fl6_src;
@@ -849,7 +842,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
        if (dst == NULL) {
                opt = np->opt;
                if (opt == NULL &&
-                   np->rxopt.bits.srcrt == 2 &&
+                   np->rxopt.bits.osrcrt == 2 &&
                    treq->pktopts) {
                        struct sk_buff *pktopts = treq->pktopts;
                        struct inet6_skb_parm *rxopt = IP6CB(pktopts);
@@ -888,7 +881,6 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
        }
 
 done:
-       dst_release(dst);
         if (opt && opt != np->opt)
                sock_kfree_s(sk, opt, opt->tot_len);
        return err;
@@ -915,11 +907,10 @@ static int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
        struct inet6_skb_parm *opt = IP6CB(skb);
 
        if (np->rxopt.all) {
-               if ((opt->hop && np->rxopt.bits.hopopts) ||
-                   ((IPV6_FLOWINFO_MASK&*(u32*)skb->nh.raw) &&
-                    np->rxopt.bits.rxflow) ||
-                   (opt->srcrt && np->rxopt.bits.srcrt) ||
-                   ((opt->dst1 || opt->dst0) && np->rxopt.bits.dstopts))
+               if ((opt->hop && (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) ||
+                   ((IPV6_FLOWINFO_MASK & *(u32*)skb->nh.raw) && np->rxopt.bits.rxflow) ||
+                   (opt->srcrt && (np->rxopt.bits.srcrt || np->rxopt.bits.osrcrt)) ||
+                   ((opt->dst1 || opt->dst0) && (np->rxopt.bits.dstopts || np->rxopt.bits.odstopts)))
                        return 1;
        }
        return 0;
@@ -1001,10 +992,8 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
        /* sk = NULL, but it is safe for now. RST socket required. */
        if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
 
-               if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
-                       dst_release(buff->dst);
+               if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0)
                        return;
-               }
 
                ip6_xmit(NULL, buff, &fl, NULL, 0);
                TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
@@ -1068,10 +1057,8 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
        fl.fl_ip_sport = t1->source;
 
        if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
-               if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
-                       dst_release(buff->dst);
+               if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0)
                        return;
-               }
                ip6_xmit(NULL, buff, &fl, NULL, 0);
                TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
                return;
@@ -1190,8 +1177,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        TCP_ECN_create_request(req, skb->h.th);
        treq->pktopts = NULL;
        if (ipv6_opt_accepted(sk, skb) ||
-           np->rxopt.bits.rxinfo ||
-           np->rxopt.bits.rxhlim) {
+           np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
+           np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
                atomic_inc(&skb->users);
                treq->pktopts = skb;
        }
@@ -1288,7 +1275,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        if (sk_acceptq_is_full(sk))
                goto out_overflow;
 
-       if (np->rxopt.bits.srcrt == 2 &&
+       if (np->rxopt.bits.osrcrt == 2 &&
            opt == NULL && treq->pktopts) {
                struct inet6_skb_parm *rxopt = IP6CB(treq->pktopts);
                if (rxopt->srcrt)
@@ -1414,20 +1401,18 @@ out:
 static int tcp_v6_checksum_init(struct sk_buff *skb)
 {
        if (skb->ip_summed == CHECKSUM_HW) {
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
                if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-                                 &skb->nh.ipv6h->daddr,skb->csum))
+                                 &skb->nh.ipv6h->daddr,skb->csum)) {
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
                        return 0;
-               LIMIT_NETDEBUG(KERN_DEBUG "hw tcp v6 csum failed\n");
+               }
        }
+
+       skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
+                                 &skb->nh.ipv6h->daddr, 0);
+
        if (skb->len <= 76) {
-               if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-                                &skb->nh.ipv6h->daddr,skb_checksum(skb, 0, skb->len, 0)))
-                       return -1;
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-       } else {
-               skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-                                         &skb->nh.ipv6h->daddr,0);
+               return __skb_checksum_complete(skb);
        }
        return 0;
 }
@@ -1544,9 +1529,9 @@ ipv6_pktoptions:
        tp = tcp_sk(sk);
        if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
            !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
-               if (np->rxopt.bits.rxinfo)
+               if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
                        np->mcast_oif = inet6_iif(opt_skb);
-               if (np->rxopt.bits.rxhlim)
+               if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
                        np->mcast_hops = opt_skb->nh.ipv6h->hop_limit;
                if (ipv6_opt_accepted(sk, opt_skb)) {
                        skb_set_owner_r(opt_skb, sk);
@@ -1588,7 +1573,7 @@ static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
                goto discard_it;
 
        if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
-            tcp_v6_checksum_init(skb) < 0))
+            tcp_v6_checksum_init(skb)))
                goto bad_packet;
 
        th = skb->h.th;
@@ -1734,7 +1719,6 @@ static int tcp_v6_rebuild_header(struct sock *sk)
 
                if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
                        sk->sk_err_soft = -err;
-                       dst_release(dst);
                        return err;
                }
 
@@ -1787,7 +1771,6 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
 
                if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
                        sk->sk_route_caps = 0;
-                       dst_release(dst);
                        return err;
                }