2006-01-02 21:04:38 +03:00
/*
* net / tipc / bearer . c : TIPC bearer code
2007-02-09 17:25:21 +03:00
*
2006-01-11 21:14:19 +03:00
* Copyright ( c ) 1996 - 2006 , Ericsson AB
2006-10-17 08:44:59 +04:00
* Copyright ( c ) 2004 - 2006 , 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 "config.h"
# include "dbg.h"
# include "bearer.h"
# include "link.h"
# include "port.h"
# include "discover.h"
# include "bcast.h"
# define MAX_ADDR_STR 32
2006-03-21 09:36:47 +03:00
static struct media * media_list = NULL ;
2006-01-02 21:04:38 +03:00
static u32 media_count = 0 ;
2006-03-21 09:36:47 +03:00
struct bearer * tipc_bearers = NULL ;
2006-01-02 21:04:38 +03:00
/**
* media_name_valid - validate media name
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Returns 1 if media name is valid , otherwise 0.
*/
static int media_name_valid ( const char * name )
{
u32 len ;
len = strlen ( name ) ;
if ( ( len + 1 ) > TIPC_MAX_MEDIA_NAME )
return 0 ;
return ( strspn ( name , tipc_alphabet ) = = len ) ;
}
/**
* media_find - locates specified media object by name
*/
static struct media * media_find ( const char * name )
{
struct media * m_ptr ;
u32 i ;
for ( i = 0 , m_ptr = media_list ; i < media_count ; i + + , m_ptr + + ) {
if ( ! strcmp ( m_ptr - > name , name ) )
return m_ptr ;
}
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
/**
* tipc_register_media - register a media type
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Bearers for this media type must be activated separately at a later stage .
*/
int tipc_register_media ( u32 media_type ,
2007-02-09 17:25:21 +03:00
char * name ,
int ( * enable ) ( struct tipc_bearer * ) ,
void ( * disable ) ( struct tipc_bearer * ) ,
int ( * send_msg ) ( struct sk_buff * ,
2006-01-02 21:04:38 +03:00
struct tipc_bearer * ,
2007-02-09 17:25:21 +03:00
struct tipc_media_addr * ) ,
2006-01-02 21:04:38 +03:00
char * ( * addr2str ) ( struct tipc_media_addr * a ,
char * str_buf , int str_size ) ,
struct tipc_media_addr * bcast_addr ,
const u32 bearer_priority ,
const u32 link_tolerance , /* [ms] */
const u32 send_window_limit )
{
struct media * m_ptr ;
u32 media_id ;
u32 i ;
int res = - EINVAL ;
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
if ( ! media_list )
goto exit ;
if ( ! media_name_valid ( name ) ) {
2006-06-26 10:52:17 +04:00
warn ( " Media <%s> rejected, illegal name \n " , name ) ;
2006-01-02 21:04:38 +03:00
goto exit ;
}
if ( ! bcast_addr ) {
2006-06-26 10:52:17 +04:00
warn ( " Media <%s> rejected, no broadcast address \n " , name ) ;
2006-01-02 21:04:38 +03:00
goto exit ;
}
2006-01-14 00:22:22 +03:00
if ( ( bearer_priority < TIPC_MIN_LINK_PRI ) & &
( bearer_priority > TIPC_MAX_LINK_PRI ) ) {
2007-02-09 17:25:21 +03:00
warn ( " Media <%s> rejected, illegal priority (%u) \n " , name ,
2006-06-26 10:52:17 +04:00
bearer_priority ) ;
2006-01-02 21:04:38 +03:00
goto exit ;
}
2007-02-09 17:25:21 +03:00
if ( ( link_tolerance < TIPC_MIN_LINK_TOL ) | |
2006-01-02 21:04:38 +03:00
( link_tolerance > TIPC_MAX_LINK_TOL ) ) {
2006-06-26 10:52:17 +04:00
warn ( " Media <%s> rejected, illegal tolerance (%u) \n " , name ,
link_tolerance ) ;
2006-01-02 21:04:38 +03:00
goto exit ;
}
media_id = media_count + + ;
if ( media_id > = MAX_MEDIA ) {
2006-06-26 10:52:17 +04:00
warn ( " Media <%s> rejected, media limit reached (%u) \n " , name ,
MAX_MEDIA ) ;
2006-01-02 21:04:38 +03:00
media_count - - ;
goto exit ;
}
for ( i = 0 ; i < media_id ; i + + ) {
if ( media_list [ i ] . type_id = = media_type ) {
2006-06-26 10:52:17 +04:00
warn ( " Media <%s> rejected, duplicate type (%u) \n " , name ,
2006-01-02 21:04:38 +03:00
media_type ) ;
media_count - - ;
goto exit ;
}
if ( ! strcmp ( name , media_list [ i ] . name ) ) {
2006-06-26 10:52:17 +04:00
warn ( " Media <%s> rejected, duplicate name \n " , name ) ;
2006-01-02 21:04:38 +03:00
media_count - - ;
goto exit ;
}
}
m_ptr = & media_list [ media_id ] ;
m_ptr - > type_id = media_type ;
m_ptr - > send_msg = send_msg ;
m_ptr - > enable_bearer = enable ;
m_ptr - > disable_bearer = disable ;
m_ptr - > addr2str = addr2str ;
memcpy ( & m_ptr - > bcast_addr , bcast_addr , sizeof ( * bcast_addr ) ) ;
m_ptr - > bcast = 1 ;
strcpy ( m_ptr - > name , name ) ;
m_ptr - > priority = bearer_priority ;
m_ptr - > tolerance = link_tolerance ;
m_ptr - > window = send_window_limit ;
dbg ( " Media <%s> registered \n " , name ) ;
res = 0 ;
exit :
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_media_addr_printf - record media address in print buffer
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
void tipc_media_addr_printf ( struct print_buf * pb , struct tipc_media_addr * a )
2006-01-02 21:04:38 +03:00
{
struct media * m_ptr ;
u32 media_type ;
u32 i ;
media_type = ntohl ( a - > type ) ;
for ( i = 0 , m_ptr = media_list ; i < media_count ; i + + , m_ptr + + ) {
if ( m_ptr - > type_id = = media_type )
break ;
}
if ( ( i < media_count ) & & ( m_ptr - > addr2str ! = NULL ) ) {
char addr_str [ MAX_ADDR_STR ] ;
2006-10-17 08:44:59 +04:00
tipc_printf ( pb , " %s(%s) " , m_ptr - > name ,
2006-01-02 21:04:38 +03:00
m_ptr - > addr2str ( a , addr_str , sizeof ( addr_str ) ) ) ;
} else {
unchar * addr = ( unchar * ) & a - > dev_addr ;
2006-10-17 08:44:59 +04:00
tipc_printf ( pb , " UNKNOWN(%u) " , media_type ) ;
2006-01-02 21:04:38 +03:00
for ( i = 0 ; i < ( sizeof ( * a ) - sizeof ( a - > type ) ) ; i + + ) {
2006-10-17 08:44:59 +04:00
tipc_printf ( pb , " -%02x " , addr [ i ] ) ;
2006-01-02 21:04:38 +03:00
}
}
}
/**
2006-01-18 02:38:21 +03:00
* tipc_media_get_names - record names of registered media in buffer
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
struct sk_buff * tipc_media_get_names ( void )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * buf ;
struct media * m_ptr ;
int i ;
2006-01-18 02:38:21 +03:00
buf = tipc_cfg_reply_alloc ( MAX_MEDIA * TLV_SPACE ( TIPC_MAX_MEDIA_NAME ) ) ;
2006-01-02 21:04:38 +03:00
if ( ! buf )
return NULL ;
2006-01-18 02:38:21 +03:00
read_lock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
for ( i = 0 , m_ptr = media_list ; i < media_count ; i + + , m_ptr + + ) {
2007-02-09 17:25:21 +03:00
tipc_cfg_append_tlv ( buf , TIPC_TLV_MEDIA_NAME , m_ptr - > name ,
2006-01-18 02:38:21 +03:00
strlen ( m_ptr - > name ) + 1 ) ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
return buf ;
}
/**
* bearer_name_validate - validate & ( optionally ) deconstruct bearer name
* @ name - ptr to bearer name string
* @ name_parts - ptr to area for bearer name components ( or NULL if not needed )
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Returns 1 if bearer name is valid , otherwise 0.
*/
2007-02-09 17:25:21 +03:00
static int bearer_name_validate ( const char * name ,
2006-01-02 21:04:38 +03:00
struct bearer_name * name_parts )
{
char name_copy [ TIPC_MAX_BEARER_NAME ] ;
char * media_name ;
char * if_name ;
u32 media_len ;
u32 if_len ;
/* copy bearer name & ensure length is OK */
name_copy [ TIPC_MAX_BEARER_NAME - 1 ] = 0 ;
/* need above in case non-Posix strncpy() doesn't pad with nulls */
strncpy ( name_copy , name , TIPC_MAX_BEARER_NAME ) ;
if ( name_copy [ TIPC_MAX_BEARER_NAME - 1 ] ! = 0 )
return 0 ;
/* ensure all component parts of bearer name are present */
media_name = name_copy ;
if ( ( if_name = strchr ( media_name , ' : ' ) ) = = NULL )
return 0 ;
* ( if_name + + ) = 0 ;
media_len = if_name - media_name ;
if_len = strlen ( if_name ) + 1 ;
/* validate component parts of bearer name */
2007-02-09 17:25:21 +03:00
if ( ( media_len < = 1 ) | | ( media_len > TIPC_MAX_MEDIA_NAME ) | |
( if_len < = 1 ) | | ( if_len > TIPC_MAX_IF_NAME ) | |
2006-01-02 21:04:38 +03:00
( strspn ( media_name , tipc_alphabet ) ! = ( media_len - 1 ) ) | |
( strspn ( if_name , tipc_alphabet ) ! = ( if_len - 1 ) ) )
return 0 ;
/* return bearer name components, if necessary */
if ( name_parts ) {
strcpy ( name_parts - > media_name , media_name ) ;
strcpy ( name_parts - > if_name , if_name ) ;
}
return 1 ;
}
/**
* bearer_find - locates bearer object with matching bearer name
*/
static struct bearer * bearer_find ( const char * name )
{
struct bearer * b_ptr ;
u32 i ;
2006-06-26 10:52:17 +04:00
if ( tipc_mode ! = TIPC_NET_MODE )
return NULL ;
2006-01-18 02:38:21 +03:00
for ( i = 0 , b_ptr = tipc_bearers ; i < MAX_BEARERS ; i + + , b_ptr + + ) {
2006-01-02 21:04:38 +03:00
if ( b_ptr - > active & & ( ! strcmp ( b_ptr - > publ . name , name ) ) )
return b_ptr ;
}
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_bearer_find_interface - locates bearer object with matching interface name
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
struct bearer * tipc_bearer_find_interface ( const char * if_name )
2006-01-02 21:04:38 +03:00
{
struct bearer * b_ptr ;
char * b_if_name ;
u32 i ;
2006-01-18 02:38:21 +03:00
for ( i = 0 , b_ptr = tipc_bearers ; i < MAX_BEARERS ; i + + , b_ptr + + ) {
2006-01-02 21:04:38 +03:00
if ( ! b_ptr - > active )
continue ;
b_if_name = strchr ( b_ptr - > publ . name , ' : ' ) + 1 ;
if ( ! strcmp ( b_if_name , if_name ) )
return b_ptr ;
}
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_bearer_get_names - record names of bearers in buffer
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
struct sk_buff * tipc_bearer_get_names ( void )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * buf ;
struct media * m_ptr ;
struct bearer * b_ptr ;
int i , j ;
2006-01-18 02:38:21 +03:00
buf = tipc_cfg_reply_alloc ( MAX_BEARERS * TLV_SPACE ( TIPC_MAX_BEARER_NAME ) ) ;
2006-01-02 21:04:38 +03:00
if ( ! buf )
return NULL ;
2006-01-18 02:38:21 +03:00
read_lock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
for ( i = 0 , m_ptr = media_list ; i < media_count ; i + + , m_ptr + + ) {
for ( j = 0 ; j < MAX_BEARERS ; j + + ) {
2006-01-18 02:38:21 +03:00
b_ptr = & tipc_bearers [ j ] ;
2006-01-02 21:04:38 +03:00
if ( b_ptr - > active & & ( b_ptr - > media = = m_ptr ) ) {
2007-02-09 17:25:21 +03:00
tipc_cfg_append_tlv ( buf , TIPC_TLV_BEARER_NAME ,
b_ptr - > publ . name ,
2006-01-18 02:38:21 +03:00
strlen ( b_ptr - > publ . name ) + 1 ) ;
2006-01-02 21:04:38 +03:00
}
}
}
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
return buf ;
}
2006-01-18 02:38:21 +03:00
void tipc_bearer_add_dest ( struct bearer * b_ptr , u32 dest )
2006-01-02 21:04:38 +03:00
{
2006-01-18 02:38:21 +03:00
tipc_nmap_add ( & b_ptr - > nodes , dest ) ;
tipc_disc_update_link_req ( b_ptr - > link_req ) ;
tipc_bcbearer_sort ( ) ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
void tipc_bearer_remove_dest ( struct bearer * b_ptr , u32 dest )
2006-01-02 21:04:38 +03:00
{
2006-01-18 02:38:21 +03:00
tipc_nmap_remove ( & b_ptr - > nodes , dest ) ;
tipc_disc_update_link_req ( b_ptr - > link_req ) ;
tipc_bcbearer_sort ( ) ;
2006-01-02 21:04:38 +03:00
}
/*
* bearer_push ( ) : Resolve bearer congestion . Force the waiting
* links to push out their unsent packets , one packet per link
* per iteration , until all packets are gone or congestion reoccurs .
2006-01-18 02:38:21 +03:00
* ' tipc_net_lock ' is read_locked when this function is called
2006-01-02 21:04:38 +03:00
* bearer . lock must be taken before calling
* Returns binary true ( 1 ) ore false ( 0 )
*/
static int bearer_push ( struct bearer * b_ptr )
{
u32 res = TIPC_OK ;
struct link * ln , * tln ;
if ( b_ptr - > publ . blocked )
return 0 ;
while ( ! list_empty ( & b_ptr - > cong_links ) & & ( res ! = PUSH_FAILED ) ) {
list_for_each_entry_safe ( ln , tln , & b_ptr - > cong_links , link_list ) {
2006-01-18 02:38:21 +03:00
res = tipc_link_push_packet ( ln ) ;
2006-01-02 21:04:38 +03:00
if ( res = = PUSH_FAILED )
break ;
if ( res = = PUSH_FINISHED )
list_move_tail ( & ln - > link_list , & b_ptr - > links ) ;
}
}
return list_empty ( & b_ptr - > cong_links ) ;
}
2006-01-18 02:38:21 +03:00
void tipc_bearer_lock_push ( struct bearer * b_ptr )
2006-01-02 21:04:38 +03:00
{
int res ;
spin_lock_bh ( & b_ptr - > publ . lock ) ;
res = bearer_push ( b_ptr ) ;
spin_unlock_bh ( & b_ptr - > publ . lock ) ;
if ( res )
2006-01-18 02:38:21 +03:00
tipc_bcbearer_push ( ) ;
2006-01-02 21:04:38 +03:00
}
/*
2007-02-09 17:25:21 +03:00
* Interrupt enabling new requests after bearer congestion or blocking :
* See bearer_send ( ) .
2006-01-02 21:04:38 +03:00
*/
void tipc_continue ( struct tipc_bearer * tb_ptr )
{
struct bearer * b_ptr = ( struct bearer * ) tb_ptr ;
spin_lock_bh ( & b_ptr - > publ . lock ) ;
b_ptr - > continue_count + + ;
if ( ! list_empty ( & b_ptr - > cong_links ) )
2006-01-18 02:38:21 +03:00
tipc_k_signal ( ( Handler ) tipc_bearer_lock_push , ( unsigned long ) b_ptr ) ;
2006-01-02 21:04:38 +03:00
b_ptr - > publ . blocked = 0 ;
spin_unlock_bh ( & b_ptr - > publ . lock ) ;
}
/*
2007-02-09 17:25:21 +03:00
* Schedule link for sending of messages after the bearer
* has been deblocked by ' continue ( ) ' . This method is called
* when somebody tries to send a message via this link while
2006-01-18 02:38:21 +03:00
* the bearer is congested . ' tipc_net_lock ' is in read_lock here
2006-01-02 21:04:38 +03:00
* bearer . lock is busy
*/
2006-01-18 02:38:21 +03:00
static void tipc_bearer_schedule_unlocked ( struct bearer * b_ptr , struct link * l_ptr )
2006-01-02 21:04:38 +03:00
{
list_move_tail ( & l_ptr - > link_list , & b_ptr - > cong_links ) ;
}
/*
2007-02-09 17:25:21 +03:00
* Schedule link for sending of messages after the bearer
* has been deblocked by ' continue ( ) ' . This method is called
* when somebody tries to send a message via this link while
2006-01-18 02:38:21 +03:00
* the bearer is congested . ' tipc_net_lock ' is in read_lock here ,
2006-01-02 21:04:38 +03:00
* bearer . lock is free
*/
2006-01-18 02:38:21 +03:00
void tipc_bearer_schedule ( struct bearer * b_ptr , struct link * l_ptr )
2006-01-02 21:04:38 +03:00
{
spin_lock_bh ( & b_ptr - > publ . lock ) ;
2006-01-18 02:38:21 +03:00
tipc_bearer_schedule_unlocked ( b_ptr , l_ptr ) ;
2006-01-02 21:04:38 +03:00
spin_unlock_bh ( & b_ptr - > publ . lock ) ;
}
/*
2006-01-18 02:38:21 +03:00
* tipc_bearer_resolve_congestion ( ) : Check if there is bearer congestion ,
2006-01-02 21:04:38 +03:00
* and if there is , try to resolve it before returning .
2006-01-18 02:38:21 +03:00
* ' tipc_net_lock ' is read_locked when this function is called
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
int tipc_bearer_resolve_congestion ( struct bearer * b_ptr , struct link * l_ptr )
2006-01-02 21:04:38 +03:00
{
int res = 1 ;
if ( list_empty ( & b_ptr - > cong_links ) )
return 1 ;
spin_lock_bh ( & b_ptr - > publ . lock ) ;
if ( ! bearer_push ( b_ptr ) ) {
2006-01-18 02:38:21 +03:00
tipc_bearer_schedule_unlocked ( b_ptr , l_ptr ) ;
2006-01-02 21:04:38 +03:00
res = 0 ;
}
spin_unlock_bh ( & b_ptr - > publ . lock ) ;
return res ;
}
/**
* tipc_enable_bearer - enable bearer with the given name
2007-02-09 17:25:21 +03:00
*/
2006-01-02 21:04:38 +03:00
int tipc_enable_bearer ( const char * name , u32 bcast_scope , u32 priority )
{
struct bearer * b_ptr ;
struct media * m_ptr ;
struct bearer_name b_name ;
char addr_string [ 16 ] ;
u32 bearer_id ;
u32 with_this_prio ;
u32 i ;
int res = - EINVAL ;
2006-06-26 10:52:17 +04:00
if ( tipc_mode ! = TIPC_NET_MODE ) {
warn ( " Bearer <%s> rejected, not supported in standalone mode \n " ,
name ) ;
2006-01-02 21:04:38 +03:00
return - ENOPROTOOPT ;
2006-06-26 10:52:17 +04:00
}
if ( ! bearer_name_validate ( name , & b_name ) ) {
warn ( " Bearer <%s> rejected, illegal name \n " , name ) ;
2006-01-14 00:22:22 +03:00
return - EINVAL ;
2006-06-26 10:52:17 +04:00
}
2007-02-09 17:25:21 +03:00
if ( ! tipc_addr_domain_valid ( bcast_scope ) | |
2006-06-26 10:52:17 +04:00
! in_scope ( bcast_scope , tipc_own_addr ) ) {
warn ( " Bearer <%s> rejected, illegal broadcast scope \n " , name ) ;
return - EINVAL ;
}
2006-01-14 00:22:22 +03:00
if ( ( priority < TIPC_MIN_LINK_PRI | |
priority > TIPC_MAX_LINK_PRI ) & &
2006-06-26 10:52:17 +04:00
( priority ! = TIPC_MEDIA_LINK_PRI ) ) {
warn ( " Bearer <%s> rejected, illegal priority \n " , name ) ;
2006-01-02 21:04:38 +03:00
return - EINVAL ;
2006-06-26 10:52:17 +04:00
}
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
m_ptr = media_find ( b_name . media_name ) ;
if ( ! m_ptr ) {
2006-06-26 10:52:17 +04:00
warn ( " Bearer <%s> rejected, media <%s> not registered \n " , name ,
b_name . media_name ) ;
2006-01-02 21:04:38 +03:00
goto failed ;
}
2006-01-14 00:22:22 +03:00
if ( priority = = TIPC_MEDIA_LINK_PRI )
2006-01-02 21:04:38 +03:00
priority = m_ptr - > priority ;
restart :
bearer_id = MAX_BEARERS ;
with_this_prio = 1 ;
for ( i = MAX_BEARERS ; i - - ! = 0 ; ) {
2006-01-18 02:38:21 +03:00
if ( ! tipc_bearers [ i ] . active ) {
2006-01-02 21:04:38 +03:00
bearer_id = i ;
continue ;
}
2006-01-18 02:38:21 +03:00
if ( ! strcmp ( name , tipc_bearers [ i ] . publ . name ) ) {
2006-06-26 10:52:17 +04:00
warn ( " Bearer <%s> rejected, already enabled \n " , name ) ;
2006-01-02 21:04:38 +03:00
goto failed ;
}
2006-01-18 02:38:21 +03:00
if ( ( tipc_bearers [ i ] . priority = = priority ) & &
2006-01-02 21:04:38 +03:00
( + + with_this_prio > 2 ) ) {
if ( priority - - = = 0 ) {
2006-06-26 10:52:17 +04:00
warn ( " Bearer <%s> rejected, duplicate priority \n " ,
name ) ;
2006-01-02 21:04:38 +03:00
goto failed ;
}
2006-06-26 10:52:17 +04:00
warn ( " Bearer <%s> priority adjustment required %u->%u \n " ,
2006-01-02 21:04:38 +03:00
name , priority + 1 , priority ) ;
goto restart ;
}
}
if ( bearer_id > = MAX_BEARERS ) {
2007-02-09 17:25:21 +03:00
warn ( " Bearer <%s> rejected, bearer limit reached (%u) \n " ,
2006-06-26 10:52:17 +04:00
name , MAX_BEARERS ) ;
2006-01-02 21:04:38 +03:00
goto failed ;
}
2006-01-18 02:38:21 +03:00
b_ptr = & tipc_bearers [ bearer_id ] ;
2006-01-02 21:04:38 +03:00
memset ( b_ptr , 0 , sizeof ( struct bearer ) ) ;
strcpy ( b_ptr - > publ . name , name ) ;
res = m_ptr - > enable_bearer ( & b_ptr - > publ ) ;
if ( res ) {
2006-06-26 10:52:17 +04:00
warn ( " Bearer <%s> rejected, enable failure (%d) \n " , name , - res ) ;
2006-01-02 21:04:38 +03:00
goto failed ;
}
b_ptr - > identity = bearer_id ;
b_ptr - > media = m_ptr ;
b_ptr - > net_plane = bearer_id + ' A ' ;
b_ptr - > active = 1 ;
b_ptr - > detect_scope = bcast_scope ;
b_ptr - > priority = priority ;
INIT_LIST_HEAD ( & b_ptr - > cong_links ) ;
INIT_LIST_HEAD ( & b_ptr - > links ) ;
if ( m_ptr - > bcast ) {
2006-01-18 02:38:21 +03:00
b_ptr - > link_req = tipc_disc_init_link_req ( b_ptr , & m_ptr - > bcast_addr ,
bcast_scope , 2 ) ;
2006-01-02 21:04:38 +03:00
}
2006-06-27 13:53:55 +04:00
spin_lock_init ( & b_ptr - > publ . lock ) ;
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_net_lock ) ;
2006-01-14 00:22:22 +03:00
info ( " Enabled bearer <%s>, discovery domain %s, priority %u \n " ,
name , addr_string_fill ( addr_string , bcast_scope ) , priority ) ;
2006-01-02 21:04:38 +03:00
return 0 ;
failed :
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
/**
* tipc_block_bearer ( ) : Block the bearer with the given name ,
* and reset all its links
*/
int tipc_block_bearer ( const char * name )
{
2006-03-21 09:36:47 +03:00
struct bearer * b_ptr = NULL ;
2006-01-02 21:04:38 +03:00
struct link * l_ptr ;
struct link * temp_l_ptr ;
2006-01-18 02:38:21 +03:00
read_lock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
b_ptr = bearer_find ( name ) ;
if ( ! b_ptr ) {
warn ( " Attempt to block unknown bearer <%s> \n " , name ) ;
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
return - EINVAL ;
}
2006-06-26 10:52:17 +04:00
info ( " Blocking bearer <%s> \n " , name ) ;
2006-01-02 21:04:38 +03:00
spin_lock_bh ( & b_ptr - > publ . lock ) ;
b_ptr - > publ . blocked = 1 ;
list_for_each_entry_safe ( l_ptr , temp_l_ptr , & b_ptr - > links , link_list ) {
struct node * n_ptr = l_ptr - > owner ;
spin_lock_bh ( & n_ptr - > lock ) ;
2006-01-18 02:38:21 +03:00
tipc_link_reset ( l_ptr ) ;
2006-01-02 21:04:38 +03:00
spin_unlock_bh ( & n_ptr - > lock ) ;
}
spin_unlock_bh ( & b_ptr - > publ . lock ) ;
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
return TIPC_OK ;
}
/**
* bearer_disable -
2007-02-09 17:25:21 +03:00
*
2006-01-18 02:38:21 +03:00
* Note : This routine assumes caller holds tipc_net_lock .
2006-01-02 21:04:38 +03:00
*/
static int bearer_disable ( const char * name )
{
struct bearer * b_ptr ;
struct link * l_ptr ;
struct link * temp_l_ptr ;
b_ptr = bearer_find ( name ) ;
if ( ! b_ptr ) {
warn ( " Attempt to disable unknown bearer <%s> \n " , name ) ;
return - EINVAL ;
}
2006-06-26 10:52:17 +04:00
info ( " Disabling bearer <%s> \n " , name ) ;
2006-01-18 02:38:21 +03:00
tipc_disc_stop_link_req ( b_ptr - > link_req ) ;
2006-01-02 21:04:38 +03:00
spin_lock_bh ( & b_ptr - > publ . lock ) ;
b_ptr - > link_req = NULL ;
b_ptr - > publ . blocked = 1 ;
if ( b_ptr - > media - > disable_bearer ) {
spin_unlock_bh ( & b_ptr - > publ . lock ) ;
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
b_ptr - > media - > disable_bearer ( & b_ptr - > publ ) ;
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
spin_lock_bh ( & b_ptr - > publ . lock ) ;
}
list_for_each_entry_safe ( l_ptr , temp_l_ptr , & b_ptr - > links , link_list ) {
2006-01-18 02:38:21 +03:00
tipc_link_delete ( l_ptr ) ;
2006-01-02 21:04:38 +03:00
}
spin_unlock_bh ( & b_ptr - > publ . lock ) ;
memset ( b_ptr , 0 , sizeof ( struct bearer ) ) ;
return TIPC_OK ;
}
int tipc_disable_bearer ( const char * name )
{
int res ;
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
res = bearer_disable ( name ) ;
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
2006-01-18 02:38:21 +03:00
int tipc_bearer_init ( void )
2006-01-02 21:04:38 +03:00
{
int res ;
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_net_lock ) ;
2006-07-22 01:51:30 +04:00
tipc_bearers = kcalloc ( MAX_BEARERS , sizeof ( struct bearer ) , GFP_ATOMIC ) ;
media_list = kcalloc ( MAX_MEDIA , sizeof ( struct media ) , GFP_ATOMIC ) ;
2006-01-18 02:38:21 +03:00
if ( tipc_bearers & & media_list ) {
2006-01-02 21:04:38 +03:00
res = TIPC_OK ;
} else {
2006-01-18 02:38:21 +03:00
kfree ( tipc_bearers ) ;
2006-01-02 21:04:38 +03:00
kfree ( media_list ) ;
2006-03-21 09:36:47 +03:00
tipc_bearers = NULL ;
media_list = NULL ;
2006-01-02 21:04:38 +03:00
res = - ENOMEM ;
}
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
2006-01-18 02:38:21 +03:00
void tipc_bearer_stop ( void )
2006-01-02 21:04:38 +03:00
{
u32 i ;
2006-01-18 02:38:21 +03:00
if ( ! tipc_bearers )
2006-01-02 21:04:38 +03:00
return ;
for ( i = 0 ; i < MAX_BEARERS ; i + + ) {
2006-01-18 02:38:21 +03:00
if ( tipc_bearers [ i ] . active )
tipc_bearers [ i ] . publ . blocked = 1 ;
2006-01-02 21:04:38 +03:00
}
for ( i = 0 ; i < MAX_BEARERS ; i + + ) {
2006-01-18 02:38:21 +03:00
if ( tipc_bearers [ i ] . active )
bearer_disable ( tipc_bearers [ i ] . publ . name ) ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
kfree ( tipc_bearers ) ;
2006-01-02 21:04:38 +03:00
kfree ( media_list ) ;
2006-03-21 09:36:47 +03:00
tipc_bearers = NULL ;
media_list = NULL ;
2006-01-02 21:04:38 +03:00
media_count = 0 ;
}