Commit 5a00d2d2 authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji Committed by David S. Miller

[IPV6]: Convert /proc/net/tcp6 to seq_file.

parent a9b7fa76
...@@ -77,7 +77,8 @@ MODULE_LICENSE("GPL"); ...@@ -77,7 +77,8 @@ MODULE_LICENSE("GPL");
extern int raw6_proc_init(void); extern int raw6_proc_init(void);
extern int raw6_proc_exit(void); extern int raw6_proc_exit(void);
extern int tcp6_get_info(char *, char **, off_t, int); extern int tcp6_proc_init(void);
extern void tcp6_proc_exit(void);
extern int udp6_proc_init(void); extern int udp6_proc_init(void);
extern void udp6_proc_exit(void); extern void udp6_proc_exit(void);
...@@ -789,7 +790,7 @@ static int __init inet6_init(void) ...@@ -789,7 +790,7 @@ static int __init inet6_init(void)
err = -ENOMEM; err = -ENOMEM;
if (raw6_proc_init()) if (raw6_proc_init())
goto proc_raw6_fail; goto proc_raw6_fail;
if (!proc_net_create("tcp6", 0, tcp6_get_info)) if (tcp6_proc_init())
goto proc_tcp6_fail; goto proc_tcp6_fail;
if (udp6_proc_init()) if (udp6_proc_init())
goto proc_udp6_fail; goto proc_udp6_fail;
...@@ -824,7 +825,7 @@ static int __init inet6_init(void) ...@@ -824,7 +825,7 @@ static int __init inet6_init(void)
proc_misc6_fail: proc_misc6_fail:
udp6_proc_exit(); udp6_proc_exit();
proc_udp6_fail: proc_udp6_fail:
proc_net_remove("tcp6"); tcp6_proc_exit();
proc_tcp6_fail: proc_tcp6_fail:
raw6_proc_exit(); raw6_proc_exit();
proc_raw6_fail: proc_raw6_fail:
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
* Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
* a single port at the same time. * a single port at the same time.
* YOSHIFUJI Hideaki @USAGI: convert /proc/net/tcp6 to seq_file.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -55,6 +56,9 @@ ...@@ -55,6 +56,9 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static void tcp_v6_send_reset(struct sk_buff *skb); static void tcp_v6_send_reset(struct sk_buff *skb);
static void tcp_v6_or_send_ack(struct sk_buff *skb, struct open_request *req); static void tcp_v6_or_send_ack(struct sk_buff *skb, struct open_request *req);
static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len, static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len,
...@@ -1934,7 +1938,8 @@ static int tcp_v6_destroy_sock(struct sock *sk) ...@@ -1934,7 +1938,8 @@ static int tcp_v6_destroy_sock(struct sock *sk)
} }
/* Proc filesystem TCPv6 sock list dumping. */ /* Proc filesystem TCPv6 sock list dumping. */
static void get_openreq6(struct sock *sk, struct open_request *req, char *tmpbuf, int i, int uid) static void get_openreq6(struct seq_file *seq,
struct sock *sk, struct open_request *req, int i, int uid)
{ {
struct in6_addr *dest, *src; struct in6_addr *dest, *src;
int ttd = req->expires - jiffies; int ttd = req->expires - jiffies;
...@@ -1944,28 +1949,28 @@ static void get_openreq6(struct sock *sk, struct open_request *req, char *tmpbuf ...@@ -1944,28 +1949,28 @@ static void get_openreq6(struct sock *sk, struct open_request *req, char *tmpbuf
src = &req->af.v6_req.loc_addr; src = &req->af.v6_req.loc_addr;
dest = &req->af.v6_req.rmt_addr; dest = &req->af.v6_req.rmt_addr;
sprintf(tmpbuf, seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p", "%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p\n",
i, i,
src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], src->s6_addr32[2], src->s6_addr32[3],
ntohs(inet_sk(sk)->sport), ntohs(inet_sk(sk)->sport),
dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], dest->s6_addr32[2], dest->s6_addr32[3],
ntohs(req->rmt_port), ntohs(req->rmt_port),
TCP_SYN_RECV, TCP_SYN_RECV,
0,0, /* could print option size, but that is af dependent. */ 0,0, /* could print option size, but that is af dependent. */
1, /* timers active (only the expire timer) */ 1, /* timers active (only the expire timer) */
ttd, ttd,
req->retrans, req->retrans,
uid, uid,
0, /* non standard timer */ 0, /* non standard timer */
0, /* open_requests have no inode */ 0, /* open_requests have no inode */
0, req); 0, req);
} }
static void get_tcp6_sock(struct sock *sp, char *tmpbuf, int i) static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
{ {
struct in6_addr *dest, *src; struct in6_addr *dest, *src;
__u16 destp, srcp; __u16 destp, srcp;
...@@ -1993,28 +1998,29 @@ static void get_tcp6_sock(struct sock *sp, char *tmpbuf, int i) ...@@ -1993,28 +1998,29 @@ static void get_tcp6_sock(struct sock *sp, char *tmpbuf, int i)
timer_expires = jiffies; timer_expires = jiffies;
} }
sprintf(tmpbuf, seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d", "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n",
i, i,
src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp, src->s6_addr32[2], src->s6_addr32[3], srcp,
dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], destp, dest->s6_addr32[2], dest->s6_addr32[3], destp,
sp->state, sp->state,
tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq, tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
timer_active, timer_expires-jiffies, timer_active, timer_expires-jiffies,
tp->retransmits, tp->retransmits,
sock_i_uid(sp), sock_i_uid(sp),
tp->probes_out, tp->probes_out,
sock_i_ino(sp), sock_i_ino(sp),
atomic_read(&sp->refcnt), sp, atomic_read(&sp->refcnt), sp,
tp->rto, tp->ack.ato, (tp->ack.quick<<1)|tp->ack.pingpong, tp->rto, tp->ack.ato, (tp->ack.quick<<1)|tp->ack.pingpong,
tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
); );
} }
static void get_timewait6_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i) static void get_timewait6_sock(struct seq_file *seq,
struct tcp_tw_bucket *tw, int i)
{ {
struct in6_addr *dest, *src; struct in6_addr *dest, *src;
__u16 destp, srcp; __u16 destp, srcp;
...@@ -2028,144 +2034,67 @@ static void get_timewait6_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i) ...@@ -2028,144 +2034,67 @@ static void get_timewait6_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
destp = ntohs(tw->dport); destp = ntohs(tw->dport);
srcp = ntohs(tw->sport); srcp = ntohs(tw->sport);
sprintf(tmpbuf, seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p", "%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p\n",
i, i,
src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp, src->s6_addr32[2], src->s6_addr32[3], srcp,
dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], destp, dest->s6_addr32[2], dest->s6_addr32[3], destp,
tw->substate, 0, 0, tw->substate, 0, 0,
3, ttd, 0, 0, 0, 0, 3, ttd, 0, 0, 0, 0,
atomic_read(&tw->refcnt), tw); atomic_read(&tw->refcnt), tw);
} }
#define LINE_LEN 190 static int tcp6_seq_show(struct seq_file *seq, void *v)
#define LINE_FMT "%-190s\n"
int tcp6_get_info(char *buffer, char **start, off_t offset, int length)
{ {
int len = 0, num = 0, i; struct tcp_iter_state *st;
off_t begin, pos = 0;
char tmpbuf[LINE_LEN+2]; if (v == (void *)1) {
seq_printf(seq,
if (offset < LINE_LEN+1) " sl "
len += sprintf(buffer, LINE_FMT, "local_address "
" sl " /* 6 */ "remote_address "
"local_address " /* 38 */ "st tx_queue rx_queue tr tm->when retrnsmt"
"remote_address " /* 38 */ " uid timeout inode\n");
"st tx_queue rx_queue tr tm->when retrnsmt" /* 41 */ goto out;
" uid timeout inode"); /* 21 */ }
/*----*/ st = seq->private;
/*144 */
pos = LINE_LEN+1;
/* First, walk listening socket table. */
tcp_listen_lock();
for(i = 0; i < TCP_LHTABLE_SIZE; i++) {
struct sock *sk = tcp_listening_hash[i];
struct tcp_listen_opt *lopt;
int k;
for (sk = tcp_listening_hash[i]; sk; sk = sk->next, num++) {
struct open_request *req;
int uid;
struct tcp_opt *tp = tcp_sk(sk);
if (sk->family != PF_INET6)
continue;
pos += LINE_LEN+1;
if (pos >= offset) {
get_tcp6_sock(sk, tmpbuf, num);
len += sprintf(buffer+len, LINE_FMT, tmpbuf);
if (pos >= offset + length) {
tcp_listen_unlock();
goto out_no_bh;
}
}
uid = sock_i_uid(sk);
read_lock_bh(&tp->syn_wait_lock);
lopt = tp->listen_opt;
if (lopt && lopt->qlen != 0) {
for (k=0; k<TCP_SYNQ_HSIZE; k++) {
for (req = lopt->syn_table[k]; req; req = req->dl_next, num++) {
if (req->class->family != PF_INET6)
continue;
pos += LINE_LEN+1;
if (pos <= offset)
continue;
get_openreq6(sk, req, tmpbuf, num, uid);
len += sprintf(buffer+len, LINE_FMT, tmpbuf);
if (pos >= offset + length) {
read_unlock_bh(&tp->syn_wait_lock);
tcp_listen_unlock();
goto out_no_bh;
}
}
}
}
read_unlock_bh(&tp->syn_wait_lock);
/* Completed requests are in normal socket hash table */ switch (st->state) {
} case TCP_SEQ_STATE_LISTENING:
case TCP_SEQ_STATE_ESTABLISHED:
get_tcp6_sock(seq, v, st->num);
break;
case TCP_SEQ_STATE_OPENREQ:
get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
break;
case TCP_SEQ_STATE_TIME_WAIT:
get_timewait6_sock(seq, v, st->num);
break;
} }
tcp_listen_unlock(); out:
return 0;
}
local_bh_disable(); static struct file_operations tcp6_seq_fops;
static struct tcp_seq_afinfo tcp6_seq_afinfo = {
.owner = THIS_MODULE,
.name = "tcp6",
.family = AF_INET6,
.seq_show = tcp6_seq_show,
.seq_fops = &tcp6_seq_fops,
};
/* Next, walk established hash chain. */ int __init tcp6_proc_init(void)
for (i = 0; i < tcp_ehash_size; i++) { {
struct tcp_ehash_bucket *head = &tcp_ehash[i]; return tcp_proc_register(&tcp6_seq_afinfo);
struct sock *sk; }
struct tcp_tw_bucket *tw;
read_lock(&head->lock);
for(sk = head->chain; sk; sk = sk->next, num++) {
if (sk->family != PF_INET6)
continue;
pos += LINE_LEN+1;
if (pos <= offset)
continue;
get_tcp6_sock(sk, tmpbuf, num);
len += sprintf(buffer+len, LINE_FMT, tmpbuf);
if (pos >= offset + length) {
read_unlock(&head->lock);
goto out;
}
}
for (tw = (struct tcp_tw_bucket *)tcp_ehash[i+tcp_ehash_size].chain;
tw != NULL;
tw = (struct tcp_tw_bucket *)tw->next, num++) {
if (tw->family != PF_INET6)
continue;
pos += LINE_LEN+1;
if (pos <= offset)
continue;
get_timewait6_sock(tw, tmpbuf, num);
len += sprintf(buffer+len, LINE_FMT, tmpbuf);
if (pos >= offset + length) {
read_unlock(&head->lock);
goto out;
}
}
read_unlock(&head->lock);
}
out: void tcp6_proc_exit(void)
local_bh_enable(); {
out_no_bh: tcp_proc_unregister(&tcp6_seq_afinfo);
begin = len - (pos - offset);
*start = buffer + begin;
len -= begin;
if (len > length)
len = length;
if (len < 0)
len = 0;
return len;
} }
struct proto tcpv6_prot = { struct proto tcpv6_prot = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment