ipv6: Consolidate route lookup sequences.
[linux-2.6.git] / net / ipv6 / syncookies.c
index 676c80b..0b4cf35 100644 (file)
@@ -27,28 +27,17 @@ extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
 #define COOKIEBITS 24  /* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
-/*
- * This table has to be sorted and terminated with (__u16)-1.
- * XXX generate a better table.
- * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
- *
- * Taken directly from ipv4 implementation.
- * Should this list be modified for ipv6 use or is it close enough?
- * rfc 2460 8.3 suggests mss values 20 bytes less than ipv4 counterpart
- */
+/* Table must be sorted. */
 static __u16 const msstab[] = {
-       64 - 1,
-       256 - 1,
-       512 - 1,
-       536 - 1,
-       1024 - 1,
-       1440 - 1,
-       1460 - 1,
-       4312 - 1,
-       (__u16)-1
+       64,
+       512,
+       536,
+       1280 - 60,
+       1480 - 60,
+       1500 - 60,
+       4460 - 60,
+       9000 - 60,
 };
-/* The number doesn't include the -1 terminator */
-#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
 
 /*
  * This (misnamed) value is the age of syncookie which is permitted.
@@ -74,12 +63,13 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
        return child;
 }
 
-static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS],
+                     ipv6_cookie_scratch);
 
 static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr,
                       __be16 sport, __be16 dport, u32 count, int c)
 {
-       __u32 *tmp = __get_cpu_var(cookie_scratch);
+       __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch);
 
        /*
         * we have 320 bits of information to hash, copy in the remaining
@@ -131,11 +121,13 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
        int mssind;
        const __u16 mss = *mssp;
 
-       tcp_sk(sk)->last_synq_overflow = jiffies;
+       tcp_synq_overflow(sk);
+
+       for (mssind = ARRAY_SIZE(msstab) - 1; mssind ; mssind--)
+               if (mss >= msstab[mssind])
+                       break;
 
-       for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
-               ;
-       *mssp = msstab[mssind] + 1;
+       *mssp = msstab[mssind];
 
        NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
 
@@ -153,11 +145,13 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
                                            th->source, th->dest, seq,
                                            jiffies / (HZ * 60), COUNTER_TRIES);
 
-       return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+       return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
 }
 
 struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 {
+       struct tcp_options_received tcp_opt;
+       u8 *hash_location;
        struct inet_request_sock *ireq;
        struct inet6_request_sock *ireq6;
        struct tcp_request_sock *treq;
@@ -170,12 +164,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        int mss;
        struct dst_entry *dst;
        __u8 rcv_wscale;
-       struct tcp_options_received tcp_opt;
+       bool ecn_ok;
 
-       if (!sysctl_tcp_syncookies || !th->ack)
+       if (!sysctl_tcp_syncookies || !th->ack || th->rst)
                goto out;
 
-       if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) ||
+       if (tcp_synq_no_recent_overflow(sk) ||
                (mss = cookie_check(skb, cookie)) == 0) {
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED);
                goto out;
@@ -185,10 +179,10 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 
        /* check for timestamp cookie support */
        memset(&tcp_opt, 0, sizeof(tcp_opt));
-       tcp_parse_options(skb, &tcp_opt, 0);
+       tcp_parse_options(skb, &tcp_opt, &hash_location, 0);
 
-       if (tcp_opt.saw_tstamp)
-               cookie_check_timestamp(&tcp_opt);
+       if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
+               goto out;
 
        ret = NULL;
        req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
@@ -222,9 +216,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 
        req->expires = 0UL;
        req->retrans = 0;
-       ireq->ecn_ok            = 0;
+       ireq->ecn_ok            = ecn_ok;
        ireq->snd_wscale        = tcp_opt.snd_wscale;
-       ireq->rcv_wscale        = tcp_opt.rcv_wscale;
        ireq->sack_ok           = tcp_opt.sack_ok;
        ireq->wscale_ok         = tcp_opt.wscale_ok;
        ireq->tstamp_ok         = tcp_opt.saw_tstamp;
@@ -238,35 +231,29 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
         * me if there is a preferred way.
         */
        {
-               struct in6_addr *final_p = NULL, final;
+               struct in6_addr *final_p, final;
                struct flowi fl;
                memset(&fl, 0, sizeof(fl));
                fl.proto = IPPROTO_TCP;
                ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
-               if (np->opt && np->opt->srcrt) {
-                       struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
-                       ipv6_addr_copy(&final, &fl.fl6_dst);
-                       ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-                       final_p = &final;
-               }
+               final_p = fl6_update_dst(&fl, np->opt, &final);
                ipv6_addr_copy(&fl.fl6_src, &ireq6->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_sk(sk)->sport;
+               fl.fl_ip_sport = inet_sk(sk)->inet_sport;
                security_req_classify_flow(req, &fl);
-               if (ip6_dst_lookup(sk, &dst, &fl))
-                       goto out_free;
 
-               if (final_p)
-                       ipv6_addr_copy(&fl.fl6_dst, final_p);
-               if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+               dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
+               if (IS_ERR(dst))
                        goto out_free;
        }
 
        req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW);
        tcp_select_initial_window(tcp_full_space(sk), req->mss,
                                  &req->rcv_wnd, &req->window_clamp,
-                                 ireq->wscale_ok, &rcv_wscale);
+                                 ireq->wscale_ok, &rcv_wscale,
+                                 dst_metric(dst, RTAX_INITRWND));
 
        ireq->rcv_wscale = rcv_wscale;