2005-04-17 02:20:36 +04:00
/*
* DECnet An implementation of the DECnet protocol suite for the LINUX
* operating system . DECnet is implemented using the BSD Socket
* interface as the means of communication with the user level .
*
* DECnet sysctl support functions
*
* Author : Steve Whitehouse < SteveW @ ACM . org >
*
*
* Changes :
* Steve Whitehouse - C99 changes and default device handling
2005-12-06 00:42:06 +03:00
* Steve Whitehouse - Memory buffer settings , like the tcp ones
2005-04-17 02:20:36 +04:00
*
*/
# include <linux/mm.h>
# include <linux/sysctl.h>
# include <linux/fs.h>
# include <linux/netdevice.h>
# include <linux/string.h>
# include <net/neighbour.h>
# include <net/dst.h>
# include <net/flow.h>
# include <asm/uaccess.h>
# include <net/dn.h>
# include <net/dn_dev.h>
# include <net/dn_route.h>
int decnet_debug_level ;
int decnet_time_wait = 30 ;
int decnet_dn_count = 1 ;
int decnet_di_count = 3 ;
int decnet_dr_count = 3 ;
int decnet_log_martians = 1 ;
int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW ;
2005-12-06 00:42:06 +03:00
/* Reasonable defaults, I hope, based on tcp's defaults */
2010-11-10 02:24:26 +03:00
long sysctl_decnet_mem [ 3 ] = { 768 < < 3 , 1024 < < 3 , 1536 < < 3 } ;
2005-12-06 00:42:06 +03:00
int sysctl_decnet_wmem [ 3 ] = { 4 * 1024 , 16 * 1024 , 128 * 1024 } ;
int sysctl_decnet_rmem [ 3 ] = { 4 * 1024 , 87380 , 87380 * 2 } ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_SYSCTL
extern int decnet_dst_gc_interval ;
static int min_decnet_time_wait [ ] = { 5 } ;
static int max_decnet_time_wait [ ] = { 600 } ;
static int min_state_count [ ] = { 1 } ;
static int max_state_count [ ] = { NSP_MAXRXTSHIFT } ;
static int min_decnet_dst_gc_interval [ ] = { 1 } ;
static int max_decnet_dst_gc_interval [ ] = { 60 } ;
static int min_decnet_no_fc_max_cwnd [ ] = { NSP_MIN_WINDOW } ;
static int max_decnet_no_fc_max_cwnd [ ] = { NSP_MAX_WINDOW } ;
static char node_name [ 7 ] = " ??? " ;
static struct ctl_table_header * dn_table_header = NULL ;
/*
* ctype . h : - )
*/
# define ISNUM(x) (((x) >= '0') && ((x) <= '9'))
# define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z'))
# define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z'))
# define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
# define INVALID_END_CHAR(x) (ISNUM(x) || ISALPHA(x))
static void strip_it ( char * str )
{
for ( ; ; ) {
2011-07-01 13:43:03 +04:00
switch ( * str ) {
case ' ' :
case ' \n ' :
case ' \r ' :
case ' : ' :
* str = 0 ;
/* Fallthrough */
case 0 :
return ;
2005-04-17 02:20:36 +04:00
}
str + + ;
}
}
/*
* Simple routine to parse an ascii DECnet address
* into a network order address .
*/
2006-03-21 09:42:39 +03:00
static int parse_addr ( __le16 * addr , char * str )
2005-04-17 02:20:36 +04:00
{
2006-03-21 09:42:39 +03:00
__u16 area , node ;
2005-04-17 02:20:36 +04:00
while ( * str & & ! ISNUM ( * str ) ) str + + ;
if ( * str = = 0 )
return - 1 ;
area = ( * str + + - ' 0 ' ) ;
if ( ISNUM ( * str ) ) {
area * = 10 ;
area + = ( * str + + - ' 0 ' ) ;
}
if ( * str + + ! = ' . ' )
return - 1 ;
if ( ! ISNUM ( * str ) )
return - 1 ;
node = * str + + - ' 0 ' ;
if ( ISNUM ( * str ) ) {
node * = 10 ;
node + = ( * str + + - ' 0 ' ) ;
}
if ( ISNUM ( * str ) ) {
node * = 10 ;
node + = ( * str + + - ' 0 ' ) ;
}
if ( ISNUM ( * str ) ) {
node * = 10 ;
node + = ( * str + + - ' 0 ' ) ;
}
if ( ( node > 1023 ) | | ( area > 63 ) )
return - 1 ;
if ( INVALID_END_CHAR ( * str ) )
return - 1 ;
2008-11-27 11:12:47 +03:00
* addr = cpu_to_le16 ( ( area < < 10 ) | node ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-02-09 17:24:40 +03:00
static int dn_node_address_handler ( ctl_table * table , int write ,
2005-04-17 02:20:36 +04:00
void __user * buffer ,
size_t * lenp , loff_t * ppos )
{
char addr [ DN_ASCBUF_LEN ] ;
size_t len ;
2006-03-21 09:42:39 +03:00
__le16 dnaddr ;
2005-04-17 02:20:36 +04:00
if ( ! * lenp | | ( * ppos & & ! write ) ) {
* lenp = 0 ;
return 0 ;
}
if ( write ) {
2009-02-25 13:32:39 +03:00
len = ( * lenp < DN_ASCBUF_LEN ) ? * lenp : ( DN_ASCBUF_LEN - 1 ) ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( addr , buffer , len ) )
return - EFAULT ;
addr [ len ] = 0 ;
strip_it ( addr ) ;
if ( parse_addr ( & dnaddr , addr ) )
return - EINVAL ;
dn_dev_devices_off ( ) ;
decnet_address = dnaddr ;
dn_dev_devices_on ( ) ;
* ppos + = len ;
return 0 ;
}
2008-11-27 11:12:47 +03:00
dn_addr2asc ( le16_to_cpu ( decnet_address ) , addr ) ;
2005-04-17 02:20:36 +04:00
len = strlen ( addr ) ;
addr [ len + + ] = ' \n ' ;
if ( len > * lenp ) len = * lenp ;
if ( copy_to_user ( buffer , addr , len ) )
return - EFAULT ;
* lenp = len ;
* ppos + = len ;
return 0 ;
}
2007-02-09 17:24:40 +03:00
static int dn_def_dev_handler ( ctl_table * table , int write ,
2005-04-17 02:20:36 +04:00
void __user * buffer ,
size_t * lenp , loff_t * ppos )
{
size_t len ;
struct net_device * dev ;
char devname [ 17 ] ;
if ( ! * lenp | | ( * ppos & & ! write ) ) {
* lenp = 0 ;
return 0 ;
}
if ( write ) {
if ( * lenp > 16 )
return - E2BIG ;
if ( copy_from_user ( devname , buffer , * lenp ) )
return - EFAULT ;
devname [ * lenp ] = 0 ;
strip_it ( devname ) ;
2007-09-17 22:56:21 +04:00
dev = dev_get_by_name ( & init_net , devname ) ;
2005-04-17 02:20:36 +04:00
if ( dev = = NULL )
return - ENODEV ;
if ( dev - > dn_ptr = = NULL ) {
dev_put ( dev ) ;
return - ENODEV ;
}
if ( dn_dev_set_default ( dev , 1 ) ) {
dev_put ( dev ) ;
return - ENODEV ;
}
* ppos + = * lenp ;
return 0 ;
}
dev = dn_dev_get_default ( ) ;
if ( dev = = NULL ) {
* lenp = 0 ;
return 0 ;
}
strcpy ( devname , dev - > name ) ;
dev_put ( dev ) ;
len = strlen ( devname ) ;
devname [ len + + ] = ' \n ' ;
if ( len > * lenp ) len = * lenp ;
if ( copy_to_user ( buffer , devname , len ) )
return - EFAULT ;
* lenp = len ;
* ppos + = len ;
return 0 ;
}
static ctl_table dn_table [ ] = {
{
2007-02-09 17:24:40 +03:00
. procname = " node_address " ,
. maxlen = 7 ,
. mode = 0644 ,
2005-04-17 02:20:36 +04:00
. proc_handler = dn_node_address_handler ,
} ,
{
. procname = " node_name " ,
2007-02-09 17:24:40 +03:00
. data = node_name ,
2005-04-17 02:20:36 +04:00
. maxlen = 7 ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dostring ,
2005-04-17 02:20:36 +04:00
} ,
{
2007-02-09 17:24:40 +03:00
. procname = " default_device " ,
. maxlen = 16 ,
2005-04-17 02:20:36 +04:00
. mode = 0644 ,
. proc_handler = dn_def_dev_handler ,
} ,
{
. procname = " time_wait " ,
. data = & decnet_time_wait ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dointvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = & min_decnet_time_wait ,
. extra2 = & max_decnet_time_wait
} ,
{
. procname = " dn_count " ,
. data = & decnet_dn_count ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dointvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = & min_state_count ,
. extra2 = & max_state_count
} ,
{
. procname = " di_count " ,
. data = & decnet_di_count ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dointvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = & min_state_count ,
. extra2 = & max_state_count
} ,
{
. procname = " dr_count " ,
. data = & decnet_dr_count ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dointvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = & min_state_count ,
. extra2 = & max_state_count
} ,
{
. procname = " dst_gc_interval " ,
. data = & decnet_dst_gc_interval ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dointvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = & min_decnet_dst_gc_interval ,
. extra2 = & max_decnet_dst_gc_interval
} ,
{
. procname = " no_fc_max_cwnd " ,
. data = & decnet_no_fc_max_cwnd ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dointvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = & min_decnet_no_fc_max_cwnd ,
. extra2 = & max_decnet_no_fc_max_cwnd
} ,
2005-12-06 00:42:06 +03:00
{
2007-02-09 17:24:40 +03:00
. procname = " decnet_mem " ,
. data = & sysctl_decnet_mem ,
. maxlen = sizeof ( sysctl_decnet_mem ) ,
. mode = 0644 ,
2010-11-10 02:24:26 +03:00
. proc_handler = proc_doulongvec_minmax
2007-02-09 17:24:40 +03:00
} ,
{
. procname = " decnet_rmem " ,
. data = & sysctl_decnet_rmem ,
. maxlen = sizeof ( sysctl_decnet_rmem ) ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dointvec ,
2007-02-09 17:24:40 +03:00
} ,
{
. procname = " decnet_wmem " ,
. data = & sysctl_decnet_wmem ,
. maxlen = sizeof ( sysctl_decnet_wmem ) ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dointvec ,
2007-02-09 17:24:40 +03:00
} ,
2005-04-17 02:20:36 +04:00
{
. procname = " debug " ,
. data = & decnet_debug_level ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2008-11-04 05:21:05 +03:00
. proc_handler = proc_dointvec ,
2005-04-17 02:20:36 +04:00
} ,
2009-11-06 00:32:03 +03:00
{ }
2005-04-17 02:20:36 +04:00
} ;
void dn_register_sysctl ( void )
{
2012-04-19 17:40:37 +04:00
dn_table_header = register_net_sysctl ( & init_net , " net/decnet " , dn_table ) ;
2005-04-17 02:20:36 +04:00
}
void dn_unregister_sysctl ( void )
{
2012-04-19 17:24:33 +04:00
unregister_net_sysctl_table ( dn_table_header ) ;
2005-04-17 02:20:36 +04:00
}
# else /* CONFIG_SYSCTL */
void dn_unregister_sysctl ( void )
{
}
void dn_register_sysctl ( void )
{
}
# endif