2006-01-02 21:04:38 +03:00
/*
* net / tipc / config . c : TIPC configuration management code
2007-02-09 17:25:21 +03:00
*
2006-01-11 21:14:19 +03:00
* Copyright ( c ) 2002 - 2006 , Ericsson AB
2013-06-17 18:54:41 +04:00
* Copyright ( c ) 2004 - 2007 , 2010 - 2013 , Wind River Systems
2006-01-02 21:04:38 +03:00
* All rights reserved .
*
2006-01-11 15:30:43 +03:00
* Redistribution and use in source and binary forms , with or without
2006-01-02 21:04:38 +03:00
* modification , are permitted provided that the following conditions are met :
*
2006-01-11 15:30:43 +03:00
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission .
2006-01-02 21:04:38 +03:00
*
2006-01-11 15:30:43 +03:00
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
2006-01-02 21:04:38 +03:00
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "core.h"
2014-08-23 02:09:14 +04:00
# include "socket.h"
2006-01-02 21:04:38 +03:00
# include "name_table.h"
# include "config.h"
2013-06-17 18:54:41 +04:00
# include "server.h"
2006-01-02 21:04:38 +03:00
2012-06-29 08:50:23 +04:00
# define REPLY_TRUNCATED "<truncated>\n"
2006-01-02 21:04:38 +03:00
static const void * req_tlv_area ; /* request message TLV area */
static int req_tlv_space ; /* request message TLV area size */
static int rep_headroom ; /* reply message headroom to use */
2006-01-18 02:38:21 +03:00
struct sk_buff * tipc_cfg_reply_alloc ( int payload_size )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * buf ;
buf = alloc_skb ( rep_headroom + payload_size , GFP_ATOMIC ) ;
if ( buf )
skb_reserve ( buf , rep_headroom ) ;
return buf ;
}
2007-02-09 17:25:21 +03:00
int tipc_cfg_append_tlv ( struct sk_buff * buf , int tlv_type ,
2006-01-18 02:38:21 +03:00
void * tlv_data , int tlv_data_size )
2006-01-02 21:04:38 +03:00
{
2007-04-20 07:29:13 +04:00
struct tlv_desc * tlv = ( struct tlv_desc * ) skb_tail_pointer ( buf ) ;
2006-01-02 21:04:38 +03:00
int new_tlv_space = TLV_SPACE ( tlv_data_size ) ;
2010-12-31 21:59:25 +03:00
if ( skb_tailroom ( buf ) < new_tlv_space )
2006-01-02 21:04:38 +03:00
return 0 ;
skb_put ( buf , new_tlv_space ) ;
tlv - > tlv_type = htons ( tlv_type ) ;
tlv - > tlv_len = htons ( TLV_LENGTH ( tlv_data_size ) ) ;
if ( tlv_data_size & & tlv_data )
memcpy ( TLV_DATA ( tlv ) , tlv_data , tlv_data_size ) ;
return 1 ;
}
2010-10-13 17:20:35 +04:00
static struct sk_buff * tipc_cfg_reply_unsigned_type ( u16 tlv_type , u32 value )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * buf ;
2006-11-08 11:19:09 +03:00
__be32 value_net ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
buf = tipc_cfg_reply_alloc ( TLV_SPACE ( sizeof ( value ) ) ) ;
2006-01-02 21:04:38 +03:00
if ( buf ) {
value_net = htonl ( value ) ;
2007-02-09 17:25:21 +03:00
tipc_cfg_append_tlv ( buf , tlv_type , & value_net ,
2006-01-18 02:38:21 +03:00
sizeof ( value_net ) ) ;
2006-01-02 21:04:38 +03:00
}
return buf ;
}
2010-10-13 17:20:35 +04:00
static struct sk_buff * tipc_cfg_reply_unsigned ( u32 value )
{
return tipc_cfg_reply_unsigned_type ( TIPC_TLV_UNSIGNED , value ) ;
}
2006-01-18 02:38:21 +03:00
struct sk_buff * tipc_cfg_reply_string_type ( u16 tlv_type , char * string )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * buf ;
int string_len = strlen ( string ) + 1 ;
2006-01-18 02:38:21 +03:00
buf = tipc_cfg_reply_alloc ( TLV_SPACE ( string_len ) ) ;
2006-01-02 21:04:38 +03:00
if ( buf )
2006-01-18 02:38:21 +03:00
tipc_cfg_append_tlv ( buf , tlv_type , string , string_len ) ;
2006-01-02 21:04:38 +03:00
return buf ;
}
2010-05-11 18:30:08 +04:00
static struct sk_buff * tipc_show_stats ( void )
{
struct sk_buff * buf ;
struct tlv_desc * rep_tlv ;
2012-06-29 08:50:23 +04:00
char * pb ;
int pb_len ;
2010-05-11 18:30:08 +04:00
int str_len ;
u32 value ;
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_UNSIGNED ) )
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
value = ntohl ( * ( u32 * ) TLV_DATA ( req_tlv_area ) ) ;
if ( value ! = 0 )
return tipc_cfg_reply_error_string ( " unsupported argument " ) ;
2012-06-29 08:50:23 +04:00
buf = tipc_cfg_reply_alloc ( TLV_SPACE ( ULTRA_STRING_MAX_LEN ) ) ;
2010-05-11 18:30:08 +04:00
if ( buf = = NULL )
return NULL ;
rep_tlv = ( struct tlv_desc * ) buf - > data ;
2012-06-29 08:50:23 +04:00
pb = TLV_DATA ( rep_tlv ) ;
pb_len = ULTRA_STRING_MAX_LEN ;
2010-05-11 18:30:08 +04:00
2012-06-29 08:50:23 +04:00
str_len = tipc_snprintf ( pb , pb_len , " TIPC version " TIPC_MOD_VER " \n " ) ;
str_len + = 1 ; /* for "\0" */
2010-05-11 18:30:08 +04:00
skb_put ( buf , TLV_SPACE ( str_len ) ) ;
TLV_SET ( rep_tlv , TIPC_TLV_ULTRA_STRING , NULL , str_len ) ;
return buf ;
}
2006-01-02 21:04:38 +03:00
static struct sk_buff * cfg_enable_bearer ( void )
{
struct tipc_bearer_config * args ;
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_BEARER_CONFIG ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-01-02 21:04:38 +03:00
args = ( struct tipc_bearer_config * ) TLV_DATA ( req_tlv_area ) ;
if ( tipc_enable_bearer ( args - > name ,
2011-02-28 22:56:15 +03:00
ntohl ( args - > disc_domain ) ,
2006-01-02 21:04:38 +03:00
ntohl ( args - > priority ) ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( " unable to enable bearer " ) ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_none ( ) ;
2006-01-02 21:04:38 +03:00
}
static struct sk_buff * cfg_disable_bearer ( void )
{
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_BEARER_NAME ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-01-02 21:04:38 +03:00
if ( tipc_disable_bearer ( ( char * ) TLV_DATA ( req_tlv_area ) ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( " unable to disable bearer " ) ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_none ( ) ;
2006-01-02 21:04:38 +03:00
}
static struct sk_buff * cfg_set_own_addr ( void )
{
u32 addr ;
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_NET_ADDR ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-01-02 21:04:38 +03:00
2006-11-08 11:19:09 +03:00
addr = ntohl ( * ( __be32 * ) TLV_DATA ( req_tlv_area ) ) ;
2006-01-02 21:04:38 +03:00
if ( addr = = tipc_own_addr )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_none ( ) ;
if ( ! tipc_addr_node_valid ( addr ) )
return tipc_cfg_reply_error_string ( TIPC_CFG_INVALID_VALUE
" (node address) " ) ;
2011-11-08 22:48:28 +04:00
if ( tipc_own_addr )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned) " ) ;
2014-05-05 04:56:16 +04:00
if ( ! tipc_net_start ( addr ) )
return tipc_cfg_reply_none ( ) ;
return tipc_cfg_reply_error_string ( " cannot change to network mode " ) ;
2006-01-02 21:04:38 +03:00
}
static struct sk_buff * cfg_set_max_ports ( void )
{
u32 value ;
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_UNSIGNED ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-11-08 11:19:09 +03:00
value = ntohl ( * ( __be32 * ) TLV_DATA ( req_tlv_area ) ) ;
2006-06-26 10:51:08 +04:00
if ( value = = tipc_max_ports )
return tipc_cfg_reply_none ( ) ;
2012-02-24 00:44:08 +04:00
if ( value < 127 | | value > 65535 )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_INVALID_VALUE
" (max ports must be 127-65535) " ) ;
2011-11-08 22:18:59 +04:00
return tipc_cfg_reply_error_string ( TIPC_CFG_NOT_SUPPORTED
" (cannot change max ports while TIPC is active) " ) ;
2006-01-02 21:04:38 +03:00
}
static struct sk_buff * cfg_set_netid ( void )
{
u32 value ;
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_UNSIGNED ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-11-08 11:19:09 +03:00
value = ntohl ( * ( __be32 * ) TLV_DATA ( req_tlv_area ) ) ;
2006-06-26 10:51:08 +04:00
if ( value = = tipc_net_id )
return tipc_cfg_reply_none ( ) ;
2012-02-24 00:44:08 +04:00
if ( value < 1 | | value > 9999 )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_INVALID_VALUE
" (network id must be 1-9999) " ) ;
2011-11-08 22:48:28 +04:00
if ( tipc_own_addr )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_NOT_SUPPORTED
2006-06-26 10:51:08 +04:00
" (cannot change network id once TIPC has joined a network) " ) ;
tipc_net_id = value ;
return tipc_cfg_reply_none ( ) ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
struct sk_buff * tipc_cfg_do_cmd ( u32 orig_node , u16 cmd , const void * request_area ,
int request_space , int reply_headroom )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * rep_tlv_buf ;
2014-04-21 06:55:42 +04:00
rtnl_lock ( ) ;
2006-01-02 21:04:38 +03:00
/* Save request and reply details in a well-known location */
req_tlv_area = request_area ;
req_tlv_space = request_space ;
rep_headroom = reply_headroom ;
/* Check command authorization */
2012-04-18 17:42:56 +04:00
if ( likely ( in_own_node ( orig_node ) ) ) {
2006-01-02 21:04:38 +03:00
/* command is permitted */
2014-03-27 08:54:31 +04:00
} else {
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_cfg_reply_error_string ( TIPC_CFG_NOT_SUPPORTED
" (cannot be done remotely) " ) ;
2006-01-02 21:04:38 +03:00
goto exit ;
}
/* Call appropriate processing routine */
switch ( cmd ) {
case TIPC_CMD_NOOP :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_cfg_reply_none ( ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_GET_NODES :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_node_get_nodes ( req_tlv_area , req_tlv_space ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_GET_LINKS :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_node_get_links ( req_tlv_area , req_tlv_space ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_SHOW_LINK_STATS :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_link_cmd_show_stats ( req_tlv_area , req_tlv_space ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_RESET_LINK_STATS :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_link_cmd_reset_stats ( req_tlv_area , req_tlv_space ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_SHOW_NAME_TABLE :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_nametbl_get ( req_tlv_area , req_tlv_space ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_GET_BEARER_NAMES :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_bearer_get_names ( ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_GET_MEDIA_NAMES :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_media_get_names ( ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_SHOW_PORTS :
2014-08-23 02:09:14 +04:00
rep_tlv_buf = tipc_sk_socks_show ( ) ;
2006-01-02 21:04:38 +03:00
break ;
2010-05-11 18:30:08 +04:00
case TIPC_CMD_SHOW_STATS :
rep_tlv_buf = tipc_show_stats ( ) ;
break ;
2006-01-02 21:04:38 +03:00
case TIPC_CMD_SET_LINK_TOL :
case TIPC_CMD_SET_LINK_PRI :
case TIPC_CMD_SET_LINK_WINDOW :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_link_cmd_config ( req_tlv_area , req_tlv_space , cmd ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_ENABLE_BEARER :
rep_tlv_buf = cfg_enable_bearer ( ) ;
break ;
case TIPC_CMD_DISABLE_BEARER :
rep_tlv_buf = cfg_disable_bearer ( ) ;
break ;
case TIPC_CMD_SET_NODE_ADDR :
rep_tlv_buf = cfg_set_own_addr ( ) ;
break ;
case TIPC_CMD_SET_MAX_PORTS :
rep_tlv_buf = cfg_set_max_ports ( ) ;
break ;
case TIPC_CMD_SET_NETID :
rep_tlv_buf = cfg_set_netid ( ) ;
break ;
case TIPC_CMD_GET_MAX_PORTS :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_cfg_reply_unsigned ( tipc_max_ports ) ;
2006-01-02 21:04:38 +03:00
break ;
case TIPC_CMD_GET_NETID :
2006-01-18 02:38:21 +03:00
rep_tlv_buf = tipc_cfg_reply_unsigned ( tipc_net_id ) ;
2006-01-02 21:04:38 +03:00
break ;
2008-05-22 01:52:30 +04:00
case TIPC_CMD_NOT_NET_ADMIN :
rep_tlv_buf =
tipc_cfg_reply_error_string ( TIPC_CFG_NOT_NET_ADMIN ) ;
break ;
2010-12-31 21:59:16 +03:00
case TIPC_CMD_SET_MAX_ZONES :
case TIPC_CMD_GET_MAX_ZONES :
2010-12-31 21:59:17 +03:00
case TIPC_CMD_SET_MAX_SLAVES :
case TIPC_CMD_GET_MAX_SLAVES :
2010-12-31 21:59:19 +03:00
case TIPC_CMD_SET_MAX_CLUSTERS :
case TIPC_CMD_GET_MAX_CLUSTERS :
2011-02-25 22:22:11 +03:00
case TIPC_CMD_SET_MAX_NODES :
case TIPC_CMD_GET_MAX_NODES :
2012-08-16 16:09:13 +04:00
case TIPC_CMD_SET_MAX_SUBSCR :
case TIPC_CMD_GET_MAX_SUBSCR :
2012-08-16 16:09:14 +04:00
case TIPC_CMD_SET_MAX_PUBL :
case TIPC_CMD_GET_MAX_PUBL :
2012-06-29 08:50:24 +04:00
case TIPC_CMD_SET_LOG_SIZE :
2014-03-27 08:54:31 +04:00
case TIPC_CMD_SET_REMOTE_MNG :
case TIPC_CMD_GET_REMOTE_MNG :
2012-06-29 08:50:24 +04:00
case TIPC_CMD_DUMP_LOG :
2010-12-31 21:59:16 +03:00
rep_tlv_buf = tipc_cfg_reply_error_string ( TIPC_CFG_NOT_SUPPORTED
" (obsolete command) " ) ;
break ;
2006-01-02 21:04:38 +03:00
default :
2006-10-17 09:00:56 +04:00
rep_tlv_buf = tipc_cfg_reply_error_string ( TIPC_CFG_NOT_SUPPORTED
" (unknown command) " ) ;
2006-01-02 21:04:38 +03:00
break ;
}
2012-06-29 08:50:23 +04:00
WARN_ON ( rep_tlv_buf - > len > TLV_SPACE ( ULTRA_STRING_MAX_LEN ) ) ;
/* Append an error message if we cannot return all requested data */
if ( rep_tlv_buf - > len = = TLV_SPACE ( ULTRA_STRING_MAX_LEN ) ) {
if ( * ( rep_tlv_buf - > data + ULTRA_STRING_MAX_LEN ) ! = ' \0 ' )
sprintf ( rep_tlv_buf - > data + rep_tlv_buf - > len -
sizeof ( REPLY_TRUNCATED ) - 1 , REPLY_TRUNCATED ) ;
}
2006-01-02 21:04:38 +03:00
/* Return reply buffer */
exit :
2014-04-21 06:55:42 +04:00
rtnl_unlock ( ) ;
2006-01-02 21:04:38 +03:00
return rep_tlv_buf ;
}