diff options
| author | Hideaki Yoshifuji <yoshfuji@linux-ipv6.org> | 2003-07-02 12:23:18 +1000 |
|---|---|---|
| committer | James Morris <jmorris@kernel.bkbits.net> | 2003-07-02 12:23:18 +1000 |
| commit | ba22d84c4729cdb68753cb31319c4e712b80a4ea (patch) | |
| tree | 4c4ad2a11c7b48f12caf996b6160cf110ca21aad /net/ipv6 | |
| parent | f26e95cb2b2d656f5fbaa840f9e283cf21ecfdad (diff) | |
[NET] convert /proc/net/mfilter6 to seq_file
Diffstat (limited to 'net/ipv6')
| -rw-r--r-- | net/ipv6/mcast.c | 227 |
1 files changed, 164 insertions, 63 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 717d77ee8492..f286ae429a2c 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2179,80 +2179,178 @@ static struct file_operations igmp6_mc_seq_fops = { .release = seq_release_private, }; -static int ip6_mcf_read_proc(char *buffer, char **start, off_t offset, - int length, int *eof, void *data) -{ - off_t pos=0, begin=0; - int len=0; - int first=1; +struct igmp6_mcf_iter_state { struct net_device *dev; - - read_lock(&dev_base_lock); - for (dev=dev_base; dev; dev=dev->next) { - struct inet6_dev *idev = in6_dev_get(dev); - struct ifmcaddr6 *imc; + struct inet6_dev *idev; + struct ifmcaddr6 *im; +}; - if (idev == NULL) - continue; +#define igmp6_mcf_seq_private(seq) ((struct igmp6_mcf_iter_state *)&seq->private) - read_lock_bh(&idev->lock); +static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) +{ + struct ip6_sf_list *psf = NULL; + struct ifmcaddr6 *im = NULL; + struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); - for (imc=idev->mc_list; imc; imc=imc->next) { - struct ip6_sf_list *psf; - unsigned long i; - - spin_lock_bh(&imc->mca_lock); - for (psf=imc->mca_sources; psf; psf=psf->sf_next) { - if (first) { - len += sprintf(buffer+len, "%3s %6s " - "%32s %32s %6s %6s\n", "Idx", - "Device", "Multicast Address", - "Source Address", "INC", "EXC"); - first = 0; - } - len += sprintf(buffer+len,"%3d %6.6s ", - dev->ifindex, dev->name); - - for (i=0; i<16; i++) - len += sprintf(buffer+len, "%02x", - imc->mca_addr.s6_addr[i]); - buffer[len++] = ' '; - for (i=0; i<16; i++) - len += sprintf(buffer+len, "%02x", - psf->sf_addr.s6_addr[i]); - len += sprintf(buffer+len, " %6lu %6lu\n", - psf->sf_count[MCAST_INCLUDE], - psf->sf_count[MCAST_EXCLUDE]); - pos = begin+len; - if (pos < offset) { - len=0; - begin=pos; - } - if (pos > offset+length) { - spin_unlock_bh(&imc->mca_lock); - read_unlock_bh(&idev->lock); - in6_dev_put(idev); - goto done; - } + for (state->dev = dev_base, state->idev = NULL, state->im = NULL; + state->dev; + state->dev = state->dev->next) { + struct inet6_dev *idev; + idev = in6_dev_get(state->dev); + if (unlikely(idev == NULL)) + continue; + read_lock_bh(&idev->lock); + im = idev->mc_list; + if (likely(im != NULL)) { + spin_lock_bh(&im->mca_lock); + psf = im->mca_sources; + if (likely(psf != NULL)) { + state->im = im; + state->idev = idev; + break; } - spin_unlock_bh(&imc->mca_lock); + spin_unlock_bh(&im->mca_lock); } read_unlock_bh(&idev->lock); - in6_dev_put(idev); } - *eof = 1; + return psf; +} -done: +static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_sf_list *psf) +{ + struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); + + psf = psf->sf_next; + while (!psf) { + spin_unlock_bh(&state->im->mca_lock); + state->im = state->im->next; + while (!state->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; + goto out; + } + state->idev = in6_dev_get(state->dev); + if (!state->idev) + continue; + read_lock_bh(&state->idev->lock); + state->im = state->idev->mc_list; + } + if (!state->im) + break; + spin_lock_bh(&state->im->mca_lock); + psf = state->im->mca_sources; + } +out: + return psf; +} + +static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos) +{ + struct ip6_sf_list *psf = igmp6_mcf_get_first(seq); + if (psf) + while (pos && (psf = igmp6_mcf_get_next(seq, psf)) != NULL) + --pos; + return pos ? NULL : psf; +} + +static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) +{ + read_lock(&dev_base_lock); + return *pos ? igmp6_mcf_get_idx(seq, *pos) : (void *)1; +} + +static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct ip6_sf_list *psf; + if (v == (void *)1) + psf = igmp6_mcf_get_first(seq); + else + psf = igmp6_mcf_get_next(seq, v); + ++*pos; + return psf; +} + +static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) +{ + struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); + if (likely(state->im != NULL)) + spin_unlock_bh(&state->im->mca_lock); + if (likely(state->idev != NULL)) { + read_unlock_bh(&state->idev->lock); + in6_dev_put(state->idev); + } read_unlock(&dev_base_lock); +} + +static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) +{ + struct ip6_sf_list *psf = (struct ip6_sf_list *)v; + struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); + + if (v == (void *)1) { + seq_printf(seq, + "%3s %6s " + "%32s %32s %6s %6s\n", "Idx", + "Device", "Multicast Address", + "Source Address", "INC", "EXC"); + } else { + seq_printf(seq, + "%3d %6.6s " + "%04x%04x%04x%04x%04x%04x%04x%04x " + "%04x%04x%04x%04x%04x%04x%04x%04x " + "%6lu %6lu\n", + state->dev->ifindex, state->dev->name, + NIP6(state->im->mca_addr), + NIP6(psf->sf_addr), + psf->sf_count[MCAST_INCLUDE], + psf->sf_count[MCAST_EXCLUDE]); + } + return 0; +} + +static struct seq_operations igmp6_mcf_seq_ops = { + .start = igmp6_mcf_seq_start, + .next = igmp6_mcf_seq_next, + .stop = igmp6_mcf_seq_stop, + .show = igmp6_mcf_seq_show, +}; + +static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc = -ENOMEM; + struct igmp6_mcf_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); + + if (!s) + goto out; - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - if (len<0) - len=0; - return len; + rc = seq_open(file, &igmp6_mcf_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_mcf_seq_fops = { + .owner = THIS_MODULE, + .open = igmp6_mcf_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; #endif int __init igmp6_init(struct net_proto_family *ops) @@ -2284,7 +2382,9 @@ int __init igmp6_init(struct net_proto_family *ops) 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); + p = create_proc_entry("mcfilter6", S_IRUGO, proc_net); + if (p) + p->proc_fops = &igmp6_mcf_seq_fops; #endif return 0; @@ -2295,6 +2395,7 @@ void igmp6_cleanup(void) sock_release(igmp6_socket); igmp6_socket = NULL; /* for safety */ #ifdef CONFIG_PROC_FS + proc_net_remove("mcfilter6"); proc_net_remove("igmp6"); #endif } |
