2005-04-17 02:20:36 +04:00
/*
* atalk_proc . c - proc support for Appletalk
*
* Copyright ( c ) Arnaldo Carvalho de Melo < acme @ conectiva . com . br >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation , version 2.
*/
# include <linux/init.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
2007-09-12 14:01:34 +04:00
# include <net/net_namespace.h>
2005-04-17 02:20:36 +04:00
# include <net/sock.h>
# include <linux/atalk.h>
static __inline__ struct atalk_iface * atalk_get_interface_idx ( loff_t pos )
{
struct atalk_iface * i ;
for ( i = atalk_interfaces ; pos & & i ; i = i - > next )
- - pos ;
return i ;
}
static void * atalk_seq_interface_start ( struct seq_file * seq , loff_t * pos )
2008-01-15 14:28:43 +03:00
__acquires ( atalk_interfaces_lock )
2005-04-17 02:20:36 +04:00
{
loff_t l = * pos ;
read_lock_bh ( & atalk_interfaces_lock ) ;
return l ? atalk_get_interface_idx ( - - l ) : SEQ_START_TOKEN ;
}
static void * atalk_seq_interface_next ( struct seq_file * seq , void * v , loff_t * pos )
{
struct atalk_iface * i ;
+ + * pos ;
if ( v = = SEQ_START_TOKEN ) {
i = NULL ;
if ( atalk_interfaces )
i = atalk_interfaces ;
goto out ;
}
i = v ;
i = i - > next ;
out :
return i ;
}
static void atalk_seq_interface_stop ( struct seq_file * seq , void * v )
2008-01-15 14:28:43 +03:00
__releases ( atalk_interfaces_lock )
2005-04-17 02:20:36 +04:00
{
read_unlock_bh ( & atalk_interfaces_lock ) ;
}
static int atalk_seq_interface_show ( struct seq_file * seq , void * v )
{
struct atalk_iface * iface ;
if ( v = = SEQ_START_TOKEN ) {
seq_puts ( seq , " Interface Address Networks "
" Status \n " ) ;
goto out ;
}
iface = v ;
seq_printf ( seq , " %-16s %04X:%02X %04X-%04X %d \n " ,
iface - > dev - > name , ntohs ( iface - > address . s_net ) ,
iface - > address . s_node , ntohs ( iface - > nets . nr_firstnet ) ,
ntohs ( iface - > nets . nr_lastnet ) , iface - > status ) ;
out :
return 0 ;
}
static __inline__ struct atalk_route * atalk_get_route_idx ( loff_t pos )
{
struct atalk_route * r ;
for ( r = atalk_routes ; pos & & r ; r = r - > next )
- - pos ;
return r ;
}
static void * atalk_seq_route_start ( struct seq_file * seq , loff_t * pos )
2008-01-15 14:28:43 +03:00
__acquires ( atalk_routes_lock )
2005-04-17 02:20:36 +04:00
{
loff_t l = * pos ;
read_lock_bh ( & atalk_routes_lock ) ;
return l ? atalk_get_route_idx ( - - l ) : SEQ_START_TOKEN ;
}
static void * atalk_seq_route_next ( struct seq_file * seq , void * v , loff_t * pos )
{
struct atalk_route * r ;
+ + * pos ;
if ( v = = SEQ_START_TOKEN ) {
r = NULL ;
if ( atalk_routes )
r = atalk_routes ;
goto out ;
}
r = v ;
r = r - > next ;
out :
return r ;
}
static void atalk_seq_route_stop ( struct seq_file * seq , void * v )
2008-01-15 14:28:43 +03:00
__releases ( atalk_routes_lock )
2005-04-17 02:20:36 +04:00
{
read_unlock_bh ( & atalk_routes_lock ) ;
}
static int atalk_seq_route_show ( struct seq_file * seq , void * v )
{
struct atalk_route * rt ;
if ( v = = SEQ_START_TOKEN ) {
seq_puts ( seq , " Target Router Flags Dev \n " ) ;
goto out ;
}
if ( atrtr_default . dev ) {
rt = & atrtr_default ;
seq_printf ( seq , " Default %04X:%02X %-4d %s \n " ,
ntohs ( rt - > gateway . s_net ) , rt - > gateway . s_node ,
rt - > flags , rt - > dev - > name ) ;
}
rt = v ;
seq_printf ( seq , " %04X:%02X %04X:%02X %-4d %s \n " ,
ntohs ( rt - > target . s_net ) , rt - > target . s_node ,
ntohs ( rt - > gateway . s_net ) , rt - > gateway . s_node ,
rt - > flags , rt - > dev - > name ) ;
out :
return 0 ;
}
static __inline__ struct sock * atalk_get_socket_idx ( loff_t pos )
{
struct sock * s ;
struct hlist_node * node ;
sk_for_each ( s , node , & atalk_sockets )
if ( ! pos - - )
goto found ;
s = NULL ;
found :
return s ;
}
static void * atalk_seq_socket_start ( struct seq_file * seq , loff_t * pos )
2008-01-15 14:28:43 +03:00
__acquires ( atalk_sockets_lock )
2005-04-17 02:20:36 +04:00
{
loff_t l = * pos ;
read_lock_bh ( & atalk_sockets_lock ) ;
return l ? atalk_get_socket_idx ( - - l ) : SEQ_START_TOKEN ;
}
static void * atalk_seq_socket_next ( struct seq_file * seq , void * v , loff_t * pos )
{
struct sock * i ;
+ + * pos ;
if ( v = = SEQ_START_TOKEN ) {
i = sk_head ( & atalk_sockets ) ;
goto out ;
}
i = sk_next ( v ) ;
out :
return i ;
}
static void atalk_seq_socket_stop ( struct seq_file * seq , void * v )
2008-01-15 14:28:43 +03:00
__releases ( atalk_sockets_lock )
2005-04-17 02:20:36 +04:00
{
read_unlock_bh ( & atalk_sockets_lock ) ;
}
static int atalk_seq_socket_show ( struct seq_file * seq , void * v )
{
struct sock * s ;
struct atalk_sock * at ;
if ( v = = SEQ_START_TOKEN ) {
seq_printf ( seq , " Type Local_addr Remote_addr Tx_queue "
" Rx_queue St UID \n " ) ;
goto out ;
}
s = v ;
at = at_sk ( s ) ;
seq_printf ( seq , " %02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X "
" %02X %d \n " ,
s - > sk_type , ntohs ( at - > src_net ) , at - > src_node , at - > src_port ,
ntohs ( at - > dest_net ) , at - > dest_node , at - > dest_port ,
atomic_read ( & s - > sk_wmem_alloc ) ,
atomic_read ( & s - > sk_rmem_alloc ) ,
s - > sk_state , SOCK_INODE ( s - > sk_socket ) - > i_uid ) ;
out :
return 0 ;
}
2007-07-11 10:07:31 +04:00
static const struct seq_operations atalk_seq_interface_ops = {
2005-04-17 02:20:36 +04:00
. start = atalk_seq_interface_start ,
. next = atalk_seq_interface_next ,
. stop = atalk_seq_interface_stop ,
. show = atalk_seq_interface_show ,
} ;
2007-07-11 10:07:31 +04:00
static const struct seq_operations atalk_seq_route_ops = {
2005-04-17 02:20:36 +04:00
. start = atalk_seq_route_start ,
. next = atalk_seq_route_next ,
. stop = atalk_seq_route_stop ,
. show = atalk_seq_route_show ,
} ;
2007-07-11 10:07:31 +04:00
static const struct seq_operations atalk_seq_socket_ops = {
2005-04-17 02:20:36 +04:00
. start = atalk_seq_socket_start ,
. next = atalk_seq_socket_next ,
. stop = atalk_seq_socket_stop ,
. show = atalk_seq_socket_show ,
} ;
static int atalk_seq_interface_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & atalk_seq_interface_ops ) ;
}
static int atalk_seq_route_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & atalk_seq_route_ops ) ;
}
static int atalk_seq_socket_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & atalk_seq_socket_ops ) ;
}
2007-02-12 11:55:35 +03:00
static const struct file_operations atalk_seq_interface_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = atalk_seq_interface_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release ,
} ;
2007-02-12 11:55:35 +03:00
static const struct file_operations atalk_seq_route_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = atalk_seq_route_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release ,
} ;
2007-02-12 11:55:35 +03:00
static const struct file_operations atalk_seq_socket_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = atalk_seq_socket_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release ,
} ;
static struct proc_dir_entry * atalk_proc_dir ;
int __init atalk_proc_init ( void )
{
struct proc_dir_entry * p ;
int rc = - ENOMEM ;
2007-09-12 14:01:34 +04:00
atalk_proc_dir = proc_mkdir ( " atalk " , init_net . proc_net ) ;
2005-04-17 02:20:36 +04:00
if ( ! atalk_proc_dir )
goto out ;
atalk_proc_dir - > owner = THIS_MODULE ;
2008-02-28 23:53:32 +03:00
p = proc_create ( " interface " , S_IRUGO , atalk_proc_dir ,
& atalk_seq_interface_fops ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
goto out_interface ;
2008-02-28 23:53:32 +03:00
p = proc_create ( " route " , S_IRUGO , atalk_proc_dir ,
& atalk_seq_route_fops ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
goto out_route ;
2008-02-28 23:53:32 +03:00
p = proc_create ( " socket " , S_IRUGO , atalk_proc_dir ,
& atalk_seq_socket_fops ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
goto out_socket ;
2008-02-28 23:53:32 +03:00
p = proc_create ( " arp " , S_IRUGO , atalk_proc_dir , & atalk_seq_arp_fops ) ;
2007-02-09 17:24:27 +03:00
if ( ! p )
2005-04-17 02:20:36 +04:00
goto out_arp ;
rc = 0 ;
out :
return rc ;
out_arp :
remove_proc_entry ( " socket " , atalk_proc_dir ) ;
out_socket :
remove_proc_entry ( " route " , atalk_proc_dir ) ;
out_route :
remove_proc_entry ( " interface " , atalk_proc_dir ) ;
out_interface :
2007-09-12 14:01:34 +04:00
remove_proc_entry ( " atalk " , init_net . proc_net ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
void __exit atalk_proc_exit ( void )
{
remove_proc_entry ( " interface " , atalk_proc_dir ) ;
remove_proc_entry ( " route " , atalk_proc_dir ) ;
remove_proc_entry ( " socket " , atalk_proc_dir ) ;
remove_proc_entry ( " arp " , atalk_proc_dir ) ;
2007-09-12 14:01:34 +04:00
remove_proc_entry ( " atalk " , init_net . proc_net ) ;
2005-04-17 02:20:36 +04:00
}