2006-01-02 19:04:38 +01:00
/*
* net / tipc / node . c : TIPC node management routines
2007-02-09 23:25:21 +09:00
*
2006-01-11 19:14:19 +01:00
* Copyright ( c ) 2000 - 2006 , Ericsson AB
2011-01-07 13:00:11 -05:00
* Copyright ( c ) 2005 - 2006 , 2010 - 2011 , Wind River Systems
2006-01-02 19:04:38 +01:00
* All rights reserved .
*
2006-01-11 13:30:43 +01:00
* Redistribution and use in source and binary forms , with or without
2006-01-02 19:04:38 +01:00
* modification , are permitted provided that the following conditions are met :
*
2006-01-11 13:30:43 +01: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 19:04:38 +01:00
*
2006-01-11 13:30:43 +01: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 19:04:38 +01:00
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "core.h"
# include "config.h"
# include "node.h"
# include "name_distr.h"
2008-09-02 23:38:32 -07:00
static void node_lost_contact ( struct tipc_node * n_ptr ) ;
static void node_established_contact ( struct tipc_node * n_ptr ) ;
2006-01-02 19:04:38 +01:00
2008-05-21 14:53:00 -07:00
static DEFINE_SPINLOCK ( node_create_lock ) ;
2010-12-31 18:59:34 +00:00
u32 tipc_own_tag ;
2006-01-02 19:04:38 +01:00
2008-05-21 14:53:00 -07:00
/**
* tipc_node_create - create neighboring node
*
* Currently , this routine is called by neighbor discovery code , which holds
* net_lock for reading only . We must take node_create_lock to ensure a node
* isn ' t created twice if two different bearers discover the node at the same
* time . ( It would be preferable to switch to holding net_lock in write mode ,
* but this is a non - trivial change . )
*/
2008-09-02 23:38:32 -07:00
struct tipc_node * tipc_node_create ( u32 addr )
2006-01-02 19:04:38 +01:00
{
2008-09-02 23:38:32 -07:00
struct tipc_node * n_ptr ;
2010-12-31 18:59:19 +00:00
u32 n_num ;
2006-01-02 19:04:38 +01:00
2008-05-21 14:53:00 -07:00
spin_lock_bh ( & node_create_lock ) ;
2010-12-31 18:59:23 +00:00
n_ptr = tipc_node_find ( addr ) ;
if ( n_ptr ) {
spin_unlock_bh ( & node_create_lock ) ;
return n_ptr ;
2008-05-21 14:53:00 -07:00
}
2010-12-31 18:59:23 +00:00
n_ptr = kzalloc ( sizeof ( * n_ptr ) , GFP_ATOMIC ) ;
2006-06-25 23:52:17 -07:00
if ( ! n_ptr ) {
2008-05-21 14:53:00 -07:00
spin_unlock_bh ( & node_create_lock ) ;
2006-06-25 23:52:17 -07:00
warn ( " Node creation failed, no memory \n " ) ;
return NULL ;
}
n_ptr - > addr = addr ;
2010-12-31 18:59:18 +00:00
spin_lock_init ( & n_ptr - > lock ) ;
2006-06-25 23:52:17 -07:00
INIT_LIST_HEAD ( & n_ptr - > nsub ) ;
2010-12-31 18:59:19 +00:00
n_num = tipc_node ( addr ) ;
tipc_net . nodes [ n_num ] = n_ptr ;
if ( n_num > tipc_net . highest_node )
tipc_net . highest_node = n_num ;
2006-06-25 23:52:17 -07:00
2008-05-21 14:53:00 -07:00
spin_unlock_bh ( & node_create_lock ) ;
2006-01-02 19:04:38 +01:00
return n_ptr ;
}
2008-09-02 23:38:32 -07:00
void tipc_node_delete ( struct tipc_node * n_ptr )
2006-01-02 19:04:38 +01:00
{
2010-12-31 18:59:19 +00:00
u32 n_num ;
2006-01-02 19:04:38 +01:00
if ( ! n_ptr )
return ;
2010-12-31 18:59:19 +00:00
n_num = tipc_node ( n_ptr - > addr ) ;
tipc_net . nodes [ n_num ] = NULL ;
2006-01-02 19:04:38 +01:00
kfree ( n_ptr ) ;
2010-12-31 18:59:19 +00:00
while ( ! tipc_net . nodes [ tipc_net . highest_node ] )
if ( - - tipc_net . highest_node = = 0 )
break ;
2006-01-02 19:04:38 +01:00
}
/**
2006-01-18 00:38:21 +01:00
* tipc_node_link_up - handle addition of link
2007-02-09 23:25:21 +09:00
*
2006-01-02 19:04:38 +01:00
* Link becomes active ( alone or shared ) or standby , depending on its priority .
*/
2008-09-02 23:38:32 -07:00
void tipc_node_link_up ( struct tipc_node * n_ptr , struct link * l_ptr )
2006-01-02 19:04:38 +01:00
{
struct link * * active = & n_ptr - > active_links [ 0 ] ;
2006-06-25 23:52:50 -07:00
n_ptr - > working_links + + ;
2006-01-02 19:04:38 +01:00
info ( " Established link <%s> on network plane %c \n " ,
l_ptr - > name , l_ptr - > b_ptr - > net_plane ) ;
2007-02-09 23:25:21 +09:00
2006-01-02 19:04:38 +01:00
if ( ! active [ 0 ] ) {
active [ 0 ] = active [ 1 ] = l_ptr ;
node_established_contact ( n_ptr ) ;
return ;
}
2007-02-09 23:25:21 +09:00
if ( l_ptr - > priority < active [ 0 ] - > priority ) {
2006-06-25 23:52:17 -07:00
info ( " New link <%s> becomes standby \n " , l_ptr - > name ) ;
2006-01-02 19:04:38 +01:00
return ;
}
2006-01-18 00:38:21 +01:00
tipc_link_send_duplicate ( active [ 0 ] , l_ptr ) ;
2007-02-09 23:25:21 +09:00
if ( l_ptr - > priority = = active [ 0 ] - > priority ) {
2006-01-02 19:04:38 +01:00
active [ 0 ] = l_ptr ;
return ;
}
2006-06-25 23:52:17 -07:00
info ( " Old link <%s> becomes standby \n " , active [ 0 ] - > name ) ;
if ( active [ 1 ] ! = active [ 0 ] )
info ( " Old link <%s> becomes standby \n " , active [ 1 ] - > name ) ;
2006-01-02 19:04:38 +01:00
active [ 0 ] = active [ 1 ] = l_ptr ;
}
/**
* node_select_active_links - select active link
*/
2008-09-02 23:38:32 -07:00
static void node_select_active_links ( struct tipc_node * n_ptr )
2006-01-02 19:04:38 +01:00
{
struct link * * active = & n_ptr - > active_links [ 0 ] ;
u32 i ;
u32 highest_prio = 0 ;
2007-02-09 23:25:21 +09:00
active [ 0 ] = active [ 1 ] = NULL ;
2006-01-02 19:04:38 +01:00
for ( i = 0 ; i < MAX_BEARERS ; i + + ) {
2007-02-09 23:25:21 +09:00
struct link * l_ptr = n_ptr - > links [ i ] ;
2006-01-02 19:04:38 +01:00
2006-01-18 00:38:21 +01:00
if ( ! l_ptr | | ! tipc_link_is_up ( l_ptr ) | |
2006-01-02 19:04:38 +01:00
( l_ptr - > priority < highest_prio ) )
continue ;
if ( l_ptr - > priority > highest_prio ) {
2007-02-09 23:25:21 +09:00
highest_prio = l_ptr - > priority ;
2006-01-02 19:04:38 +01:00
active [ 0 ] = active [ 1 ] = l_ptr ;
} else {
active [ 1 ] = l_ptr ;
}
}
}
/**
2006-01-18 00:38:21 +01:00
* tipc_node_link_down - handle loss of link
2006-01-02 19:04:38 +01:00
*/
2008-09-02 23:38:32 -07:00
void tipc_node_link_down ( struct tipc_node * n_ptr , struct link * l_ptr )
2006-01-02 19:04:38 +01:00
{
struct link * * active ;
2006-06-25 23:52:50 -07:00
n_ptr - > working_links - - ;
2006-01-18 00:38:21 +01:00
if ( ! tipc_link_is_active ( l_ptr ) ) {
2006-01-02 19:04:38 +01:00
info ( " Lost standby link <%s> on network plane %c \n " ,
l_ptr - > name , l_ptr - > b_ptr - > net_plane ) ;
return ;
}
info ( " Lost link <%s> on network plane %c \n " ,
l_ptr - > name , l_ptr - > b_ptr - > net_plane ) ;
active = & n_ptr - > active_links [ 0 ] ;
if ( active [ 0 ] = = l_ptr )
active [ 0 ] = active [ 1 ] ;
if ( active [ 1 ] = = l_ptr )
active [ 1 ] = active [ 0 ] ;
if ( active [ 0 ] = = l_ptr )
node_select_active_links ( n_ptr ) ;
2007-02-09 23:25:21 +09:00
if ( tipc_node_is_up ( n_ptr ) )
2006-01-18 00:38:21 +01:00
tipc_link_changeover ( l_ptr ) ;
2007-02-09 23:25:21 +09:00
else
2006-01-02 19:04:38 +01:00
node_lost_contact ( n_ptr ) ;
}
2008-09-02 23:38:32 -07:00
int tipc_node_has_active_links ( struct tipc_node * n_ptr )
2006-01-02 19:04:38 +01:00
{
2010-08-17 11:00:12 +00:00
return n_ptr - > active_links [ 0 ] ! = NULL ;
2006-01-02 19:04:38 +01:00
}
2008-09-02 23:38:32 -07:00
int tipc_node_has_redundant_links ( struct tipc_node * n_ptr )
2006-01-02 19:04:38 +01:00
{
2010-09-22 20:43:57 +00:00
return n_ptr - > working_links > 1 ;
2006-01-02 19:04:38 +01:00
}
2008-09-02 23:38:32 -07:00
int tipc_node_is_up ( struct tipc_node * n_ptr )
2006-01-02 19:04:38 +01:00
{
2010-12-31 18:59:18 +00:00
return tipc_node_has_active_links ( n_ptr ) ;
2006-01-02 19:04:38 +01:00
}
2008-09-02 23:38:32 -07:00
struct tipc_node * tipc_node_attach_link ( struct link * l_ptr )
2006-01-02 19:04:38 +01:00
{
2008-09-02 23:38:32 -07:00
struct tipc_node * n_ptr = tipc_node_find ( l_ptr - > addr ) ;
2006-01-02 19:04:38 +01:00
if ( ! n_ptr )
2006-01-18 00:38:21 +01:00
n_ptr = tipc_node_create ( l_ptr - > addr ) ;
2007-02-09 23:25:21 +09:00
if ( n_ptr ) {
2006-01-02 19:04:38 +01:00
u32 bearer_id = l_ptr - > b_ptr - > identity ;
char addr_string [ 16 ] ;
2007-02-09 23:25:21 +09:00
if ( n_ptr - > link_cnt > = 2 ) {
err ( " Attempt to create third link to %s \n " ,
2010-05-11 14:30:12 +00:00
tipc_addr_string_fill ( addr_string , n_ptr - > addr ) ) ;
2007-02-09 23:25:21 +09:00
return NULL ;
}
if ( ! n_ptr - > links [ bearer_id ] ) {
n_ptr - > links [ bearer_id ] = l_ptr ;
2010-12-31 18:59:16 +00:00
tipc_net . links + + ;
2007-02-09 23:25:21 +09:00
n_ptr - > link_cnt + + ;
return n_ptr ;
}
2010-03-24 07:57:29 +00:00
err ( " Attempt to establish second link on <%s> to %s \n " ,
2011-01-07 13:00:11 -05:00
l_ptr - > b_ptr - > name ,
2010-05-11 14:30:12 +00:00
tipc_addr_string_fill ( addr_string , l_ptr - > addr ) ) ;
2007-02-09 23:25:21 +09:00
}
2006-03-20 22:36:47 -08:00
return NULL ;
2006-01-02 19:04:38 +01:00
}
2008-09-02 23:38:32 -07:00
void tipc_node_detach_link ( struct tipc_node * n_ptr , struct link * l_ptr )
2006-01-02 19:04:38 +01:00
{
2006-03-20 22:36:47 -08:00
n_ptr - > links [ l_ptr - > b_ptr - > identity ] = NULL ;
2010-12-31 18:59:16 +00:00
tipc_net . links - - ;
2006-01-02 19:04:38 +01:00
n_ptr - > link_cnt - - ;
}
/*
* Routing table management - five cases to handle :
*
* 1 : A link towards a zone / cluster external node comes up .
2007-02-09 23:25:21 +09:00
* = > Send a multicast message updating routing tables of all
* system nodes within own cluster that the new destination
* can be reached via this node .
2006-01-02 19:04:38 +01:00
* ( node . establishedContact ( ) = > cluster . multicastNewRoute ( ) )
*
* 2 : A link towards a slave node comes up .
2007-02-09 23:25:21 +09:00
* = > Send a multicast message updating routing tables of all
* system nodes within own cluster that the new destination
* can be reached via this node .
2006-01-02 19:04:38 +01:00
* ( node . establishedContact ( ) = > cluster . multicastNewRoute ( ) )
2007-02-09 23:25:21 +09:00
* = > Send a message to the slave node about existence
2006-01-02 19:04:38 +01:00
* of all system nodes within cluster :
* ( node . establishedContact ( ) = > cluster . sendLocalRoutes ( ) )
*
* 3 : A new cluster local system node becomes available .
* = > Send message ( s ) to this particular node containing
* information about all cluster external and slave
* nodes which can be reached via this node .
* ( node . establishedContact ( ) = = > network . sendExternalRoutes ( ) )
* ( node . establishedContact ( ) = = > network . sendSlaveRoutes ( ) )
2007-02-09 23:25:21 +09:00
* = > Send messages to all directly connected slave nodes
2006-01-02 19:04:38 +01:00
* containing information about the existence of the new node
* ( node . establishedContact ( ) = > cluster . multicastNewRoute ( ) )
2007-02-09 23:25:21 +09:00
*
2006-01-02 19:04:38 +01:00
* 4 : The link towards a zone / cluster external node or slave
* node goes down .
2007-02-09 23:25:21 +09:00
* = > Send a multcast message updating routing tables of all
2006-01-02 19:04:38 +01:00
* nodes within cluster that the new destination can not any
* longer be reached via this node .
* ( node . lostAllLinks ( ) = > cluster . bcastLostRoute ( ) )
*
* 5 : A cluster local system node becomes unavailable .
* = > Remove all references to this node from the local
* routing tables . Note : This is a completely node
* local operation .
* ( node . lostAllLinks ( ) = > network . removeAsRouter ( ) )
2007-02-09 23:25:21 +09:00
* = > Send messages to all directly connected slave nodes
2006-01-02 19:04:38 +01:00
* containing information about loss of the node
* ( node . establishedContact ( ) = > cluster . multicastLostRoute ( ) )
*
*/
2008-09-02 23:38:32 -07:00
static void node_established_contact ( struct tipc_node * n_ptr )
2006-01-02 19:04:38 +01:00
{
2010-12-31 18:59:18 +00:00
tipc_k_signal ( ( Handler ) tipc_named_node_up , n_ptr - > addr ) ;
2006-01-02 19:04:38 +01:00
2007-02-09 23:25:21 +09:00
/* Syncronize broadcast acks */
n_ptr - > bclink . acked = tipc_bclink_get_last_sent ( ) ;
2006-01-02 19:04:38 +01:00
if ( n_ptr - > bclink . supported ) {
2010-12-31 18:59:19 +00:00
tipc_nmap_add ( & tipc_bcast_nmap , n_ptr - > addr ) ;
2006-01-02 19:04:38 +01:00
if ( n_ptr - > addr < tipc_own_addr )
tipc_own_tag + + ;
}
}
2010-08-17 11:00:16 +00:00
static void node_cleanup_finished ( unsigned long node_addr )
{
struct tipc_node * n_ptr ;
read_lock_bh ( & tipc_net_lock ) ;
n_ptr = tipc_node_find ( node_addr ) ;
if ( n_ptr ) {
tipc_node_lock ( n_ptr ) ;
n_ptr - > cleanup_required = 0 ;
tipc_node_unlock ( n_ptr ) ;
}
read_unlock_bh ( & tipc_net_lock ) ;
}
2008-09-02 23:38:32 -07:00
static void node_lost_contact ( struct tipc_node * n_ptr )
2006-01-02 19:04:38 +01:00
{
2008-09-02 23:38:32 -07:00
struct tipc_node_subscr * ns , * tns ;
2006-01-02 19:04:38 +01:00
char addr_string [ 16 ] ;
u32 i ;
2007-02-09 23:25:21 +09:00
/* Clean up broadcast reception remains */
n_ptr - > bclink . gap_after = n_ptr - > bclink . gap_to = 0 ;
while ( n_ptr - > bclink . deferred_head ) {
2010-12-31 18:59:32 +00:00
struct sk_buff * buf = n_ptr - > bclink . deferred_head ;
2007-02-09 23:25:21 +09:00
n_ptr - > bclink . deferred_head = buf - > next ;
buf_discard ( buf ) ;
}
if ( n_ptr - > bclink . defragm ) {
buf_discard ( n_ptr - > bclink . defragm ) ;
n_ptr - > bclink . defragm = NULL ;
}
2010-12-31 18:59:18 +00:00
if ( n_ptr - > bclink . supported ) {
2010-12-31 18:59:19 +00:00
tipc_bclink_acknowledge ( n_ptr ,
mod ( n_ptr - > bclink . acked + 10000 ) ) ;
tipc_nmap_remove ( & tipc_bcast_nmap , n_ptr - > addr ) ;
2010-12-31 18:59:18 +00:00
if ( n_ptr - > addr < tipc_own_addr )
tipc_own_tag - - ;
2006-01-02 19:04:38 +01:00
}
2007-02-09 23:25:21 +09:00
info ( " Lost contact with %s \n " ,
2010-05-11 14:30:12 +00:00
tipc_addr_string_fill ( addr_string , n_ptr - > addr ) ) ;
2006-01-02 19:04:38 +01:00
/* Abort link changeover */
for ( i = 0 ; i < MAX_BEARERS ; i + + ) {
struct link * l_ptr = n_ptr - > links [ i ] ;
2007-02-09 23:25:21 +09:00
if ( ! l_ptr )
2006-01-02 19:04:38 +01:00
continue ;
l_ptr - > reset_checkpoint = l_ptr - > next_in_no ;
l_ptr - > exp_msg_count = 0 ;
2006-01-18 00:38:21 +01:00
tipc_link_reset_fragments ( l_ptr ) ;
2006-01-02 19:04:38 +01:00
}
/* Notify subscribers */
list_for_each_entry_safe ( ns , tns , & n_ptr - > nsub , nodesub_list ) {
2007-02-09 23:25:21 +09:00
ns - > node = NULL ;
2006-01-02 19:04:38 +01:00
list_del_init ( & ns - > nodesub_list ) ;
2006-01-18 00:38:21 +01:00
tipc_k_signal ( ( Handler ) ns - > handle_node_down ,
( unsigned long ) ns - > usr_handle ) ;
2006-01-02 19:04:38 +01:00
}
2010-08-17 11:00:16 +00:00
/* Prevent re-contact with node until all cleanup is done */
n_ptr - > cleanup_required = 1 ;
tipc_k_signal ( ( Handler ) node_cleanup_finished , n_ptr - > addr ) ;
2006-01-02 19:04:38 +01:00
}
2006-01-18 00:38:21 +01:00
struct sk_buff * tipc_node_get_nodes ( const void * req_tlv_area , int req_tlv_space )
2006-01-02 19:04:38 +01:00
{
u32 domain ;
struct sk_buff * buf ;
2008-09-02 23:38:32 -07:00
struct tipc_node * n_ptr ;
2007-02-09 23:25:21 +09:00
struct tipc_node_info node_info ;
2006-06-29 12:33:20 -07:00
u32 payload_size ;
2010-12-31 18:59:23 +00:00
u32 n_num ;
2006-01-02 19:04:38 +01:00
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_NET_ADDR ) )
2006-01-18 00:38:21 +01:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-01-02 19:04:38 +01:00
2006-11-08 00:19:09 -08:00
domain = ntohl ( * ( __be32 * ) TLV_DATA ( req_tlv_area ) ) ;
2006-01-18 00:38:21 +01:00
if ( ! tipc_addr_domain_valid ( domain ) )
return tipc_cfg_reply_error_string ( TIPC_CFG_INVALID_VALUE
" (network address) " ) ;
2006-01-02 19:04:38 +01:00
2008-07-14 22:44:58 -07:00
read_lock_bh ( & tipc_net_lock ) ;
2010-12-31 18:59:23 +00:00
if ( ! tipc_net . nodes ) {
2008-07-14 22:44:58 -07:00
read_unlock_bh ( & tipc_net_lock ) ;
2007-02-09 23:25:21 +09:00
return tipc_cfg_reply_none ( ) ;
2008-07-14 22:44:58 -07:00
}
2006-01-02 19:04:38 +01:00
2010-12-31 18:59:17 +00:00
/* For now, get space for all other nodes */
2006-01-02 19:04:38 +01:00
2010-12-31 18:59:23 +00:00
payload_size = TLV_SPACE ( sizeof ( node_info ) ) *
( tipc_net . highest_node - 1 ) ;
2008-07-14 22:44:58 -07:00
if ( payload_size > 32768u ) {
read_unlock_bh ( & tipc_net_lock ) ;
2006-06-29 12:33:20 -07:00
return tipc_cfg_reply_error_string ( TIPC_CFG_NOT_SUPPORTED
" (too many nodes) " ) ;
2008-07-14 22:44:58 -07:00
}
2006-06-29 12:33:20 -07:00
buf = tipc_cfg_reply_alloc ( payload_size ) ;
2008-07-14 22:44:58 -07:00
if ( ! buf ) {
read_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 19:04:38 +01:00
return NULL ;
2008-07-14 22:44:58 -07:00
}
2006-01-02 19:04:38 +01:00
/* Add TLVs for all nodes in scope */
2010-12-31 18:59:23 +00:00
for ( n_num = 1 ; n_num < = tipc_net . highest_node ; n_num + + ) {
n_ptr = tipc_net . nodes [ n_num ] ;
if ( ! n_ptr | | ! tipc_in_scope ( domain , n_ptr - > addr ) )
2006-01-02 19:04:38 +01:00
continue ;
2007-02-09 23:25:21 +09:00
node_info . addr = htonl ( n_ptr - > addr ) ;
node_info . up = htonl ( tipc_node_is_up ( n_ptr ) ) ;
tipc_cfg_append_tlv ( buf , TIPC_TLV_NODE_INFO ,
2006-01-18 00:38:21 +01:00
& node_info , sizeof ( node_info ) ) ;
2006-01-02 19:04:38 +01:00
}
2008-07-14 22:44:58 -07:00
read_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 19:04:38 +01:00
return buf ;
}
2006-01-18 00:38:21 +01:00
struct sk_buff * tipc_node_get_links ( const void * req_tlv_area , int req_tlv_space )
2006-01-02 19:04:38 +01:00
{
u32 domain ;
struct sk_buff * buf ;
2008-09-02 23:38:32 -07:00
struct tipc_node * n_ptr ;
2007-02-09 23:25:21 +09:00
struct tipc_link_info link_info ;
2006-06-29 12:33:20 -07:00
u32 payload_size ;
2010-12-31 18:59:23 +00:00
u32 n_num ;
2006-01-02 19:04:38 +01:00
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_NET_ADDR ) )
2006-01-18 00:38:21 +01:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-01-02 19:04:38 +01:00
2006-11-08 00:19:09 -08:00
domain = ntohl ( * ( __be32 * ) TLV_DATA ( req_tlv_area ) ) ;
2006-01-18 00:38:21 +01:00
if ( ! tipc_addr_domain_valid ( domain ) )
return tipc_cfg_reply_error_string ( TIPC_CFG_INVALID_VALUE
" (network address) " ) ;
2006-01-02 19:04:38 +01:00
2007-02-09 23:25:21 +09:00
if ( tipc_mode ! = TIPC_NET_MODE )
return tipc_cfg_reply_none ( ) ;
2008-07-14 22:44:58 -07:00
read_lock_bh ( & tipc_net_lock ) ;
2006-06-29 12:33:20 -07:00
/* Get space for all unicast links + multicast link */
2010-12-31 18:59:16 +00:00
payload_size = TLV_SPACE ( sizeof ( link_info ) ) * ( tipc_net . links + 1 ) ;
2008-07-14 22:44:58 -07:00
if ( payload_size > 32768u ) {
read_unlock_bh ( & tipc_net_lock ) ;
2006-06-29 12:33:20 -07:00
return tipc_cfg_reply_error_string ( TIPC_CFG_NOT_SUPPORTED
" (too many links) " ) ;
2008-07-14 22:44:58 -07:00
}
2006-06-29 12:33:20 -07:00
buf = tipc_cfg_reply_alloc ( payload_size ) ;
2008-07-14 22:44:58 -07:00
if ( ! buf ) {
read_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 19:04:38 +01:00
return NULL ;
2008-07-14 22:44:58 -07:00
}
2006-01-02 19:04:38 +01:00
/* Add TLV for broadcast link */
2007-02-09 23:25:21 +09:00
link_info . dest = htonl ( tipc_own_addr & 0xfffff00 ) ;
link_info . up = htonl ( 1 ) ;
2009-03-18 19:11:29 -07:00
strlcpy ( link_info . str , tipc_bclink_name , TIPC_MAX_LINK_NAME ) ;
2006-01-18 00:38:21 +01:00
tipc_cfg_append_tlv ( buf , TIPC_TLV_LINK_INFO , & link_info , sizeof ( link_info ) ) ;
2006-01-02 19:04:38 +01:00
/* Add TLVs for any other links in scope */
2010-12-31 18:59:23 +00:00
for ( n_num = 1 ; n_num < = tipc_net . highest_node ; n_num + + ) {
2007-02-09 23:25:21 +09:00
u32 i ;
2006-01-02 19:04:38 +01:00
2010-12-31 18:59:23 +00:00
n_ptr = tipc_net . nodes [ n_num ] ;
if ( ! n_ptr | | ! tipc_in_scope ( domain , n_ptr - > addr ) )
2006-01-02 19:04:38 +01:00
continue ;
2008-07-14 22:44:58 -07:00
tipc_node_lock ( n_ptr ) ;
2007-02-09 23:25:21 +09:00
for ( i = 0 ; i < MAX_BEARERS ; i + + ) {
if ( ! n_ptr - > links [ i ] )
continue ;
link_info . dest = htonl ( n_ptr - > addr ) ;
link_info . up = htonl ( tipc_link_is_up ( n_ptr - > links [ i ] ) ) ;
strcpy ( link_info . str , n_ptr - > links [ i ] - > name ) ;
tipc_cfg_append_tlv ( buf , TIPC_TLV_LINK_INFO ,
2006-01-18 00:38:21 +01:00
& link_info , sizeof ( link_info ) ) ;
2007-02-09 23:25:21 +09:00
}
2008-07-14 22:44:58 -07:00
tipc_node_unlock ( n_ptr ) ;
2006-01-02 19:04:38 +01:00
}
2008-07-14 22:44:58 -07:00
read_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 19:04:38 +01:00
return buf ;
}