o ipv4: convert /proc/net/arp to seq_file

parent 56338b9f
......@@ -18,6 +18,7 @@ extern void arp_send(int type, int ptype, u32 dest_ip,
extern int arp_bind_neighbour(struct dst_entry *dst);
extern int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir);
extern void arp_ifdown(struct net_device *dev);
extern unsigned arp_state_to_flags(struct neighbour *neigh);
extern struct neigh_ops arp_broken_ops;
......
......@@ -66,6 +66,8 @@
* Alexey Kuznetsov: new arp state machine;
* now it is in net/core/neighbour.c.
* Krzysztof Halasa: Added Frame Relay ARP support.
* Arnaldo C. Melo : move proc stuff to seq_file and
* net/ipv4/ip_proc.c
*/
#include <linux/types.h>
......@@ -85,7 +87,6 @@
#include <linux/if_arp.h>
#include <linux/trdevice.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
#ifdef CONFIG_SYSCTL
......@@ -851,7 +852,7 @@ int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
}
/*
* User level interface (ioctl, /proc)
* User level interface (ioctl)
*/
/*
......@@ -918,7 +919,7 @@ int arp_req_set(struct arpreq *r, struct net_device * dev)
return err;
}
static unsigned arp_state_to_flags(struct neighbour *neigh)
unsigned arp_state_to_flags(struct neighbour *neigh)
{
unsigned flags = 0;
if (neigh->nud_state&NUD_PERMANENT)
......@@ -1066,111 +1067,6 @@ int arp_ioctl(unsigned int cmd, void *arg)
return err;
}
/*
* Write the contents of the ARP cache to a PROCfs file.
*/
#ifndef CONFIG_PROC_FS
static int arp_get_info(char *buffer, char **start, off_t offset, int length)
{
return 0;
}
#else
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
static char *ax2asc2(ax25_address *a, char *buf);
#endif
#define HBUFFERLEN 30
static int arp_get_info(char *buffer, char **start, off_t offset, int length)
{
char hbuffer[HBUFFERLEN];
int i,j,k;
const char hexbuf[] = "0123456789ABCDEF";
int size = sprintf(buffer, "IP address HW type Flags "
"HW address Mask Device\n");
int len = size;
off_t pos = size;
for (i = 0; i <= NEIGH_HASHMASK; i++) {
struct neighbour *n;
read_lock_bh(&arp_tbl.lock);
for (n = arp_tbl.hash_buckets[i]; n; n = n->next) {
char tbuf[16];
struct net_device *dev = n->dev;
int hatype = dev->type;
/* Do not confuse users "arp -a" with magic entries */
if (!(n->nud_state & ~NUD_NOARP))
continue;
read_lock(&n->lock);
/* Convert hardware address to XX:XX:XX:XX ... form. */
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM)
ax2asc2((ax25_address *)n->ha, hbuffer);
else {
#endif
for (k = 0, j = 0; k < HBUFFERLEN - 3 &&
j < dev->addr_len; j++) {
hbuffer[k++] = hexbuf[(n->ha[j] >> 4) & 15];
hbuffer[k++] = hexbuf[n->ha[j] & 15];
hbuffer[k++] = ':';
}
hbuffer[--k] = 0;
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
}
#endif
sprintf(tbuf, "%u.%u.%u.%u",
NIPQUAD(*(u32*)n->primary_key));
size = sprintf(buffer + len, "%-16s 0x%-10x0x%-10x%s"
" * %s\n",
tbuf, hatype, arp_state_to_flags(n),
hbuffer, dev->name);
read_unlock(&n->lock);
len += size;
pos += size;
if (pos <= offset)
len = 0;
if (pos >= offset + length) {
read_unlock_bh(&arp_tbl.lock);
goto done;
}
}
read_unlock_bh(&arp_tbl.lock);
}
for (i = 0; i <= PNEIGH_HASHMASK; i++) {
struct pneigh_entry *n;
for (n = arp_tbl.phash_buckets[i]; n; n = n->next) {
struct net_device *dev = n->dev;
int hatype = dev ? dev->type : 0;
char tbuf[16];
sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key));
size = sprintf(buffer + len, "%-16s 0x%-10x0x%-10x%s"
" * %s\n",
tbuf, hatype, ATF_PUBL | ATF_PERM,
"00:00:00:00:00:00",
dev ? dev->name : "*");
len += size;
pos += size;
if (pos <= offset)
len = 0;
if (pos >= offset+length)
goto done;
}
}
done: *start = buffer + len - (pos - offset); /* Start of wanted data */
len = pos - offset; /* Start slop */
if (len > length)
len = length; /* Ending slop */
if (len < 0)
len = 0;
return len;
}
#endif
/* Note, that it is not on notifier chain.
It is necessary, that this routine was called after route cache will be
flushed.
......@@ -1191,54 +1087,13 @@ static struct packet_type arp_packet_type = {
.data = (void*) 1, /* understand shared skbs */
};
void __init arp_init (void)
void __init arp_init(void)
{
neigh_table_init(&arp_tbl);
dev_add_pack(&arp_packet_type);
proc_net_create ("arp", 0, arp_get_info);
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
NET_IPV4_NEIGH, "ipv4");
#endif
}
#ifdef CONFIG_PROC_FS
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
/*
* ax25 -> ASCII conversion
*/
char *ax2asc2(ax25_address *a, char *buf)
{
char c, *s;
int n;
for (n = 0, s = buf; n < 6; n++) {
c = (a->ax25_call[n] >> 1) & 0x7F;
if (c != ' ') *s++ = c;
}
*s++ = '-';
if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
*s++ = '1';
n -= 10;
}
*s++ = n + '0';
*s++ = '\0';
if (*buf == '\0' || *buf == '-')
return "*";
return buf;
}
#endif
#endif
......@@ -15,6 +15,10 @@
#include <linux/config.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <net/neighbour.h>
#include <net/arp.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
extern int raw_get_info(char *, char **, off_t, int);
......@@ -25,8 +29,158 @@ extern int tcp_get_info(char *, char **, off_t, int);
extern int udp_get_info(char *, char **, off_t, int);
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_AX25
/*
* ax25 -> ASCII conversion
*/
char *ax2asc2(ax25_address *a, char *buf)
{
char c, *s;
int n;
for (n = 0, s = buf; n < 6; n++) {
c = (a->ax25_call[n] >> 1) & 0x7F;
if (c != ' ') *s++ = c;
}
*s++ = '-';
if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
*s++ = '1';
n -= 10;
}
*s++ = n + '0';
*s++ = '\0';
if (*buf == '\0' || *buf == '-')
return "*";
return buf;
}
#endif /* CONFIG_AX25 */
static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
{
return (void *)(unsigned long)++*pos;
}
static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
return (void *)(unsigned long)((++*pos) >=
(NEIGH_HASHMASK +
PNEIGH_HASHMASK - 1) ? 0 : *pos);
}
static void arp_seq_stop(struct seq_file *seq, void *v)
{
}
#define HBUFFERLEN 30
static __inline__ void arp_format_neigh_table(struct seq_file *seq, int entry)
{
char hbuffer[HBUFFERLEN];
const char hexbuf[] = "0123456789ABCDEF";
struct neighbour *n;
int k, j;
read_lock_bh(&arp_tbl.lock);
for (n = arp_tbl.hash_buckets[entry]; n; n = n->next) {
char tbuf[16];
struct net_device *dev = n->dev;
int hatype = dev->type;
/* Do not confuse users "arp -a" with magic entries */
if (!(n->nud_state & ~NUD_NOARP))
continue;
read_lock(&n->lock);
/* Convert hardware address to XX:XX:XX:XX ... form. */
#ifdef CONFIG_AX25
if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM)
ax2asc2((ax25_address *)n->ha, hbuffer);
else {
#endif
for (k = 0, j = 0; k < HBUFFERLEN - 3 &&
j < dev->addr_len; j++) {
hbuffer[k++] = hexbuf[(n->ha[j] >> 4) & 15];
hbuffer[k++] = hexbuf[n->ha[j] & 15];
hbuffer[k++] = ':';
}
hbuffer[--k] = 0;
#ifdef CONFIG_AX25
}
#endif
sprintf(tbuf, "%u.%u.%u.%u",
NIPQUAD(*(u32*)n->primary_key));
seq_printf(seq, "%-16s 0x%-10x0x%-10x%s"
" * %s\n",
tbuf, hatype, arp_state_to_flags(n),
hbuffer, dev->name);
read_unlock(&n->lock);
}
read_unlock_bh(&arp_tbl.lock);
}
static __inline__ void arp_format_pneigh_table(struct seq_file *seq, int entry)
{
struct pneigh_entry *n;
for (n = arp_tbl.phash_buckets[entry]; n; n = n->next) {
struct net_device *dev = n->dev;
int hatype = dev ? dev->type : 0;
char tbuf[16];
sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key));
seq_printf(seq, "%-16s 0x%-10x0x%-10x%s"
" * %s\n",
tbuf, hatype, ATF_PUBL | ATF_PERM,
"00:00:00:00:00:00",
dev ? dev->name : "*");
}
}
static int arp_seq_show(struct seq_file *seq, void *v)
{
unsigned long l = (unsigned long)v - 1;
if (!l)
seq_puts(seq, "IP address HW type Flags "
"HW address Mask Device\n");
if (l <= NEIGH_HASHMASK)
arp_format_neigh_table(seq, l);
else
arp_format_pneigh_table(seq, l - NEIGH_HASHMASK);
return 0;
}
struct seq_operations arp_seq_ops = {
.start = arp_seq_start,
.next = arp_seq_next,
.stop = arp_seq_stop,
.show = arp_seq_show,
};
static int arp_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &arp_seq_ops);
}
static struct file_operations arp_seq_fops = {
.open = arp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
int __init ipv4_proc_init(void)
{
struct proc_dir_entry *p;
int rc = 0;
if (!proc_net_create("raw", 0, raw_get_info))
......@@ -46,8 +200,15 @@ int __init ipv4_proc_init(void)
if (!proc_net_create("udp", 0, udp_get_info))
goto out_udp;
p = create_proc_entry("arp", S_IRUGO, proc_net);
if (!p)
goto out_arp;
p->proc_fops = &arp_seq_fops;
out:
return rc;
out_arp:
proc_net_remove("udp");
out_udp:
proc_net_remove("tcp");
out_tcp:
......
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