netfilter: xtables: constify args in compat copying functions
[safe/jmp/linux-2.6] / net / ipv4 / tcp_ipv4.c
index a2bcac9..c3588b4 100644 (file)
@@ -742,9 +742,9 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
  *     This still operates on a request_sock only, not on a big
  *     socket.
  */
-static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
-                               struct request_sock *req,
-                               struct request_values *rvp)
+static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
+                             struct request_sock *req,
+                             struct request_values *rvp)
 {
        const struct inet_request_sock *ireq = inet_rsk(req);
        int err = -1;
@@ -775,10 +775,11 @@ static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
        return err;
 }
 
-static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
+static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req,
                              struct request_values *rvp)
 {
-       return __tcp_v4_send_synack(sk, NULL, req, rvp);
+       TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
+       return tcp_v4_send_synack(sk, NULL, req, rvp);
 }
 
 /*
@@ -1192,10 +1193,11 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
 struct request_sock_ops tcp_request_sock_ops __read_mostly = {
        .family         =       PF_INET,
        .obj_size       =       sizeof(struct tcp_request_sock),
-       .rtx_syn_ack    =       tcp_v4_send_synack,
+       .rtx_syn_ack    =       tcp_v4_rtx_synack,
        .send_ack       =       tcp_v4_reqsk_send_ack,
        .destructor     =       tcp_v4_reqsk_destructor,
        .send_reset     =       tcp_v4_send_reset,
+       .syn_ack_timeout =      tcp_syn_ack_timeout,
 };
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -1213,9 +1215,12 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
 
 int tcp_v4_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 inet_request_sock *ireq;
+       struct tcp_sock *tp = tcp_sk(sk);
        struct dst_entry *dst = NULL;
        __be32 saddr = ip_hdr(skb)->saddr;
        __be32 daddr = ip_hdr(skb)->daddr;
@@ -1259,31 +1264,61 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops;
 #endif
 
-       ireq = inet_rsk(req);
-       ireq->loc_addr = daddr;
-       ireq->rmt_addr = saddr;
-       ireq->no_srccheck = inet_sk(sk)->transparent;
-       ireq->opt = tcp_v4_save_options(sk, skb);
-
-       dst = inet_csk_route_req(sk, req);
-       if(!dst)
-               goto drop_and_free;
-
        tcp_clear_options(&tmp_opt);
        tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
-       tmp_opt.user_mss  = tcp_sk(sk)->rx_opt.user_mss;
+       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 *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_release;
+
+               /* Secret recipe starts with IP addresses */
+               *mess++ ^= daddr;
+               *mess++ ^= saddr;
 
-       tcp_parse_options(skb, &tmp_opt, 0, dst);
+               /* plus variable length Initiator Cookie */
+               c = (u8 *)mess;
+               while (l-- > 0)
+                       *c++ ^= *hash_location++;
+
+#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_release;
+       }
+       tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
 
        if (want_cookie && !tmp_opt.saw_tstamp)
                tcp_clear_options(&tmp_opt);
 
        tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
-
        tcp_openreq_init(req, &tmp_opt, skb);
 
+       ireq = inet_rsk(req);
+       ireq->loc_addr = daddr;
+       ireq->rmt_addr = saddr;
+       ireq->no_srccheck = inet_sk(sk)->transparent;
+       ireq->opt = tcp_v4_save_options(sk, skb);
+
        if (security_inet_conn_request(sk, skb, req))
-               goto drop_and_release;
+               goto drop_and_free;
 
        if (!want_cookie)
                TCP_ECN_create_request(req, tcp_hdr(skb));
@@ -1308,6 +1343,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                 */
                if (tmp_opt.saw_tstamp &&
                    tcp_death_row.sysctl_tw_recycle &&
+                   (dst = inet_csk_route_req(sk, req)) != NULL &&
                    (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
                    peer->v4daddr == saddr) {
                        if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
@@ -1339,7 +1375,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        }
        tcp_rsk(req)->snt_isn = isn;
 
-       if (__tcp_v4_send_synack(sk, dst, req, NULL) || want_cookie)
+       if (tcp_v4_send_synack(sk, dst, req,
+                              (struct request_values *)&tmp_ext) ||
+           want_cookie)
                goto drop_and_free;
 
        inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
@@ -1425,7 +1463,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        }
 #endif
 
-       __inet_hash_nolisten(newsk);
+       __inet_hash_nolisten(newsk, NULL);
        __inet_inherit_port(sk, newsk);
 
        return newsk;
@@ -1613,6 +1651,9 @@ int tcp_v4_rcv(struct sk_buff *skb)
        if (!sk)
                goto no_tcp_socket;
 
+       if (iph->ttl < inet_sk(sk)->min_ttl)
+               goto discard_and_relse;
+
 process:
        if (sk->sk_state == TCP_TIME_WAIT)
                goto do_time_wait;
@@ -2279,6 +2320,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
        __be32 src = inet->inet_rcv_saddr;
        __u16 destp = ntohs(inet->inet_dport);
        __u16 srcp = ntohs(inet->inet_sport);
+       int rx_queue;
 
        if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
                timer_active    = 1;
@@ -2294,12 +2336,19 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
                timer_expires = jiffies;
        }
 
+       if (sk->sk_state == TCP_LISTEN)
+               rx_queue = sk->sk_ack_backlog;
+       else
+               /*
+                * because we dont lock socket, we might find a transient negative value
+                */
+               rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
+
        seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
                        "%08X %5d %8d %lu %d %p %lu %lu %u %u %d%n",
                i, src, srcp, dest, destp, sk->sk_state,
                tp->write_seq - tp->snd_una,
-               sk->sk_state == TCP_LISTEN ? sk->sk_ack_backlog :
-                                            (tp->rcv_nxt - tp->copied_seq),
+               rx_queue,
                timer_active,
                jiffies_to_clock_t(timer_expires - jiffies),
                icsk->icsk_retransmits,
@@ -2381,12 +2430,12 @@ static struct tcp_seq_afinfo tcp4_seq_afinfo = {
        },
 };
 
-static int tcp4_proc_init_net(struct net *net)
+static int __net_init tcp4_proc_init_net(struct net *net)
 {
        return tcp_proc_register(net, &tcp4_seq_afinfo);
 }
 
-static void tcp4_proc_exit_net(struct net *net)
+static void __net_exit tcp4_proc_exit_net(struct net *net)
 {
        tcp_proc_unregister(net, &tcp4_seq_afinfo);
 }
@@ -2490,12 +2539,17 @@ static int __net_init tcp_sk_init(struct net *net)
 static void __net_exit tcp_sk_exit(struct net *net)
 {
        inet_ctl_sock_destroy(net->ipv4.tcp_sock);
-       inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET);
+}
+
+static void __net_exit tcp_sk_exit_batch(struct list_head *net_exit_list)
+{
+       inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET);
 }
 
 static struct pernet_operations __net_initdata tcp_sk_ops = {
-       .init = tcp_sk_init,
-       .exit = tcp_sk_exit,
+       .init      = tcp_sk_init,
+       .exit      = tcp_sk_exit,
+       .exit_batch = tcp_sk_exit_batch,
 };
 
 void __init tcp_v4_init(void)