Commit bdba9fe9 authored by Stephen Hemminger's avatar Stephen Hemminger

[NET] Convert ROSE to seq_file

The existing ROSE /proc interface has no module owner, and doesn't check for
bounds overflow.  Easier to just convert it to the seq_file wrapper functions.

This patch is against 2.6.0-test2 (offsets assume earlier patch).
parent 6ae0b08d
...@@ -140,6 +140,9 @@ typedef struct { ...@@ -140,6 +140,9 @@ typedef struct {
#define rose_sk(__sk) ((rose_cb *)(__sk)->sk_protinfo) #define rose_sk(__sk) ((rose_cb *)(__sk)->sk_protinfo)
/* Magic value indicating first entry in /proc (ie header) */
#define ROSE_PROC_START ((void *) 1)
/* af_rose.c */ /* af_rose.c */
extern ax25_address rose_callsign; extern ax25_address rose_callsign;
extern int sysctl_rose_restart_request_timeout; extern int sysctl_rose_restart_request_timeout;
...@@ -154,7 +157,7 @@ extern int sysctl_rose_maximum_vcs; ...@@ -154,7 +157,7 @@ extern int sysctl_rose_maximum_vcs;
extern int sysctl_rose_window_size; extern int sysctl_rose_window_size;
extern int rosecmp(rose_address *, rose_address *); extern int rosecmp(rose_address *, rose_address *);
extern int rosecmpm(rose_address *, rose_address *, unsigned short); extern int rosecmpm(rose_address *, rose_address *, unsigned short);
extern char *rose2asc(rose_address *); extern const char *rose2asc(const rose_address *);
extern struct sock *rose_find_socket(unsigned int, struct rose_neigh *); extern struct sock *rose_find_socket(unsigned int, struct rose_neigh *);
extern void rose_kill_by_neigh(struct rose_neigh *); extern void rose_kill_by_neigh(struct rose_neigh *);
extern unsigned int rose_new_lci(struct rose_neigh *); extern unsigned int rose_new_lci(struct rose_neigh *);
...@@ -193,6 +196,9 @@ extern void rose_enquiry_response(struct sock *); ...@@ -193,6 +196,9 @@ extern void rose_enquiry_response(struct sock *);
/* rose_route.c */ /* rose_route.c */
extern struct rose_neigh *rose_loopback_neigh; extern struct rose_neigh *rose_loopback_neigh;
extern struct file_operations rose_neigh_fops;
extern struct file_operations rose_nodes_fops;
extern struct file_operations rose_routes_fops;
extern int rose_add_loopback_neigh(void); extern int rose_add_loopback_neigh(void);
extern int rose_add_loopback_node(rose_address *); extern int rose_add_loopback_node(rose_address *);
...@@ -207,9 +213,6 @@ extern struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *, unsign ...@@ -207,9 +213,6 @@ extern struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *, unsign
extern int rose_rt_ioctl(unsigned int, void *); extern int rose_rt_ioctl(unsigned int, void *);
extern void rose_link_failed(ax25_cb *, int); extern void rose_link_failed(ax25_cb *, int);
extern int rose_route_frame(struct sk_buff *, ax25_cb *); extern int rose_route_frame(struct sk_buff *, ax25_cb *);
extern int rose_nodes_get_info(char *, char **, off_t, int);
extern int rose_neigh_get_info(char *, char **, off_t, int);
extern int rose_routes_get_info(char *, char **, off_t, int);
extern void rose_rt_free(void); extern void rose_rt_free(void);
/* rose_subr.c */ /* rose_subr.c */
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <net/rose.h> #include <net/rose.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/arp.h> #include <net/arp.h>
...@@ -56,8 +57,8 @@ int sysctl_rose_link_fail_timeout = ROSE_DEFAULT_FAIL_TIMEOUT; ...@@ -56,8 +57,8 @@ int sysctl_rose_link_fail_timeout = ROSE_DEFAULT_FAIL_TIMEOUT;
int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC; int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC;
int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE; int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE;
static HLIST_HEAD(rose_list); HLIST_HEAD(rose_list);
static spinlock_t rose_list_lock = SPIN_LOCK_UNLOCKED; spinlock_t rose_list_lock = SPIN_LOCK_UNLOCKED;
static struct proto_ops rose_proto_ops; static struct proto_ops rose_proto_ops;
...@@ -66,7 +67,7 @@ ax25_address rose_callsign; ...@@ -66,7 +67,7 @@ ax25_address rose_callsign;
/* /*
* Convert a ROSE address into text. * Convert a ROSE address into text.
*/ */
char *rose2asc(rose_address *addr) const char *rose2asc(const rose_address *addr)
{ {
static char buffer[11]; static char buffer[11];
...@@ -1332,29 +1333,57 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1332,29 +1333,57 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return 0; return 0;
} }
static int rose_get_info(char *buffer, char **start, off_t offset, int length) #ifdef CONFIG_PROC_FS
static void *rose_info_start(struct seq_file *seq, loff_t *pos)
{ {
int i;
struct sock *s; struct sock *s;
struct hlist_node *node; struct hlist_node *node;
struct net_device *dev;
const char *devname, *callsign;
int len = 0;
off_t pos = 0;
off_t begin = 0;
spin_lock_bh(&rose_list_lock); spin_lock_bh(&rose_list_lock);
if (*pos == 0)
return ROSE_PROC_START;
len += sprintf(buffer, "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); i = 1;
sk_for_each(s, node, &rose_list) { sk_for_each(s, node, &rose_list) {
if (i == *pos)
return s;
++i;
}
return NULL;
}
static void *rose_info_next(struct seq_file *seq, void *v, loff_t *pos)
{
++*pos;
return (v == ROSE_PROC_START) ? sk_head(&rose_list)
: sk_next((struct sock *)v);
}
static void rose_info_stop(struct seq_file *seq, void *v)
{
spin_unlock_bh(&rose_list_lock);
}
static int rose_info_show(struct seq_file *seq, void *v)
{
if (v == ROSE_PROC_START)
seq_puts(seq,
"dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n");
else {
struct sock *s = v;
rose_cb *rose = rose_sk(s); rose_cb *rose = rose_sk(s);
const char *devname, *callsign;
const struct net_device *dev = rose->device;
if ((dev = rose->device) == NULL) if (!dev)
devname = "???"; devname = "???";
else else
devname = dev->name; devname = dev->name;
len += sprintf(buffer + len, "%-10s %-9s ", seq_printf(seq, "%-10s %-9s ",
rose2asc(&rose->dest_addr), rose2asc(&rose->dest_addr),
ax2asc(&rose->dest_call)); ax2asc(&rose->dest_call));
...@@ -1363,7 +1392,8 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1363,7 +1392,8 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
else else
callsign = ax2asc(&rose->source_call); callsign = ax2asc(&rose->source_call);
len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n", seq_printf(seq,
"%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
rose2asc(&rose->source_addr), rose2asc(&rose->source_addr),
callsign, callsign,
devname, devname,
...@@ -1383,27 +1413,32 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1383,27 +1413,32 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
atomic_read(&s->sk_wmem_alloc), atomic_read(&s->sk_wmem_alloc),
atomic_read(&s->sk_rmem_alloc), atomic_read(&s->sk_rmem_alloc),
s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L);
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
} }
if (pos > offset + length) return 0;
break; }
}
spin_unlock_bh(&rose_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
if (len > length) len = length; static struct seq_operations rose_info_seqops = {
.start = rose_info_start,
.next = rose_info_next,
.stop = rose_info_stop,
.show = rose_info_show,
};
return len; static int rose_info_open(struct inode *inode, struct file *file)
{
return seq_open(file, &rose_info_seqops);
} }
static struct file_operations rose_info_fops = {
.owner = THIS_MODULE,
.open = rose_info_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
#endif /* CONFIG_PROC_FS */
static struct net_proto_family rose_family_ops = { static struct net_proto_family rose_family_ops = {
.family = PF_ROSE, .family = PF_ROSE,
.create = rose_create, .create = rose_create,
...@@ -1499,10 +1534,11 @@ static int __init rose_proto_init(void) ...@@ -1499,10 +1534,11 @@ static int __init rose_proto_init(void)
rose_add_loopback_neigh(); rose_add_loopback_neigh();
proc_net_create("rose", 0, rose_get_info); proc_net_fops_create("rose", S_IRUGO, &rose_info_fops);
proc_net_create("rose_neigh", 0, rose_neigh_get_info); proc_net_fops_create("rose_neigh", S_IRUGO, &rose_neigh_fops);
proc_net_create("rose_nodes", 0, rose_nodes_get_info); proc_net_fops_create("rose_nodes", S_IRUGO, &rose_nodes_fops);
proc_net_create("rose_routes", 0, rose_routes_get_info); proc_net_fops_create("rose_routes", S_IRUGO, &rose_routes_fops);
return 0; return 0;
} }
module_init(rose_proto_init); module_init(rose_proto_init);
......
...@@ -35,12 +35,13 @@ ...@@ -35,12 +35,13 @@
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/init.h> #include <linux/init.h>
#include <net/rose.h> #include <net/rose.h>
#include <linux/seq_file.h>
static unsigned int rose_neigh_no = 1; static unsigned int rose_neigh_no = 1;
static struct rose_node *rose_node_list; static struct rose_node *rose_node_list;
static spinlock_t rose_node_list_lock = SPIN_LOCK_UNLOCKED; static spinlock_t rose_node_list_lock = SPIN_LOCK_UNLOCKED;
static struct rose_neigh *rose_neigh_list; struct rose_neigh *rose_neigh_list;
static spinlock_t rose_neigh_list_lock = SPIN_LOCK_UNLOCKED; static spinlock_t rose_neigh_list_lock = SPIN_LOCK_UNLOCKED;
static struct rose_route *rose_route_list; static struct rose_route *rose_route_list;
static spinlock_t rose_route_list_lock = SPIN_LOCK_UNLOCKED; static spinlock_t rose_route_list_lock = SPIN_LOCK_UNLOCKED;
...@@ -1066,72 +1067,124 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) ...@@ -1066,72 +1067,124 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
return res; return res;
} }
int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length) #ifdef CONFIG_PROC_FS
static void *rose_node_start(struct seq_file *seq, loff_t *pos)
{ {
struct rose_node *rose_node; struct rose_node *rose_node;
int len = 0; int i = 1;
off_t pos = 0;
off_t begin = 0;
int i;
spin_lock_bh(&rose_neigh_list_lock); spin_lock_bh(&rose_neigh_list_lock);
if (*pos == 0)
return ROSE_PROC_START;
for (rose_node = rose_node_list; rose_node && i < *pos;
rose_node = rose_node->next, ++i);
len += sprintf(buffer, "address mask n neigh neigh neigh\n"); return (i == *pos) ? rose_node : NULL;
}
static void *rose_node_next(struct seq_file *seq, void *v, loff_t *pos)
{
++*pos;
for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) { return (v == ROSE_PROC_START) ? rose_node_list
: ((struct rose_node *)v)->next;
}
static void rose_node_stop(struct seq_file *seq, void *v)
{
spin_unlock_bh(&rose_neigh_list_lock);
}
static int rose_node_show(struct seq_file *seq, void *v)
{
int i;
if (v == ROSE_PROC_START)
seq_puts(seq, "address mask n neigh neigh neigh\n");
else {
const struct rose_node *rose_node = v;
/* if (rose_node->loopback) { /* if (rose_node->loopback) {
len += sprintf(buffer + len, "%-10s %04d 1 loopback\n", seq_printf(seq, "%-10s %04d 1 loopback\n",
rose2asc(&rose_node->address), rose2asc(&rose_node->address),
rose_node->mask); rose_node->mask);
} else { */ } else { */
len += sprintf(buffer + len, "%-10s %04d %d", seq_printf(seq, "%-10s %04d %d",
rose2asc(&rose_node->address), rose2asc(&rose_node->address),
rose_node->mask, rose_node->mask,
rose_node->count); rose_node->count);
for (i = 0; i < rose_node->count; i++) for (i = 0; i < rose_node->count; i++)
len += sprintf(buffer + len, " %05d", seq_printf(seq, " %05d",
rose_node->neighbour[i]->number); rose_node->neighbour[i]->number);
len += sprintf(buffer + len, "\n"); seq_puts(seq, "\n");
/* } */ /* } */
}
return 0;
}
pos = begin + len; static struct seq_operations rose_node_seqops = {
.start = rose_node_start,
.next = rose_node_next,
.stop = rose_node_stop,
.show = rose_node_show,
};
if (pos < offset) { static int rose_nodes_open(struct inode *inode, struct file *file)
len = 0; {
begin = pos; return seq_open(file, &rose_node_seqops);
} }
if (pos > offset + length) struct file_operations rose_nodes_fops = {
break; .owner = THIS_MODULE,
} .open = rose_nodes_open,
spin_unlock_bh(&rose_neigh_list_lock); .read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static void *rose_neigh_start(struct seq_file *seq, loff_t *pos)
{
struct rose_neigh *rose_neigh;
int i = 1;
*start = buffer + (offset - begin); spin_lock_bh(&rose_neigh_list_lock);
len -= (offset - begin); if (*pos == 0)
return ROSE_PROC_START;
if (len > length) for (rose_neigh = rose_neigh_list; rose_neigh && i < *pos;
len = length; rose_neigh = rose_neigh->next, ++i);
return len; return (i == *pos) ? rose_neigh : NULL;
} }
int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length) static void *rose_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
{ {
struct rose_neigh *rose_neigh; ++*pos;
int len = 0;
off_t pos = 0;
off_t begin = 0;
int i;
spin_lock_bh(&rose_neigh_list_lock); return (v == ROSE_PROC_START) ? rose_neigh_list
: ((struct rose_neigh *)v)->next;
}
static void rose_neigh_stop(struct seq_file *seq, void *v)
{
spin_unlock_bh(&rose_neigh_list_lock);
}
len += sprintf(buffer, "addr callsign dev count use mode restart t0 tf digipeaters\n"); static int rose_neigh_show(struct seq_file *seq, void *v)
{
int i;
if (v == ROSE_PROC_START)
seq_puts(seq,
"addr callsign dev count use mode restart t0 tf digipeaters\n");
else {
struct rose_neigh *rose_neigh = v;
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
/* if (!rose_neigh->loopback) { */ /* if (!rose_neigh->loopback) { */
len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu", seq_printf(seq, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu",
rose_neigh->number, rose_neigh->number,
(rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(&rose_neigh->callsign), (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(&rose_neigh->callsign),
rose_neigh->dev ? rose_neigh->dev->name : "???", rose_neigh->dev ? rose_neigh->dev->name : "???",
...@@ -1144,87 +1197,118 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1144,87 +1197,118 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
if (rose_neigh->digipeat != NULL) { if (rose_neigh->digipeat != NULL) {
for (i = 0; i < rose_neigh->digipeat->ndigi; i++) for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i])); seq_printf(seq, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
} }
len += sprintf(buffer + len, "\n"); seq_puts(seq, "\n");
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
} }
return 0;
}
if (pos > offset + length)
break;
/* } */
}
spin_unlock_bh(&rose_neigh_list_lock); static struct seq_operations rose_neigh_seqops = {
.start = rose_neigh_start,
.next = rose_neigh_next,
.stop = rose_neigh_stop,
.show = rose_neigh_show,
};
*start = buffer + (offset - begin); static int rose_neigh_open(struct inode *inode, struct file *file)
len -= (offset - begin); {
return seq_open(file, &rose_neigh_seqops);
}
if (len > length) struct file_operations rose_neigh_fops = {
len = length; .owner = THIS_MODULE,
.open = rose_neigh_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
return len;
}
int rose_routes_get_info(char *buffer, char **start, off_t offset, int length) static void *rose_route_start(struct seq_file *seq, loff_t *pos)
{ {
struct rose_route *rose_route; struct rose_route *rose_route;
int len = 0; int i = 1;
off_t pos = 0;
off_t begin = 0;
spin_lock_bh(&rose_route_list_lock); spin_lock_bh(&rose_route_list_lock);
if (*pos == 0)
return ROSE_PROC_START;
for (rose_route = rose_route_list; rose_route && i < *pos;
rose_route = rose_route->next, ++i);
return (i == *pos) ? rose_route : NULL;
}
static void *rose_route_next(struct seq_file *seq, void *v, loff_t *pos)
{
++*pos;
return (v == ROSE_PROC_START) ? rose_route_list
: ((struct rose_route *)v)->next;
}
static void rose_route_stop(struct seq_file *seq, void *v)
{
spin_unlock_bh(&rose_route_list_lock);
}
len += sprintf(buffer, "lci address callsign neigh <-> lci address callsign neigh\n"); static int rose_route_show(struct seq_file *seq, void *v)
{
if (v == ROSE_PROC_START)
seq_puts(seq,
"lci address callsign neigh <-> lci address callsign neigh\n");
else {
struct rose_route *rose_route = v;
for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) { if (rose_route->neigh1)
if (rose_route->neigh1 != NULL) { seq_printf(seq,
len += sprintf(buffer + len, "%3.3X %-10s %-9s %05d ", "%3.3X %-10s %-9s %05d ",
rose_route->lci1, rose_route->lci1,
rose2asc(&rose_route->src_addr), rose2asc(&rose_route->src_addr),
ax2asc(&rose_route->src_call), ax2asc(&rose_route->src_call),
rose_route->neigh1->number); rose_route->neigh1->number);
} else { else
len += sprintf(buffer + len, "000 * * 00000 "); seq_puts(seq,
} "000 * * 00000 ");
if (rose_route->neigh2 != NULL) { if (rose_route->neigh2)
len += sprintf(buffer + len, "%3.3X %-10s %-9s %05d\n", seq_printf(seq,
"%3.3X %-10s %-9s %05d\n",
rose_route->lci2, rose_route->lci2,
rose2asc(&rose_route->dest_addr), rose2asc(&rose_route->dest_addr),
ax2asc(&rose_route->dest_call), ax2asc(&rose_route->dest_call),
rose_route->neigh2->number); rose_route->neigh2->number);
} else { else
len += sprintf(buffer + len, "000 * * 00000\n"); seq_puts(seq,
} "000 * * 00000\n");
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
break;
} }
return 0;
}
spin_unlock_bh(&rose_route_list_lock); static struct seq_operations rose_route_seqops = {
.start = rose_route_start,
.next = rose_route_next,
.stop = rose_route_stop,
.show = rose_route_show,
};
*start = buffer + (offset - begin); static int rose_route_open(struct inode *inode, struct file *file)
len -= (offset - begin); {
return seq_open(file, &rose_route_seqops);
}
if (len > length) struct file_operations rose_routes_fops = {
len = length; .owner = THIS_MODULE,
.open = rose_route_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
return len; #endif /* CONFIG_PROC_FS */
}
/* /*
* Release all memory associated with ROSE routing structures. * Release all memory associated with ROSE routing structures.
......
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