2005-04-17 02:20:36 +04:00
/*
* X .25 Packet Layer release 002
*
* This is ALPHA test software . This code may break your machine ,
* randomly fail to work with new releases , misbehave and / or generally
2007-02-09 17:25:27 +03:00
* screw up . It might even work .
2005-04-17 02:20:36 +04:00
*
* This code REQUIRES 2.4 with seq_file support
*
* This module :
* This module 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 ; either version
* 2 of the License , or ( at your option ) any later version .
*
* History
* 2002 / 10 / 06 Arnaldo Carvalho de Melo seq_file support
*/
# include <linux/init.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <net/sock.h>
# include <net/x25.h>
# ifdef CONFIG_PROC_FS
static __inline__ struct x25_route * x25_get_route_idx ( loff_t pos )
{
struct list_head * route_entry ;
struct x25_route * rt = NULL ;
list_for_each ( route_entry , & x25_route_list ) {
rt = list_entry ( route_entry , struct x25_route , node ) ;
if ( ! pos - - )
goto found ;
}
rt = NULL ;
found :
return rt ;
}
static void * x25_seq_route_start ( struct seq_file * seq , loff_t * pos )
{
loff_t l = * pos ;
read_lock_bh ( & x25_route_list_lock ) ;
return l ? x25_get_route_idx ( - - l ) : SEQ_START_TOKEN ;
}
static void * x25_seq_route_next ( struct seq_file * seq , void * v , loff_t * pos )
{
struct x25_route * rt ;
+ + * pos ;
if ( v = = SEQ_START_TOKEN ) {
rt = NULL ;
if ( ! list_empty ( & x25_route_list ) )
rt = list_entry ( x25_route_list . next ,
struct x25_route , node ) ;
goto out ;
}
rt = v ;
if ( rt - > node . next ! = & x25_route_list )
rt = list_entry ( rt - > node . next , struct x25_route , node ) ;
2007-02-09 17:25:27 +03:00
else
2005-04-17 02:20:36 +04:00
rt = NULL ;
out :
return rt ;
}
static void x25_seq_route_stop ( struct seq_file * seq , void * v )
{
read_unlock_bh ( & x25_route_list_lock ) ;
}
static int x25_seq_route_show ( struct seq_file * seq , void * v )
{
struct x25_route * rt ;
if ( v = = SEQ_START_TOKEN ) {
seq_puts ( seq , " Address Digits Device \n " ) ;
goto out ;
}
rt = v ;
seq_printf ( seq , " %-15s %-6d %-5s \n " ,
rt - > address . x25_addr , rt - > sigdigits ,
rt - > dev ? rt - > dev - > name : " ??? " ) ;
out :
return 0 ;
2007-02-09 17:25:27 +03:00
}
2005-04-17 02:20:36 +04:00
static __inline__ struct sock * x25_get_socket_idx ( loff_t pos )
{
struct sock * s ;
struct hlist_node * node ;
sk_for_each ( s , node , & x25_list )
if ( ! pos - - )
goto found ;
s = NULL ;
found :
return s ;
}
static void * x25_seq_socket_start ( struct seq_file * seq , loff_t * pos )
{
loff_t l = * pos ;
read_lock_bh ( & x25_list_lock ) ;
return l ? x25_get_socket_idx ( - - l ) : SEQ_START_TOKEN ;
}
static void * x25_seq_socket_next ( struct seq_file * seq , void * v , loff_t * pos )
{
struct sock * s ;
+ + * pos ;
if ( v = = SEQ_START_TOKEN ) {
s = sk_head ( & x25_list ) ;
goto out ;
}
s = sk_next ( v ) ;
out :
return s ;
}
static void x25_seq_socket_stop ( struct seq_file * seq , void * v )
{
read_unlock_bh ( & x25_list_lock ) ;
}
static int x25_seq_socket_show ( struct seq_file * seq , void * v )
{
struct sock * s ;
struct x25_sock * x25 ;
struct net_device * dev ;
const char * devname ;
if ( v = = SEQ_START_TOKEN ) {
seq_printf ( seq , " dest_addr src_addr dev lci st vs vr "
" va t t2 t21 t22 t23 Snd-Q Rcv-Q inode \n " ) ;
goto out ;
}
s = v ;
x25 = x25_sk ( s ) ;
if ( ! x25 - > neighbour | | ( dev = x25 - > neighbour - > dev ) = = NULL )
devname = " ??? " ;
else
devname = x25 - > neighbour - > dev - > name ;
seq_printf ( seq , " %-10s %-10s %-5s %3.3X %d %d %d %d %3lu %3lu "
" %3lu %3lu %3lu %5d %5d %ld \n " ,
! x25 - > dest_addr . x25_addr [ 0 ] ? " * " : x25 - > dest_addr . x25_addr ,
! x25 - > source_addr . x25_addr [ 0 ] ? " * " : x25 - > source_addr . x25_addr ,
devname , x25 - > lci & 0x0FFF , x25 - > state , x25 - > vs , x25 - > vr ,
x25 - > va , x25_display_timer ( s ) / HZ , x25 - > t2 / HZ ,
x25 - > t21 / HZ , x25 - > t22 / HZ , x25 - > t23 / HZ ,
atomic_read ( & s - > sk_wmem_alloc ) ,
atomic_read ( & s - > sk_rmem_alloc ) ,
s - > sk_socket ? SOCK_INODE ( s - > sk_socket ) - > i_ino : 0L ) ;
out :
return 0 ;
2007-02-09 17:25:27 +03:00
}
2005-04-17 02:20:36 +04:00
2007-02-09 00:35:18 +03:00
static __inline__ struct x25_forward * x25_get_forward_idx ( loff_t pos )
{
struct x25_forward * f ;
struct list_head * entry ;
list_for_each ( entry , & x25_forward_list ) {
f = list_entry ( entry , struct x25_forward , node ) ;
if ( ! pos - - )
goto found ;
}
f = NULL ;
found :
return f ;
}
static void * x25_seq_forward_start ( struct seq_file * seq , loff_t * pos )
{
loff_t l = * pos ;
read_lock_bh ( & x25_forward_list_lock ) ;
return l ? x25_get_forward_idx ( - - l ) : SEQ_START_TOKEN ;
}
static void * x25_seq_forward_next ( struct seq_file * seq , void * v , loff_t * pos )
{
struct x25_forward * f ;
+ + * pos ;
if ( v = = SEQ_START_TOKEN ) {
f = NULL ;
if ( ! list_empty ( & x25_forward_list ) )
f = list_entry ( x25_forward_list . next ,
struct x25_forward , node ) ;
goto out ;
}
f = v ;
if ( f - > node . next ! = & x25_forward_list )
f = list_entry ( f - > node . next , struct x25_forward , node ) ;
else
f = NULL ;
out :
return f ;
}
static void x25_seq_forward_stop ( struct seq_file * seq , void * v )
{
read_unlock_bh ( & x25_forward_list_lock ) ;
}
static int x25_seq_forward_show ( struct seq_file * seq , void * v )
{
struct x25_forward * f ;
if ( v = = SEQ_START_TOKEN ) {
seq_printf ( seq , " lci dev1 dev2 \n " ) ;
goto out ;
}
f = v ;
seq_printf ( seq , " %d %-10s %-10s \n " ,
f - > lci , f - > dev1 - > name , f - > dev2 - > name ) ;
out :
return 0 ;
}
2007-07-11 10:07:31 +04:00
static const struct seq_operations x25_seq_route_ops = {
2005-04-17 02:20:36 +04:00
. start = x25_seq_route_start ,
. next = x25_seq_route_next ,
. stop = x25_seq_route_stop ,
. show = x25_seq_route_show ,
} ;
2007-07-11 10:07:31 +04:00
static const struct seq_operations x25_seq_socket_ops = {
2005-04-17 02:20:36 +04:00
. start = x25_seq_socket_start ,
. next = x25_seq_socket_next ,
. stop = x25_seq_socket_stop ,
. show = x25_seq_socket_show ,
} ;
2007-07-11 10:07:31 +04:00
static const struct seq_operations x25_seq_forward_ops = {
2007-02-09 00:35:18 +03:00
. start = x25_seq_forward_start ,
. next = x25_seq_forward_next ,
. stop = x25_seq_forward_stop ,
. show = x25_seq_forward_show ,
} ;
2005-04-17 02:20:36 +04:00
static int x25_seq_socket_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & x25_seq_socket_ops ) ;
}
static int x25_seq_route_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & x25_seq_route_ops ) ;
}
2007-02-09 00:35:18 +03:00
static int x25_seq_forward_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & x25_seq_forward_ops ) ;
}
2007-02-12 11:55:36 +03:00
static const struct file_operations x25_seq_socket_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = x25_seq_socket_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release ,
} ;
2007-02-12 11:55:36 +03:00
static const struct file_operations x25_seq_route_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = x25_seq_route_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release ,
} ;
2007-02-09 00:35:18 +03:00
static struct file_operations x25_seq_forward_fops = {
. owner = THIS_MODULE ,
. open = x25_seq_forward_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release ,
} ;
2005-04-17 02:20:36 +04:00
static struct proc_dir_entry * x25_proc_dir ;
int __init x25_proc_init ( void )
{
struct proc_dir_entry * p ;
int rc = - ENOMEM ;
x25_proc_dir = proc_mkdir ( " x25 " , proc_net ) ;
if ( ! x25_proc_dir )
goto out ;
p = create_proc_entry ( " route " , S_IRUGO , x25_proc_dir ) ;
if ( ! p )
goto out_route ;
p - > proc_fops = & x25_seq_route_fops ;
p = create_proc_entry ( " socket " , S_IRUGO , x25_proc_dir ) ;
if ( ! p )
goto out_socket ;
p - > proc_fops = & x25_seq_socket_fops ;
2007-02-09 00:35:18 +03:00
p = create_proc_entry ( " forward " , S_IRUGO , x25_proc_dir ) ;
if ( ! p )
goto out_forward ;
p - > proc_fops = & x25_seq_forward_fops ;
2005-04-17 02:20:36 +04:00
rc = 0 ;
2007-02-09 00:35:18 +03:00
2005-04-17 02:20:36 +04:00
out :
return rc ;
2007-02-09 00:35:18 +03:00
out_forward :
remove_proc_entry ( " socket " , x25_proc_dir ) ;
2005-04-17 02:20:36 +04:00
out_socket :
remove_proc_entry ( " route " , x25_proc_dir ) ;
out_route :
remove_proc_entry ( " x25 " , proc_net ) ;
goto out ;
}
void __exit x25_proc_exit ( void )
{
2007-02-09 00:35:18 +03:00
remove_proc_entry ( " forward " , x25_proc_dir ) ;
2005-04-17 02:20:36 +04:00
remove_proc_entry ( " route " , x25_proc_dir ) ;
remove_proc_entry ( " socket " , x25_proc_dir ) ;
remove_proc_entry ( " x25 " , proc_net ) ;
}
# else /* CONFIG_PROC_FS */
int __init x25_proc_init ( void )
{
return 0 ;
}
void __exit x25_proc_exit ( void )
{
}
# endif /* CONFIG_PROC_FS */