Commit 24818d6e authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji Committed by James Morris

[NET] convert /proc/net/igmp to seq_file

parent f16fd25c
......@@ -79,7 +79,7 @@ extern rwlock_t ip_ra_lock;
extern void ip_mc_dropsocket(struct sock *);
extern void ip_mc_dropdevice(struct net_device *dev);
extern int ip_mc_procinfo(char *, char **, off_t, int);
extern int igmp_mc_proc_init(void);
extern int ip_mcf_procinfo(char *, char **, off_t, int);
/*
......
......@@ -99,7 +99,10 @@
#ifdef CONFIG_IP_MROUTE
#include <linux/mroute.h>
#endif
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#endif
#define IP_MAX_MEMBERSHIPS 20
......@@ -2090,65 +2093,162 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
return rv;
}
#if defined(CONFIG_PROC_FS)
struct igmp_mc_iter_state {
struct net_device *dev;
struct in_device *in_dev;
};
#define igmp_mc_seq_private(seq) ((struct igmp_mc_iter_state *)&seq->private)
int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
{
off_t pos=0, begin=0;
struct ip_mc_list *im;
int len=0;
struct net_device *dev;
struct ip_mc_list *im = NULL;
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
for (state->dev = dev_base, state->in_dev = NULL;
state->dev;
state->dev = state->dev->next) {
struct in_device *in_dev;
in_dev = in_dev_get(state->dev);
if (!in_dev)
continue;
read_lock(&in_dev->lock);
im = in_dev->mc_list;
if (im) {
state->in_dev = in_dev;
break;
}
read_unlock(&in_dev->lock);
}
return im;
}
static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im)
{
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
im = im->next;
while (!im) {
if (likely(state->in_dev != NULL)) {
read_unlock(&state->in_dev->lock);
in_dev_put(state->in_dev);
}
state->dev = state->dev->next;
if (!state->dev) {
state->in_dev = NULL;
break;
}
state->in_dev = in_dev_get(state->dev);
if (!state->in_dev)
continue;
read_lock(&state->in_dev->lock);
im = state->in_dev->mc_list;
}
return im;
}
len=sprintf(buffer,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n");
static struct ip_mc_list *igmp_mc_get_idx(struct seq_file *seq, loff_t pos)
{
struct ip_mc_list *im = igmp_mc_get_first(seq);
if (im)
while (pos && (im = igmp_mc_get_next(seq, im)) != NULL)
--pos;
return pos ? NULL : im;
}
static void *igmp_mc_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&dev_base_lock);
for(dev = dev_base; dev; dev = dev->next) {
struct in_device *in_dev = in_dev_get(dev);
char *querier = "NONE";
return *pos ? igmp_mc_get_idx(seq, *pos) : (void *)1;
}
if (in_dev == NULL)
continue;
static void *igmp_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct ip_mc_list *im;
if (v == (void *)1)
im = igmp_mc_get_first(seq);
else
im = igmp_mc_get_next(seq, v);
++*pos;
return im;
}
static void igmp_mc_seq_stop(struct seq_file *seq, void *v)
{
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
if (likely(state->in_dev != NULL)) {
read_unlock(&state->in_dev->lock);
in_dev_put(state->in_dev);
}
read_unlock(&dev_base_lock);
}
static int igmp_mc_seq_show(struct seq_file *seq, void *v)
{
if (v == (void *)1)
seq_printf(seq,
"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n");
else {
struct ip_mc_list *im = (struct ip_mc_list *)v;
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
char *querier;
#ifdef CONFIG_IP_MULTICAST
querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2";
querier = IGMP_V1_SEEN(state->in_dev) ? "V1" : "V2";
#else
querier = "NONE";
#endif
len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n",
dev->ifindex, dev->name, dev->mc_count, querier);
read_lock(&in_dev->lock);
for (im = in_dev->mc_list; im; im = im->next) {
len+=sprintf(buffer+len,
"\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
im->multiaddr, im->users,
im->tm_running, im->timer.expires-jiffies, im->reporter);
pos=begin+len;
if(pos<offset)
{
len=0;
begin=pos;
}
if(pos>offset+length) {
read_unlock(&in_dev->lock);
in_dev_put(in_dev);
goto done;
}
if (state->in_dev->mc_list == im) {
seq_printf(seq, "%d\t%-10s: %5d %7s\n",
state->dev->ifindex, state->dev->name, state->dev->mc_count, querier);
}
read_unlock(&in_dev->lock);
in_dev_put(in_dev);
seq_printf(seq,
"\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
im->multiaddr, im->users,
im->tm_running, im->timer.expires-jiffies, im->reporter);
}
done:
read_unlock(&dev_base_lock);
return 0;
}
*start=buffer+(offset-begin);
len-=(offset-begin);
if(len>length)
len=length;
if(len<0)
len=0;
return len;
static struct seq_operations igmp_mc_seq_ops = {
.start = igmp_mc_seq_start,
.next = igmp_mc_seq_next,
.stop = igmp_mc_seq_stop,
.show = igmp_mc_seq_show,
};
static int igmp_mc_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rc = -ENOMEM;
struct igmp_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &igmp_mc_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 igmp_mc_seq_fops = {
.owner = THIS_MODULE,
.open = igmp_mc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
#endif
int ip_mcf_procinfo(char *buffer, char **start, off_t offset, int length)
{
off_t pos=0, begin=0;
......@@ -2214,3 +2314,15 @@ int ip_mcf_procinfo(char *buffer, char **start, off_t offset, int length)
return len;
}
#ifdef CONFIG_PROC_FS
int __init igmp_mc_proc_init(void)
{
struct proc_dir_entry *p;
p = create_proc_entry("igmp", S_IRUGO, proc_net);
if (p)
p->proc_fops = &igmp_mc_seq_fops;
return 0;
}
#endif
......@@ -1314,7 +1314,7 @@ void __init ip_init(void)
inet_initpeers();
#ifdef CONFIG_IP_MULTICAST
proc_net_create("igmp", 0, ip_mc_procinfo);
igmp_mc_proc_init();
#endif
proc_net_create("mcfilter", 0, ip_mcf_procinfo);
}
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