]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv4/tcp_ipv4.c
[NETNS][IPV6] tcp6 - make proc per namespace
[linux-2.6-omap-h63xx.git] / net / ipv4 / tcp_ipv4.c
index 00156bf421ca092b3b5145c77a7bb51293eb87dd..744bc9d6cebc111c28e708ec536e6c068afa14c7 100644 (file)
@@ -552,7 +552,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
        if (th->rst)
                return;
 
-       if (((struct rtable *)skb->dst)->rt_type != RTN_LOCAL)
+       if (skb->rtable->rt_type != RTN_LOCAL)
                return;
 
        /* Swap the send and the receive. */
@@ -723,8 +723,8 @@ static void tcp_v4_reqsk_send_ack(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 request_sock *req,
-                             struct dst_entry *dst)
+static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
+                               struct dst_entry *dst)
 {
        const struct inet_request_sock *ireq = inet_rsk(req);
        int err = -1;
@@ -732,7 +732,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
 
        /* First, grab a route. */
        if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL)
-               goto out;
+               return -1;
 
        skb = tcp_make_synack(sk, dst, req);
 
@@ -751,11 +751,15 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
                err = net_xmit_eval(err);
        }
 
-out:
        dst_release(dst);
        return err;
 }
 
+static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req)
+{
+       return __tcp_v4_send_synack(sk, req, NULL);
+}
+
 /*
  *     IPv4 request_sock destructor.
  */
@@ -1258,8 +1262,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 #endif
 
        /* Never answer to SYNs send to broadcast or multicast */
-       if (((struct rtable *)skb->dst)->rt_flags &
-           (RTCF_BROADCAST | RTCF_MULTICAST))
+       if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
                goto drop;
 
        /* TW buckets are converted to open requests without
@@ -1351,8 +1354,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                            (s32)(peer->tcp_ts - req->ts_recent) >
                                                        TCP_PAWS_WINDOW) {
                                NET_INC_STATS_BH(LINUX_MIB_PAWSPASSIVEREJECTED);
-                               dst_release(dst);
-                               goto drop_and_free;
+                               goto drop_and_release;
                        }
                }
                /* Kill the following clause, if you dislike this way. */
@@ -1372,24 +1374,21 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                                       "request from %u.%u.%u.%u/%u\n",
                                       NIPQUAD(saddr),
                                       ntohs(tcp_hdr(skb)->source));
-                       dst_release(dst);
-                       goto drop_and_free;
+                       goto drop_and_release;
                }
 
                isn = tcp_v4_init_sequence(skb);
        }
        tcp_rsk(req)->snt_isn = isn;
 
-       if (tcp_v4_send_synack(sk, req, dst))
+       if (__tcp_v4_send_synack(sk, req, dst) || want_cookie)
                goto drop_and_free;
 
-       if (want_cookie) {
-               reqsk_free(req);
-       } else {
-               inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
-       }
+       inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
        return 0;
 
+drop_and_release:
+       dst_release(dst);
 drop_and_free:
        reqsk_free(req);
 drop:
@@ -1949,6 +1948,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
        struct hlist_node *node;
        struct sock *sk = cur;
        struct tcp_iter_state* st = seq->private;
+       struct net *net = st->net;
 
        if (!sk) {
                st->bucket = 0;
@@ -1965,7 +1965,8 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
                req = req->dl_next;
                while (1) {
                        while (req) {
-                               if (req->rsk_ops->family == st->family) {
+                               if (req->rsk_ops->family == st->family &&
+                                   req->sk->sk_net == net) {
                                        cur = req;
                                        goto out;
                                }
@@ -1989,7 +1990,7 @@ get_req:
        }
 get_sk:
        sk_for_each_from(sk, node) {
-               if (sk->sk_family == st->family) {
+               if (sk->sk_family == st->family && sk->sk_net == net) {
                        cur = sk;
                        goto out;
                }
@@ -2028,6 +2029,7 @@ static void *listening_get_idx(struct seq_file *seq, loff_t *pos)
 static void *established_get_first(struct seq_file *seq)
 {
        struct tcp_iter_state* st = seq->private;
+       struct net *net = st->net;
        void *rc = NULL;
 
        for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
@@ -2038,7 +2040,8 @@ static void *established_get_first(struct seq_file *seq)
 
                read_lock_bh(lock);
                sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
-                       if (sk->sk_family != st->family) {
+                       if (sk->sk_family != st->family ||
+                           sk->sk_net != net) {
                                continue;
                        }
                        rc = sk;
@@ -2047,7 +2050,8 @@ static void *established_get_first(struct seq_file *seq)
                st->state = TCP_SEQ_STATE_TIME_WAIT;
                inet_twsk_for_each(tw, node,
                                   &tcp_hashinfo.ehash[st->bucket].twchain) {
-                       if (tw->tw_family != st->family) {
+                       if (tw->tw_family != st->family &&
+                           tw->tw_net != net) {
                                continue;
                        }
                        rc = tw;
@@ -2066,6 +2070,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
        struct inet_timewait_sock *tw;
        struct hlist_node *node;
        struct tcp_iter_state* st = seq->private;
+       struct net *net = st->net;
 
        ++st->num;
 
@@ -2073,7 +2078,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
                tw = cur;
                tw = tw_next(tw);
 get_tw:
-               while (tw && tw->tw_family != st->family) {
+               while (tw && tw->tw_family != st->family && tw->tw_net != net) {
                        tw = tw_next(tw);
                }
                if (tw) {
@@ -2094,7 +2099,7 @@ get_tw:
                sk = sk_next(sk);
 
        sk_for_each_from(sk, node) {
-               if (sk->sk_family == st->family)
+               if (sk->sk_family == st->family && sk->sk_net == net)
                        goto found;
        }
 
@@ -2202,6 +2207,7 @@ static int tcp_seq_open(struct inode *inode, struct file *file)
        struct tcp_seq_afinfo *afinfo = PDE(inode)->data;
        struct seq_file *seq;
        struct tcp_iter_state *s;
+       struct net *net;
        int rc;
 
        if (unlikely(afinfo == NULL))
@@ -2210,25 +2216,44 @@ static int tcp_seq_open(struct inode *inode, struct file *file)
        s = kzalloc(sizeof(*s), GFP_KERNEL);
        if (!s)
                return -ENOMEM;
+
+       rc = -ENXIO;
+       net = get_proc_net(inode);
+       if (!net)
+               goto out_kfree;
+
        s->family               = afinfo->family;
        s->seq_ops.start        = tcp_seq_start;
        s->seq_ops.next         = tcp_seq_next;
        s->seq_ops.show         = afinfo->seq_show;
        s->seq_ops.stop         = tcp_seq_stop;
+       s->net                  = net;
 
        rc = seq_open(file, &s->seq_ops);
        if (rc)
-               goto out_kfree;
-       seq          = file->private_data;
+               goto out_put_net;
+       seq = file->private_data;
        seq->private = s;
 out:
        return rc;
+out_put_net:
+       put_net(net);
 out_kfree:
        kfree(s);
        goto out;
 }
 
-int tcp_proc_register(struct tcp_seq_afinfo *afinfo)
+static int tcp_seq_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq = file->private_data;
+       struct tcp_iter_state *s = seq->private;
+
+       put_net(s->net);
+       seq_release_private(inode, file);
+       return 0;
+}
+
+int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo)
 {
        int rc = 0;
        struct proc_dir_entry *p;
@@ -2239,9 +2264,9 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo)
        afinfo->seq_fops->open          = tcp_seq_open;
        afinfo->seq_fops->read          = seq_read;
        afinfo->seq_fops->llseek        = seq_lseek;
-       afinfo->seq_fops->release       = seq_release_private;
+       afinfo->seq_fops->release       = tcp_seq_release;
 
-       p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops);
+       p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops);
        if (p)
                p->data = afinfo;
        else
@@ -2249,11 +2274,11 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo)
        return rc;
 }
 
-void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo)
+void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
 {
        if (!afinfo)
                return;
-       proc_net_remove(&init_net, afinfo->name);
+       proc_net_remove(net, afinfo->name);
        memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
 }
 
@@ -2394,12 +2419,12 @@ static struct tcp_seq_afinfo tcp4_seq_afinfo = {
 
 int __init tcp4_proc_init(void)
 {
-       return tcp_proc_register(&tcp4_seq_afinfo);
+       return tcp_proc_register(&init_net, &tcp4_seq_afinfo);
 }
 
 void tcp4_proc_exit(void)
 {
-       tcp_proc_unregister(&tcp4_seq_afinfo);
+       tcp_proc_unregister(&init_net, &tcp4_seq_afinfo);
 }
 #endif /* CONFIG_PROC_FS */
 
@@ -2443,7 +2468,7 @@ struct proto tcp_prot = {
        REF_PROTO_INUSE(tcp)
 };
 
-void __init tcp_v4_init(struct net_proto_family *ops)
+void __init tcp_v4_init(void)
 {
        if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW,
                                     IPPROTO_TCP) < 0)