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");
extern int raw6_proc_init(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 void udp6_proc_exit(void);
......@@ -789,7 +790,7 @@ static int __init inet6_init(void)
err = -ENOMEM;
if (raw6_proc_init())
goto proc_raw6_fail;
if (!proc_net_create("tcp6", 0, tcp6_get_info))
if (tcp6_proc_init())
goto proc_tcp6_fail;
if (udp6_proc_init())
goto proc_udp6_fail;
......@@ -824,7 +825,7 @@ static int __init inet6_init(void)
proc_misc6_fail:
udp6_proc_exit();
proc_udp6_fail:
proc_net_remove("tcp6");
tcp6_proc_exit();
proc_tcp6_fail:
raw6_proc_exit();
proc_raw6_fail:
......
......@@ -17,6 +17,7 @@
* YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
* Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
* 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
* modify it under the terms of the GNU General Public License
......@@ -55,6 +56,9 @@
#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_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,
......@@ -1934,7 +1938,8 @@ static int tcp_v6_destroy_sock(struct sock *sk)
}
/* 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;
int ttd = req->expires - jiffies;
......@@ -1944,28 +1949,28 @@ static void get_openreq6(struct sock *sk, struct open_request *req, char *tmpbuf
src = &req->af.v6_req.loc_addr;
dest = &req->af.v6_req.rmt_addr;
sprintf(tmpbuf,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3],
ntohs(inet_sk(sk)->sport),
dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3],
ntohs(req->rmt_port),
TCP_SYN_RECV,
0,0, /* could print option size, but that is af dependent. */
1, /* timers active (only the expire timer) */
ttd,
req->retrans,
uid,
0, /* non standard timer */
0, /* open_requests have no inode */
0, req);
seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p\n",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3],
ntohs(inet_sk(sk)->sport),
dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3],
ntohs(req->rmt_port),
TCP_SYN_RECV,
0,0, /* could print option size, but that is af dependent. */
1, /* timers active (only the expire timer) */
ttd,
req->retrans,
uid,
0, /* non standard timer */
0, /* open_requests have no inode */
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;
__u16 destp, srcp;
......@@ -1993,28 +1998,29 @@ static void get_tcp6_sock(struct sock *sp, char *tmpbuf, int i)
timer_expires = jiffies;
}
sprintf(tmpbuf,
"%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",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp,
dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], destp,
sp->state,
tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
timer_active, timer_expires-jiffies,
tp->retransmits,
sock_i_uid(sp),
tp->probes_out,
sock_i_ino(sp),
atomic_read(&sp->refcnt), sp,
tp->rto, tp->ack.ato, (tp->ack.quick<<1)|tp->ack.pingpong,
tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
);
seq_printf(seq,
"%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\n",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp,
dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], destp,
sp->state,
tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
timer_active, timer_expires-jiffies,
tp->retransmits,
sock_i_uid(sp),
tp->probes_out,
sock_i_ino(sp),
atomic_read(&sp->refcnt), sp,
tp->rto, tp->ack.ato, (tp->ack.quick<<1)|tp->ack.pingpong,
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;
__u16 destp, srcp;
......@@ -2028,144 +2034,67 @@ static void get_timewait6_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
destp = ntohs(tw->dport);
srcp = ntohs(tw->sport);
sprintf(tmpbuf,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp,
dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], destp,
tw->substate, 0, 0,
3, ttd, 0, 0, 0, 0,
atomic_read(&tw->refcnt), tw);
seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p\n",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp,
dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], destp,
tw->substate, 0, 0,
3, ttd, 0, 0, 0, 0,
atomic_read(&tw->refcnt), tw);
}
#define LINE_LEN 190
#define LINE_FMT "%-190s\n"
int tcp6_get_info(char *buffer, char **start, off_t offset, int length)
static int tcp6_seq_show(struct seq_file *seq, void *v)
{
int len = 0, num = 0, i;
off_t begin, pos = 0;
char tmpbuf[LINE_LEN+2];
if (offset < LINE_LEN+1)
len += sprintf(buffer, LINE_FMT,
" sl " /* 6 */
"local_address " /* 38 */
"remote_address " /* 38 */
"st tx_queue rx_queue tr tm->when retrnsmt" /* 41 */
" uid timeout inode"); /* 21 */
/*----*/
/*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);
struct tcp_iter_state *st;
if (v == (void *)1) {
seq_printf(seq,
" sl "
"local_address "
"remote_address "
"st tx_queue rx_queue tr tm->when retrnsmt"
" uid timeout inode\n");
goto out;
}
st = seq->private;
/* 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. */
for (i = 0; i < tcp_ehash_size; i++) {
struct tcp_ehash_bucket *head = &tcp_ehash[i];
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);
}
int __init tcp6_proc_init(void)
{
return tcp_proc_register(&tcp6_seq_afinfo);
}
out:
local_bh_enable();
out_no_bh:
begin = len - (pos - offset);
*start = buffer + begin;
len -= begin;
if (len > length)
len = length;
if (len < 0)
len = 0;
return len;
void tcp6_proc_exit(void)
{
tcp_proc_unregister(&tcp6_seq_afinfo);
}
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