Commit e2363971 authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji Committed by James Morris

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

parent 24818d6e
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <linux/route.h> #include <linux/route.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/snmp.h> #include <net/snmp.h>
...@@ -2039,64 +2040,145 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) ...@@ -2039,64 +2040,145 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int igmp6_read_proc(char *buffer, char **start, off_t offset, struct igmp6_mc_iter_state {
int length, int *eof, void *data)
{
off_t pos=0, begin=0;
struct ifmcaddr6 *im;
int len=0;
struct net_device *dev; struct net_device *dev;
read_lock(&dev_base_lock);
for (dev = dev_base; dev; dev = dev->next) {
struct inet6_dev *idev; struct inet6_dev *idev;
};
if ((idev = in6_dev_get(dev)) == NULL) #define igmp6_mc_seq_private(seq) ((struct igmp6_mc_iter_state *)&seq->private)
continue;
read_lock_bh(&idev->lock);
for (im = idev->mc_list; im; im = im->next) {
int i;
len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);
for (i=0; i<16; i++)
len += sprintf(buffer+len, "%02x", im->mca_addr.s6_addr[i]);
len+=sprintf(buffer+len, static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
" %5d %08X %ld\n", {
im->mca_users, struct ifmcaddr6 *im = NULL;
im->mca_flags, struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
(im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0);
pos=begin+len; for (state->dev = dev_base, state->idev = NULL;
if (pos < offset) { state->dev;
len=0; state->dev = state->dev->next) {
begin=pos; struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (!idev)
continue;
read_lock_bh(&idev->lock);
im = idev->mc_list;
if (im) {
state->idev = idev;
break;
} }
if (pos > offset+length) {
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
in6_dev_put(idev);
goto done;
} }
return im;
}
static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr6 *im)
{
struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
im = im->next;
while (!im) {
if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
state->dev = state->dev->next;
if (!state->dev) {
state->idev = NULL;
break;
} }
read_unlock_bh(&idev->lock); state->idev = in6_dev_get(state->dev);
in6_dev_put(idev); if (!state->idev)
continue;
read_lock_bh(&state->idev->lock);
im = state->idev->mc_list;
} }
*eof = 1; return im;
}
done: static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos)
{
struct ifmcaddr6 *im = igmp6_mc_get_first(seq);
if (im)
while (pos && (im = igmp6_mc_get_next(seq, im)) != NULL)
--pos;
return pos ? NULL : im;
}
static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&dev_base_lock);
return *pos ? igmp6_mc_get_idx(seq, *pos) : igmp6_mc_get_first(seq);
}
static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct ifmcaddr6 *im;
im = igmp6_mc_get_next(seq, v);
++*pos;
return im;
}
static void igmp6_mc_seq_stop(struct seq_file *seq, void *v)
{
struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
}
*start=buffer+(offset-begin); static int igmp6_mc_seq_show(struct seq_file *seq, void *v)
len-=(offset-begin); {
if(len>length) struct ifmcaddr6 *im = (struct ifmcaddr6 *)v;
len=length; struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
if (len<0)
len=0; seq_printf(seq,
return len; "%-4d %-15s %04x%04x%04x%04x%04x%04x%04x%04x %5d %08X %ld\n",
state->dev->ifindex, state->dev->name,
NIP6(im->mca_addr),
im->mca_users, im->mca_flags,
(im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0);
return 0;
}
static struct seq_operations igmp6_mc_seq_ops = {
.start = igmp6_mc_seq_start,
.next = igmp6_mc_seq_next,
.stop = igmp6_mc_seq_stop,
.show = igmp6_mc_seq_show,
};
static int igmp6_mc_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rc = -ENOMEM;
struct igmp6_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &igmp6_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 igmp6_mc_seq_fops = {
.owner = THIS_MODULE,
.open = igmp6_mc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
static int ip6_mcf_read_proc(char *buffer, char **start, off_t offset, static int ip6_mcf_read_proc(char *buffer, char **start, off_t offset,
int length, int *eof, void *data) int length, int *eof, void *data)
{ {
...@@ -2178,6 +2260,9 @@ int __init igmp6_init(struct net_proto_family *ops) ...@@ -2178,6 +2260,9 @@ int __init igmp6_init(struct net_proto_family *ops)
struct ipv6_pinfo *np; struct ipv6_pinfo *np;
struct sock *sk; struct sock *sk;
int err; int err;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *p;
#endif
err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket); err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket);
if (err < 0) { if (err < 0) {
...@@ -2194,8 +2279,11 @@ int __init igmp6_init(struct net_proto_family *ops) ...@@ -2194,8 +2279,11 @@ int __init igmp6_init(struct net_proto_family *ops)
np = inet6_sk(sk); np = inet6_sk(sk);
np->hop_limit = 1; np->hop_limit = 1;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
create_proc_read_entry("net/igmp6", 0, 0, igmp6_read_proc, NULL); p = create_proc_entry("igmp6", S_IRUGO, proc_net);
if (p)
p->proc_fops = &igmp6_mc_seq_fops;
create_proc_read_entry("net/mcfilter6", 0, 0, ip6_mcf_read_proc, NULL); create_proc_read_entry("net/mcfilter6", 0, 0, ip6_mcf_read_proc, NULL);
#endif #endif
...@@ -2207,6 +2295,6 @@ void igmp6_cleanup(void) ...@@ -2207,6 +2295,6 @@ void igmp6_cleanup(void)
sock_release(igmp6_socket); sock_release(igmp6_socket);
igmp6_socket = NULL; /* for safety */ igmp6_socket = NULL; /* for safety */
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
remove_proc_entry("net/igmp6", 0); proc_net_remove("igmp6");
#endif #endif
} }
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