2006-01-02 21:04:38 +03:00
/*
* net / tipc / discover . c
2007-02-09 17:25:21 +03:00
*
2006-01-11 20:40:41 +03:00
* Copyright ( c ) 2003 - 2006 , Ericsson AB
2011-01-07 21:00:11 +03:00
* Copyright ( c ) 2005 - 2006 , 2010 - 2011 , 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"
# include "link.h"
# include "discover.h"
# define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */
2011-04-22 05:34:03 +04:00
# define TIPC_LINK_REQ_FAST 1000 /* max delay if bearer has no links */
# define TIPC_LINK_REQ_SLOW 60000 /* max delay if bearer has links */
# define TIPC_LINK_REQ_INACTIVE 0xffffffff /* indicates no timer in use */
2006-01-02 21:04:38 +03:00
/**
2011-12-30 05:58:42 +04:00
* struct tipc_link_req - information about an ongoing link setup request
2006-01-02 21:04:38 +03:00
* @ bearer : bearer issuing requests
* @ dest : destination address for request messages
2011-04-21 01:24:07 +04:00
* @ domain : network domain to which links can be established
2011-04-22 04:05:25 +04:00
* @ num_nodes : number of nodes currently discovered ( i . e . with an active link )
2006-01-02 21:04:38 +03:00
* @ buf : request message to be ( repeatedly ) sent
* @ timer : timer governing period between requests
* @ timer_intv : current interval between requests ( in ms )
*/
2011-12-30 05:58:42 +04:00
struct tipc_link_req {
2011-01-07 21:00:11 +03:00
struct tipc_bearer * bearer ;
2006-01-02 21:04:38 +03:00
struct tipc_media_addr dest ;
2011-04-21 01:24:07 +04:00
u32 domain ;
2011-04-22 04:05:25 +04:00
int num_nodes ;
2006-01-02 21:04:38 +03:00
struct sk_buff * buf ;
struct timer_list timer ;
unsigned int timer_intv ;
} ;
2007-02-09 17:25:21 +03:00
/**
2006-01-18 02:38:21 +03:00
* tipc_disc_init_msg - initialize a link setup message
2006-01-02 21:04:38 +03:00
* @ type : message type ( request or response )
* @ dest_domain : network domain of node ( s ) which should respond to message
* @ b_ptr : ptr to bearer issuing message
*/
2006-03-21 09:37:52 +03:00
static struct sk_buff * tipc_disc_init_msg ( u32 type ,
u32 dest_domain ,
2011-01-07 21:00:11 +03:00
struct tipc_bearer * b_ptr )
2006-01-02 21:04:38 +03:00
{
2011-03-01 00:02:30 +03:00
struct sk_buff * buf = tipc_buf_acquire ( INT_H_SIZE ) ;
2006-01-02 21:04:38 +03:00
struct tipc_msg * msg ;
if ( buf ) {
msg = buf_msg ( buf ) ;
2011-03-01 00:02:30 +03:00
tipc_msg_init ( msg , LINK_CONFIG , type , INT_H_SIZE , dest_domain ) ;
2008-06-05 04:54:48 +04:00
msg_set_non_seq ( msg , 1 ) ;
2011-10-29 00:26:41 +04:00
msg_set_node_sig ( msg , tipc_random ) ;
2006-01-02 21:04:38 +03:00
msg_set_dest_domain ( msg , dest_domain ) ;
msg_set_bc_netid ( msg , tipc_net_id ) ;
2011-10-07 23:19:11 +04:00
b_ptr - > media - > addr2msg ( & b_ptr - > addr , msg_media_addr ( msg ) ) ;
2006-01-02 21:04:38 +03:00
}
return buf ;
}
2006-10-17 08:44:59 +04:00
/**
* disc_dupl_alert - issue node address duplication alert
* @ b_ptr : pointer to bearer detecting duplication
* @ node_addr : duplicated node address
* @ media_addr : media address advertised by duplicated node
*/
2011-01-07 21:00:11 +03:00
static void disc_dupl_alert ( struct tipc_bearer * b_ptr , u32 node_addr ,
2006-10-17 08:44:59 +04:00
struct tipc_media_addr * media_addr )
{
char node_addr_str [ 16 ] ;
char media_addr_str [ 64 ] ;
2010-05-11 18:30:12 +04:00
tipc_addr_string_fill ( node_addr_str , node_addr ) ;
2012-06-29 08:50:23 +04:00
tipc_media_addr_printf ( media_addr_str , sizeof ( media_addr_str ) ,
media_addr ) ;
2012-06-29 08:16:37 +04:00
pr_warn ( " Duplicate %s using %s seen on <%s> \n " , node_addr_str ,
media_addr_str , b_ptr - > name ) ;
2006-10-17 08:44:59 +04:00
}
2006-01-02 21:04:38 +03:00
/**
2006-01-18 02:38:21 +03:00
* tipc_disc_recv_msg - handle incoming link setup message ( request or response )
2006-01-02 21:04:38 +03:00
* @ buf : buffer containing message
2008-06-05 04:32:35 +04:00
* @ b_ptr : bearer that message arrived on
2006-01-02 21:04:38 +03:00
*/
2011-01-07 21:00:11 +03:00
void tipc_disc_recv_msg ( struct sk_buff * buf , struct tipc_bearer * b_ptr )
2006-01-02 21:04:38 +03:00
{
2011-02-28 18:03:05 +03:00
struct tipc_node * n_ptr ;
2011-12-30 05:58:42 +04:00
struct tipc_link * link ;
2011-10-29 01:30:08 +04:00
struct tipc_media_addr media_addr ;
2011-02-28 18:03:05 +03:00
struct sk_buff * rbuf ;
2006-01-02 21:04:38 +03:00
struct tipc_msg * msg = buf_msg ( buf ) ;
u32 dest = msg_dest_domain ( msg ) ;
u32 orig = msg_prevnode ( msg ) ;
u32 net_id = msg_bc_netid ( msg ) ;
u32 type = msg_type ( msg ) ;
2011-10-29 00:26:41 +04:00
u32 signature = msg_node_sig ( msg ) ;
2011-10-29 01:30:08 +04:00
int addr_mismatch ;
2011-02-28 18:03:05 +03:00
int link_fully_up ;
2006-01-02 21:04:38 +03:00
2011-10-07 23:48:41 +04:00
media_addr . broadcast = 1 ;
2011-10-07 23:19:11 +04:00
b_ptr - > media - > msg2addr ( & media_addr , msg_media_addr ( msg ) ) ;
2011-11-04 21:24:29 +04:00
kfree_skb ( buf ) ;
2006-01-02 21:04:38 +03:00
2011-10-29 01:30:08 +04:00
/* Ensure message from node is valid and communication is permitted */
2006-01-02 21:04:38 +03:00
if ( net_id ! = tipc_net_id )
return ;
2011-10-07 23:48:41 +04:00
if ( media_addr . broadcast )
return ;
2006-01-18 02:38:21 +03:00
if ( ! tipc_addr_domain_valid ( dest ) )
2006-01-02 21:04:38 +03:00
return ;
2006-01-18 02:38:21 +03:00
if ( ! tipc_addr_node_valid ( orig ) )
2006-01-02 21:04:38 +03:00
return ;
2006-10-17 08:44:59 +04:00
if ( orig = = tipc_own_addr ) {
2011-01-07 21:00:11 +03:00
if ( memcmp ( & media_addr , & b_ptr - > addr , sizeof ( media_addr ) ) )
2006-10-17 08:44:59 +04:00
disc_dupl_alert ( b_ptr , tipc_own_addr , & media_addr ) ;
2006-01-02 21:04:38 +03:00
return ;
2006-10-17 08:44:59 +04:00
}
2010-05-11 18:30:12 +04:00
if ( ! tipc_in_scope ( dest , tipc_own_addr ) )
2006-01-02 21:04:38 +03:00
return ;
2011-04-21 01:24:07 +04:00
if ( ! tipc_in_scope ( b_ptr - > link_req - > domain , orig ) )
2011-02-28 18:03:05 +03:00
return ;
2010-08-17 15:00:16 +04:00
2011-02-28 18:03:05 +03:00
/* Locate structure corresponding to requesting node */
n_ptr = tipc_node_find ( orig ) ;
if ( ! n_ptr ) {
n_ptr = tipc_node_create ( orig ) ;
if ( ! n_ptr )
2010-08-17 15:00:16 +04:00
return ;
2011-02-28 18:03:05 +03:00
}
tipc_node_lock ( n_ptr ) ;
2011-10-29 01:30:08 +04:00
/* Prepare to validate requesting node's signature and media address */
2011-02-28 18:03:05 +03:00
link = n_ptr - > links [ b_ptr - > identity ] ;
2011-10-29 01:30:08 +04:00
addr_mismatch = ( link ! = NULL ) & &
memcmp ( & link - > media_addr , & media_addr , sizeof ( media_addr ) ) ;
2011-02-28 18:03:05 +03:00
2011-10-29 01:30:08 +04:00
/*
* Ensure discovery message ' s signature is correct
*
* If signature is incorrect and there is no working link to the node ,
* accept the new signature but invalidate all existing links to the
* node so they won ' t re - activate without a new discovery message .
*
* If signature is incorrect and the requested link to the node is
* working , accept the new signature . ( This is an instance of delayed
* rediscovery , where a link endpoint was able to re - establish contact
* with its peer endpoint on a node that rebooted before receiving a
* discovery message from that node . )
*
* If signature is incorrect and there is a working link to the node
* that is not the requested link , reject the request ( must be from
* a duplicate node ) .
*/
if ( signature ! = n_ptr - > signature ) {
if ( n_ptr - > working_links = = 0 ) {
struct tipc_link * curr_link ;
int i ;
for ( i = 0 ; i < MAX_BEARERS ; i + + ) {
curr_link = n_ptr - > links [ i ] ;
if ( curr_link ) {
memset ( & curr_link - > media_addr , 0 ,
sizeof ( media_addr ) ) ;
tipc_link_reset ( curr_link ) ;
}
}
addr_mismatch = ( link ! = NULL ) ;
} else if ( tipc_link_is_up ( link ) & & ! addr_mismatch ) {
/* delayed rediscovery */
} else {
disc_dupl_alert ( b_ptr , orig , & media_addr ) ;
2011-02-28 18:03:05 +03:00
tipc_node_unlock ( n_ptr ) ;
return ;
2006-01-02 21:04:38 +03:00
}
2011-10-29 01:30:08 +04:00
n_ptr - > signature = signature ;
2011-02-28 18:03:05 +03:00
}
/*
* Ensure requesting node ' s media address is correct
*
* If media address doesn ' t match and the link is working , reject the
* request ( must be from a duplicate node ) .
*
* If media address doesn ' t match and the link is not working , accept
* the new media address and reset the link to ensure it starts up
* cleanly .
*/
2011-10-29 01:30:08 +04:00
if ( addr_mismatch ) {
if ( tipc_link_is_up ( link ) ) {
2011-02-28 18:03:05 +03:00
disc_dupl_alert ( b_ptr , orig , & media_addr ) ;
tipc_node_unlock ( n_ptr ) ;
2006-01-02 21:04:38 +03:00
return ;
2011-10-29 01:30:08 +04:00
} else {
memcpy ( & link - > media_addr , & media_addr ,
sizeof ( media_addr ) ) ;
tipc_link_reset ( link ) ;
}
}
/* Create a link endpoint for this bearer, if necessary */
if ( ! link ) {
link = tipc_link_create ( n_ptr , b_ptr , & media_addr ) ;
if ( ! link ) {
tipc_node_unlock ( n_ptr ) ;
return ;
2006-01-02 21:04:38 +03:00
}
2011-02-28 18:03:05 +03:00
}
/* Accept discovery message & send response, if necessary */
link_fully_up = link_working_working ( link ) ;
2011-02-28 18:56:23 +03:00
2011-02-28 19:04:08 +03:00
if ( ( type = = DSC_REQ_MSG ) & & ! link_fully_up & & ! b_ptr - > blocked ) {
2011-02-28 18:56:23 +03:00
rbuf = tipc_disc_init_msg ( DSC_RESP_MSG , orig , b_ptr ) ;
if ( rbuf ) {
2012-11-15 07:34:45 +04:00
tipc_bearer_send ( b_ptr , rbuf , & media_addr ) ;
2011-11-04 21:24:29 +04:00
kfree_skb ( rbuf ) ;
2011-02-28 18:56:23 +03:00
}
2006-01-02 21:04:38 +03:00
}
2011-02-28 18:56:23 +03:00
tipc_node_unlock ( n_ptr ) ;
2006-01-02 21:04:38 +03:00
}
/**
2011-04-22 04:05:25 +04:00
* disc_update - update frequency of periodic link setup requests
2006-01-02 21:04:38 +03:00
* @ req : ptr to link request structure
2011-04-22 05:34:03 +04:00
*
* Reinitiates discovery process if discovery object has no associated nodes
* and is either not currently searching or is searching at a slow rate
2006-01-02 21:04:38 +03:00
*/
2011-12-30 05:58:42 +04:00
static void disc_update ( struct tipc_link_req * req )
2006-01-02 21:04:38 +03:00
{
2011-04-22 05:34:03 +04:00
if ( ! req - > num_nodes ) {
if ( ( req - > timer_intv = = TIPC_LINK_REQ_INACTIVE ) | |
( req - > timer_intv > TIPC_LINK_REQ_FAST ) ) {
req - > timer_intv = TIPC_LINK_REQ_INIT ;
2006-01-02 21:04:38 +03:00
k_start_timer ( & req - > timer , req - > timer_intv ) ;
}
}
2007-02-09 17:25:21 +03:00
}
2006-01-02 21:04:38 +03:00
2011-04-22 04:05:25 +04:00
/**
* tipc_disc_add_dest - increment set of discovered nodes
* @ req : ptr to link request structure
*/
2011-12-30 05:58:42 +04:00
void tipc_disc_add_dest ( struct tipc_link_req * req )
2011-04-22 04:05:25 +04:00
{
req - > num_nodes + + ;
}
/**
* tipc_disc_remove_dest - decrement set of discovered nodes
* @ req : ptr to link request structure
*/
2011-12-30 05:58:42 +04:00
void tipc_disc_remove_dest ( struct tipc_link_req * req )
2011-04-22 04:05:25 +04:00
{
req - > num_nodes - - ;
disc_update ( req ) ;
}
2011-04-22 01:28:02 +04:00
/**
* disc_send_msg - send link setup request message
* @ req : ptr to link request structure
*/
2011-12-30 05:58:42 +04:00
static void disc_send_msg ( struct tipc_link_req * req )
2011-04-22 01:28:02 +04:00
{
if ( ! req - > bearer - > blocked )
tipc_bearer_send ( req - > bearer , req - > buf , & req - > dest ) ;
}
2006-01-02 21:04:38 +03:00
/**
* disc_timeout - send a periodic link setup request
* @ req : ptr to link request structure
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Called whenever a link setup request timer associated with a bearer expires .
*/
2011-12-30 05:58:42 +04:00
static void disc_timeout ( struct tipc_link_req * req )
2006-01-02 21:04:38 +03:00
{
2011-04-22 05:34:03 +04:00
int max_delay ;
2011-01-07 21:00:11 +03:00
spin_lock_bh ( & req - > bearer - > lock ) ;
2006-01-02 21:04:38 +03:00
2011-04-22 05:34:03 +04:00
/* Stop searching if only desired node has been found */
if ( tipc_node ( req - > domain ) & & req - > num_nodes ) {
req - > timer_intv = TIPC_LINK_REQ_INACTIVE ;
goto exit ;
2006-01-02 21:04:38 +03:00
}
2011-04-22 05:34:03 +04:00
/*
* Send discovery message , then update discovery timer
*
* Keep doubling time between requests until limit is reached ;
* hold at fast polling rate if don ' t have any associated nodes ,
* otherwise hold at slow polling rate
*/
disc_send_msg ( req ) ;
req - > timer_intv * = 2 ;
if ( req - > num_nodes )
max_delay = TIPC_LINK_REQ_SLOW ;
else
max_delay = TIPC_LINK_REQ_FAST ;
if ( req - > timer_intv > max_delay )
req - > timer_intv = max_delay ;
k_start_timer ( & req - > timer , req - > timer_intv ) ;
exit :
2011-01-07 21:00:11 +03:00
spin_unlock_bh ( & req - > bearer - > lock ) ;
2006-01-02 21:04:38 +03:00
}
/**
2011-04-21 22:58:26 +04:00
* tipc_disc_create - create object to send periodic link setup requests
2006-01-02 21:04:38 +03:00
* @ b_ptr : ptr to bearer issuing requests
* @ dest : destination address for request messages
2011-04-21 01:24:07 +04:00
* @ dest_domain : network domain to which links can be established
2007-02-09 17:25:21 +03:00
*
2011-04-21 22:58:26 +04:00
* Returns 0 if successful , otherwise - errno .
2006-01-02 21:04:38 +03:00
*/
2011-04-21 22:58:26 +04:00
int tipc_disc_create ( struct tipc_bearer * b_ptr ,
struct tipc_media_addr * dest , u32 dest_domain )
2006-01-02 21:04:38 +03:00
{
2011-12-30 05:58:42 +04:00
struct tipc_link_req * req ;
2006-01-02 21:04:38 +03:00
2006-07-22 02:52:20 +04:00
req = kmalloc ( sizeof ( * req ) , GFP_ATOMIC ) ;
2006-01-02 21:04:38 +03:00
if ( ! req )
2011-04-21 22:58:26 +04:00
return - ENOMEM ;
2006-01-02 21:04:38 +03:00
2011-01-25 22:39:59 +03:00
req - > buf = tipc_disc_init_msg ( DSC_REQ_MSG , dest_domain , b_ptr ) ;
2006-01-02 21:04:38 +03:00
if ( ! req - > buf ) {
kfree ( req ) ;
2011-04-21 22:58:26 +04:00
return - ENOMSG ;
2006-01-02 21:04:38 +03:00
}
memcpy ( & req - > dest , dest , sizeof ( * dest ) ) ;
req - > bearer = b_ptr ;
2011-04-21 01:24:07 +04:00
req - > domain = dest_domain ;
2011-04-22 04:05:25 +04:00
req - > num_nodes = 0 ;
2006-01-02 21:04:38 +03:00
req - > timer_intv = TIPC_LINK_REQ_INIT ;
k_init_timer ( & req - > timer , ( Handler ) disc_timeout , ( unsigned long ) req ) ;
k_start_timer ( & req - > timer , req - > timer_intv ) ;
2011-04-21 22:58:26 +04:00
b_ptr - > link_req = req ;
2011-04-22 01:28:02 +04:00
disc_send_msg ( req ) ;
2011-04-21 22:58:26 +04:00
return 0 ;
}
/**
* tipc_disc_delete - destroy object sending periodic link setup requests
* @ req : ptr to link request structure
*/
2011-12-30 05:58:42 +04:00
void tipc_disc_delete ( struct tipc_link_req * req )
2011-04-21 22:58:26 +04:00
{
k_cancel_timer ( & req - > timer ) ;
k_term_timer ( & req - > timer ) ;
2011-11-04 21:24:29 +04:00
kfree_skb ( req - > buf ) ;
2011-04-21 22:58:26 +04:00
kfree ( req ) ;
2007-02-09 17:25:21 +03:00
}