summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/tcp.h28
-rw-r--r--net/ipv4/af_inet.c8
-rw-r--r--net/ipv4/tcp_ipv4.c159
-rw-r--r--net/netsyms.c2
4 files changed, 119 insertions, 78 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 080e2f0d06f0..158ee68198b4 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -35,6 +35,7 @@
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
#include <linux/ipv6.h>
#endif
+#include <linux/seq_file.h>
/* This is for all connections with a full identity, no wildcards.
* New scheme, half the table is for TIME_WAIT, the other half is
@@ -1889,4 +1890,31 @@ static inline void tcp_mib_init(void)
TCP_ADD_STATS_USER(TcpMaxConn, -1);
}
+/* /proc */
+enum tcp_seq_states {
+ TCP_SEQ_STATE_LISTENING,
+ TCP_SEQ_STATE_OPENREQ,
+ TCP_SEQ_STATE_ESTABLISHED,
+ TCP_SEQ_STATE_TIME_WAIT,
+};
+
+struct tcp_seq_afinfo {
+ struct module *owner;
+ char *name;
+ sa_family_t family;
+ int (*seq_show) (struct seq_file *m, void *v);
+ struct file_operations *seq_fops;
+};
+
+struct tcp_iter_state {
+ sa_family_t family;
+ enum tcp_seq_states state;
+ struct sock *syn_wait_sk;
+ int bucket, sbucket, num, uid;
+ struct seq_operations seq_ops;
+};
+
+extern int tcp_proc_register(struct tcp_seq_afinfo *afinfo);
+extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo);
+
#endif /* _TCP_H */
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index f08e534ea02f..f96acad1857c 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1237,8 +1237,8 @@ extern void fib_proc_exit(void);
extern int ip_misc_proc_init(void);
extern int raw_proc_init(void);
extern void raw_proc_exit(void);
-extern int tcp_proc_init(void);
-extern void tcp_proc_exit(void);
+extern int tcp4_proc_init(void);
+extern void tcp4_proc_exit(void);
extern int udp4_proc_init(void);
extern void udp4_proc_exit(void);
@@ -1248,7 +1248,7 @@ int __init ipv4_proc_init(void)
if (raw_proc_init())
goto out_raw;
- if (tcp_proc_init())
+ if (tcp4_proc_init())
goto out_tcp;
if (udp4_proc_init())
goto out_udp;
@@ -1263,7 +1263,7 @@ out_misc:
out_fib:
udp4_proc_exit();
out_udp:
- tcp_proc_exit();
+ tcp4_proc_exit();
out_tcp:
raw_proc_exit();
out_raw:
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 2ad587593075..544a181ff550 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2129,19 +2129,6 @@ static int tcp_v4_destroy_sock(struct sock *sk)
#ifdef CONFIG_PROC_FS
/* Proc filesystem TCP sock list dumping. */
-enum tcp_seq_states {
- TCP_SEQ_STATE_LISTENING,
- TCP_SEQ_STATE_OPENREQ,
- TCP_SEQ_STATE_ESTABLISHED,
- TCP_SEQ_STATE_TIME_WAIT,
-};
-
-struct tcp_iter_state {
- enum tcp_seq_states state;
- struct sock *syn_wait_sk;
- int bucket, sbucket, num, uid;
-};
-
static void *listening_get_first(struct seq_file *seq)
{
struct tcp_iter_state* st = seq->private;
@@ -2155,7 +2142,7 @@ static void *listening_get_first(struct seq_file *seq)
if (!sk)
continue;
++st->num;
- if (TCP_INET_FAMILY(sk->family)) {
+ if (sk->family == st->family) {
rc = sk;
goto out;
}
@@ -2169,7 +2156,7 @@ static void *listening_get_first(struct seq_file *seq)
++st->sbucket) {
for (req = tp->listen_opt->syn_table[st->sbucket];
req; req = req->dl_next, ++st->num) {
- if (!TCP_INET_FAMILY(req->class->family))
+ if (req->class->family != st->family)
continue;
rc = req;
goto out;
@@ -2197,7 +2184,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
while (1) {
while (req) {
++st->num;
- if (TCP_INET_FAMILY(req->class->family)) {
+ if (req->class->family == st->family) {
cur = req;
goto out;
}
@@ -2215,7 +2202,7 @@ get_req:
sk = sk->next;
get_sk:
while (sk) {
- if (TCP_INET_FAMILY(sk->family)) {
+ if (sk->family == st->family) {
cur = sk;
goto out;
}
@@ -2262,7 +2249,7 @@ static void *established_get_first(struct seq_file *seq)
read_lock(&tcp_ehash[st->bucket].lock);
for (sk = tcp_ehash[st->bucket].chain; sk;
sk = sk->next, ++st->num) {
- if (!TCP_INET_FAMILY(sk->family))
+ if (sk->family != st->family)
continue;
rc = sk;
goto out;
@@ -2271,7 +2258,7 @@ static void *established_get_first(struct seq_file *seq)
for (tw = (struct tcp_tw_bucket *)
tcp_ehash[st->bucket + tcp_ehash_size].chain;
tw; tw = (struct tcp_tw_bucket *)tw->next, ++st->num) {
- if (!TCP_INET_FAMILY(tw->family))
+ if (tw->family != st->family)
continue;
rc = tw;
goto out;
@@ -2293,7 +2280,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
tw = cur;
tw = (struct tcp_tw_bucket *)tw->next;
get_tw:
- while (tw && !TCP_INET_FAMILY(tw->family)) {
+ while (tw && tw->family != st->family) {
++st->num;
tw = (struct tcp_tw_bucket *)tw->next;
}
@@ -2313,7 +2300,7 @@ get_tw:
} else
sk = sk->next;
- while (sk && !TCP_INET_FAMILY(sk->family)) {
+ while (sk && sk->family != st->family) {
++st->num;
sk = sk->next;
}
@@ -2417,8 +2404,66 @@ static void tcp_seq_stop(struct seq_file *seq, void *v)
}
}
-static void get_openreq(struct sock *sk, struct open_request *req,
- char *tmpbuf, int i, int uid)
+static int tcp_seq_open(struct inode *inode, struct file *file)
+{
+ struct tcp_seq_afinfo *afinfo = PDE(inode)->data;
+ struct seq_file *seq;
+ int rc = -ENOMEM;
+ struct tcp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+ if (!s)
+ goto out;
+ memset(s, 0, sizeof(*s));
+ 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;
+
+ rc = seq_open(file, &s->seq_ops);
+ if (rc)
+ goto out_kfree;
+ seq = file->private_data;
+ seq->private = s;
+out:
+ return rc;
+out_kfree:
+ kfree(s);
+ goto out;
+}
+
+int tcp_proc_register(struct tcp_seq_afinfo *afinfo)
+{
+ int rc = 0;
+ struct proc_dir_entry *p;
+
+ if (!afinfo)
+ return -EINVAL;
+ afinfo->seq_fops->owner = afinfo->owner;
+ 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;
+
+ p = create_proc_entry(afinfo->name, S_IRUGO, proc_net);
+ if (p) {
+ p->data = afinfo;
+ p->proc_fops = afinfo->seq_fops;
+ } else
+ rc = -ENOMEM;
+ return rc;
+}
+
+void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo)
+{
+ if (!afinfo)
+ return;
+ remove_proc_entry(afinfo->name, proc_net);
+ memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
+}
+
+static void get_openreq4(struct sock *sk, struct open_request *req,
+ char *tmpbuf, int i, int uid)
{
int ttd = req->expires - jiffies;
@@ -2441,7 +2486,7 @@ static void get_openreq(struct sock *sk, struct open_request *req,
req);
}
-static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i)
+static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i)
{
int timer_active;
unsigned long timer_expires;
@@ -2481,7 +2526,7 @@ static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i)
tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh);
}
-static void get_timewait_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
+static void get_timewait4_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
{
unsigned int dest, src;
__u16 destp, srcp;
@@ -2504,7 +2549,7 @@ static void get_timewait_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
#define TMPSZ 150
-static int tcp_seq_show(struct seq_file *seq, void *v)
+static int tcp4_seq_show(struct seq_file *seq, void *v)
{
struct tcp_iter_state* st;
char tmpbuf[TMPSZ + 1];
@@ -2521,13 +2566,13 @@ static int tcp_seq_show(struct seq_file *seq, void *v)
switch (st->state) {
case TCP_SEQ_STATE_LISTENING:
case TCP_SEQ_STATE_ESTABLISHED:
- get_tcp_sock(v, tmpbuf, st->num);
+ get_tcp4_sock(v, tmpbuf, st->num);
break;
case TCP_SEQ_STATE_OPENREQ:
- get_openreq(st->syn_wait_sk, v, tmpbuf, st->num, st->uid);
+ get_openreq4(st->syn_wait_sk, v, tmpbuf, st->num, st->uid);
break;
case TCP_SEQ_STATE_TIME_WAIT:
- get_timewait_sock(v, tmpbuf, st->num);
+ get_timewait4_sock(v, tmpbuf, st->num);
break;
}
seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf);
@@ -2535,57 +2580,23 @@ out:
return 0;
}
-static struct seq_operations tcp_seq_ops = {
- .start = tcp_seq_start,
- .next = tcp_seq_next,
- .stop = tcp_seq_stop,
- .show = tcp_seq_show,
-};
-
-static int tcp_seq_open(struct inode *inode, struct file *file)
-{
- struct seq_file *seq;
- int rc = -ENOMEM;
- struct tcp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
- if (!s)
- goto out;
- rc = seq_open(file, &tcp_seq_ops);
- if (rc)
- goto out_kfree;
- seq = file->private_data;
- seq->private = s;
- memset(s, 0, sizeof(*s));
-out:
- return rc;
-out_kfree:
- kfree(s);
- goto out;
-}
-
-static struct file_operations tcp_seq_fops = {
- .owner = THIS_MODULE,
- .open = tcp_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_private,
+static struct file_operations tcp4_seq_fops;
+static struct tcp_seq_afinfo tcp4_seq_afinfo = {
+ .owner = THIS_MODULE,
+ .name = "tcp",
+ .family = AF_INET,
+ .seq_show = tcp4_seq_show,
+ .seq_fops = &tcp4_seq_fops,
};
-int __init tcp_proc_init(void)
+int __init tcp4_proc_init(void)
{
- int rc = 0;
- struct proc_dir_entry *p = create_proc_entry("tcp", S_IRUGO, proc_net);
-
- if (p)
- p->proc_fops = &tcp_seq_fops;
- else
- rc = -ENOMEM;
- return rc;
+ return tcp_proc_register(&tcp4_seq_afinfo);
}
-void __init tcp_proc_exit(void)
+void tcp4_proc_exit(void)
{
- remove_proc_entry("tcp", proc_net);
+ tcp_proc_unregister(&tcp4_seq_afinfo);
}
#endif /* CONFIG_PROC_FS */
diff --git a/net/netsyms.c b/net/netsyms.c
index 8521972ee48e..c153585701e3 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -285,6 +285,8 @@ EXPORT_SYMBOL(unregister_inetaddr_notifier);
#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(udp_proc_register);
EXPORT_SYMBOL(udp_proc_unregister);
+EXPORT_SYMBOL(tcp_proc_register);
+EXPORT_SYMBOL(tcp_proc_unregister);
#endif
/* needed for ip_gre -cw */