2006-01-02 21:04:38 +03:00
/*
* net / tipc / port . c : TIPC port code
2007-02-09 17:25:21 +03:00
*
2007-06-11 04:25:24 +04:00
* Copyright ( c ) 1992 - 2007 , Ericsson AB
* Copyright ( c ) 2004 - 2007 , 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 "port.h"
# include "addr.h"
# include "link.h"
# include "node.h"
# include "port.h"
# include "name_table.h"
# include "user_reg.h"
# include "msg.h"
# include "bcast.h"
/* Connection management: */
# define PROBING_INTERVAL 3600000 /* [ms] => 1 h */
# define CONFIRMED 0
# define PROBING 1
# define MAX_REJECT_SIZE 1024
2006-03-21 09:36:47 +03:00
static struct sk_buff * msg_queue_head = NULL ;
static struct sk_buff * msg_queue_tail = NULL ;
2006-01-02 21:04:38 +03:00
2006-06-27 13:53:55 +04:00
DEFINE_SPINLOCK ( tipc_port_list_lock ) ;
static DEFINE_SPINLOCK ( queue_lock ) ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
static LIST_HEAD ( ports ) ;
2006-01-02 21:04:38 +03:00
static void port_handle_node_down ( unsigned long ref ) ;
static struct sk_buff * port_build_self_abort_msg ( struct port * , u32 err ) ;
static struct sk_buff * port_build_peer_abort_msg ( struct port * , u32 err ) ;
static void port_timeout ( unsigned long ref ) ;
2006-03-21 09:37:04 +03:00
static u32 port_peernode ( struct port * p_ptr )
2006-01-02 21:04:38 +03:00
{
return msg_destnode ( & p_ptr - > publ . phdr ) ;
}
2006-03-21 09:37:04 +03:00
static u32 port_peerport ( struct port * p_ptr )
2006-01-02 21:04:38 +03:00
{
return msg_destport ( & p_ptr - > publ . phdr ) ;
}
2006-03-21 09:37:04 +03:00
static u32 port_out_seqno ( struct port * p_ptr )
2006-01-02 21:04:38 +03:00
{
return msg_transp_seqno ( & p_ptr - > publ . phdr ) ;
}
2006-03-21 09:37:04 +03:00
static void port_incr_out_seqno ( struct port * p_ptr )
2006-01-02 21:04:38 +03:00
{
struct tipc_msg * m = & p_ptr - > publ . phdr ;
if ( likely ( ! msg_routed ( m ) ) )
return ;
msg_set_transp_seqno ( m , ( msg_transp_seqno ( m ) + 1 ) ) ;
}
/**
* tipc_multicast - send a multicast message to local and remote destinations
*/
int tipc_multicast ( u32 ref , struct tipc_name_seq const * seq , u32 domain ,
u32 num_sect , struct iovec const * msg_sect )
{
struct tipc_msg * hdr ;
struct sk_buff * buf ;
struct sk_buff * ibuf = NULL ;
struct port_list dports = { 0 , NULL , } ;
2006-01-18 02:38:21 +03:00
struct port * oport = tipc_port_deref ( ref ) ;
2006-01-02 21:04:38 +03:00
int ext_targets ;
int res ;
if ( unlikely ( ! oport ) )
return - EINVAL ;
/* Create multicast message */
hdr = & oport - > publ . phdr ;
msg_set_type ( hdr , TIPC_MCAST_MSG ) ;
msg_set_nametype ( hdr , seq - > type ) ;
msg_set_namelower ( hdr , seq - > lower ) ;
msg_set_nameupper ( hdr , seq - > upper ) ;
msg_set_hdr_sz ( hdr , MCAST_H_SIZE ) ;
res = msg_build ( hdr , msg_sect , num_sect , MAX_MSG_SIZE ,
! oport - > user_port , & buf ) ;
if ( unlikely ( ! buf ) )
return res ;
/* Figure out where to send multicast message */
2006-01-18 02:38:21 +03:00
ext_targets = tipc_nametbl_mc_translate ( seq - > type , seq - > lower , seq - > upper ,
TIPC_NODE_SCOPE , & dports ) ;
2007-02-09 17:25:21 +03:00
/* Send message to destinations (duplicate it only if necessary) */
2006-01-02 21:04:38 +03:00
if ( ext_targets ) {
if ( dports . count ! = 0 ) {
ibuf = skb_copy ( buf , GFP_ATOMIC ) ;
if ( ibuf = = NULL ) {
2006-01-18 02:38:21 +03:00
tipc_port_list_free ( & dports ) ;
2006-01-02 21:04:38 +03:00
buf_discard ( buf ) ;
return - ENOMEM ;
}
}
2006-01-18 02:38:21 +03:00
res = tipc_bclink_send_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
if ( ( res < 0 ) & & ( dports . count ! = 0 ) ) {
buf_discard ( ibuf ) ;
}
} else {
ibuf = buf ;
}
if ( res > = 0 ) {
if ( ibuf )
2006-01-18 02:38:21 +03:00
tipc_port_recv_mcast ( ibuf , & dports ) ;
2006-01-02 21:04:38 +03:00
} else {
2006-01-18 02:38:21 +03:00
tipc_port_list_free ( & dports ) ;
2006-01-02 21:04:38 +03:00
}
return res ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_port_recv_mcast - deliver multicast message to all destination ports
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* If there is no port list , perform a lookup to create one
*/
2006-01-18 02:38:21 +03:00
void tipc_port_recv_mcast ( struct sk_buff * buf , struct port_list * dp )
2006-01-02 21:04:38 +03:00
{
struct tipc_msg * msg ;
struct port_list dports = { 0 , NULL , } ;
struct port_list * item = dp ;
int cnt = 0 ;
msg = buf_msg ( buf ) ;
/* Create destination port list, if one wasn't supplied */
if ( dp = = NULL ) {
2006-01-18 02:38:21 +03:00
tipc_nametbl_mc_translate ( msg_nametype ( msg ) ,
2006-01-02 21:04:38 +03:00
msg_namelower ( msg ) ,
msg_nameupper ( msg ) ,
TIPC_CLUSTER_SCOPE ,
& dports ) ;
item = dp = & dports ;
}
/* Deliver a copy of message to each destination port */
if ( dp - > count ! = 0 ) {
if ( dp - > count = = 1 ) {
msg_set_destport ( msg , dp - > ports [ 0 ] ) ;
2006-01-18 02:38:21 +03:00
tipc_port_recv_msg ( buf ) ;
tipc_port_list_free ( dp ) ;
2006-01-02 21:04:38 +03:00
return ;
}
for ( ; cnt < dp - > count ; cnt + + ) {
int index = cnt % PLSIZE ;
struct sk_buff * b = skb_clone ( buf , GFP_ATOMIC ) ;
if ( b = = NULL ) {
2006-06-26 10:52:17 +04:00
warn ( " Unable to deliver multicast message(s) \n " ) ;
2006-01-02 21:04:38 +03:00
msg_dbg ( msg , " LOST: " ) ;
goto exit ;
}
if ( ( index = = 0 ) & & ( cnt ! = 0 ) ) {
item = item - > next ;
}
msg_set_destport ( buf_msg ( b ) , item - > ports [ index ] ) ;
2006-01-18 02:38:21 +03:00
tipc_port_recv_msg ( b ) ;
2006-01-02 21:04:38 +03:00
}
}
exit :
buf_discard ( buf ) ;
2006-01-18 02:38:21 +03:00
tipc_port_list_free ( dp ) ;
2006-01-02 21:04:38 +03:00
}
/**
* tipc_createport_raw - create a native TIPC port
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Returns local port reference
*/
u32 tipc_createport_raw ( void * usr_handle ,
u32 ( * dispatcher ) ( struct tipc_port * , struct sk_buff * ) ,
void ( * wakeup ) ( struct tipc_port * ) ,
const u32 importance )
{
struct port * p_ptr ;
struct tipc_msg * msg ;
u32 ref ;
2006-07-22 01:51:30 +04:00
p_ptr = kzalloc ( sizeof ( * p_ptr ) , GFP_ATOMIC ) ;
2006-06-26 10:52:17 +04:00
if ( ! p_ptr ) {
warn ( " Port creation failed, no memory \n " ) ;
2006-01-02 21:04:38 +03:00
return 0 ;
}
2006-01-18 02:38:21 +03:00
ref = tipc_ref_acquire ( p_ptr , & p_ptr - > publ . lock ) ;
2006-01-02 21:04:38 +03:00
if ( ! ref ) {
2006-06-26 10:52:17 +04:00
warn ( " Port creation failed, reference table exhausted \n " ) ;
2006-01-02 21:04:38 +03:00
kfree ( p_ptr ) ;
return 0 ;
}
2006-01-18 02:38:21 +03:00
tipc_port_lock ( ref ) ;
2007-06-11 04:25:24 +04:00
p_ptr - > publ . usr_handle = usr_handle ;
p_ptr - > publ . max_pkt = MAX_PKT_DEFAULT ;
2006-01-02 21:04:38 +03:00
p_ptr - > publ . ref = ref ;
msg = & p_ptr - > publ . phdr ;
msg_init ( msg , DATA_LOW , TIPC_NAMED_MSG , TIPC_OK , LONG_H_SIZE , 0 ) ;
msg_set_orignode ( msg , tipc_own_addr ) ;
msg_set_prevnode ( msg , tipc_own_addr ) ;
msg_set_origport ( msg , ref ) ;
msg_set_importance ( msg , importance ) ;
p_ptr - > last_in_seqno = 41 ;
p_ptr - > sent = 1 ;
INIT_LIST_HEAD ( & p_ptr - > wait_list ) ;
INIT_LIST_HEAD ( & p_ptr - > subscription . nodesub_list ) ;
2006-03-21 09:36:47 +03:00
p_ptr - > congested_link = NULL ;
2006-01-02 21:04:38 +03:00
p_ptr - > dispatcher = dispatcher ;
p_ptr - > wakeup = wakeup ;
2006-03-21 09:36:47 +03:00
p_ptr - > user_port = NULL ;
2006-01-02 21:04:38 +03:00
k_init_timer ( & p_ptr - > timer , ( Handler ) port_timeout , ref ) ;
2006-01-18 02:38:21 +03:00
spin_lock_bh ( & tipc_port_list_lock ) ;
2006-01-02 21:04:38 +03:00
INIT_LIST_HEAD ( & p_ptr - > publications ) ;
INIT_LIST_HEAD ( & p_ptr - > port_list ) ;
list_add_tail ( & p_ptr - > port_list , & ports ) ;
2006-01-18 02:38:21 +03:00
spin_unlock_bh ( & tipc_port_list_lock ) ;
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return ref ;
}
int tipc_deleteport ( u32 ref )
{
struct port * p_ptr ;
2006-03-21 09:36:47 +03:00
struct sk_buff * buf = NULL ;
2006-01-02 21:04:38 +03:00
2006-03-21 09:36:47 +03:00
tipc_withdraw ( ref , 0 , NULL ) ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2007-02-09 17:25:21 +03:00
if ( ! p_ptr )
2006-01-02 21:04:38 +03:00
return - EINVAL ;
2006-01-18 02:38:21 +03:00
tipc_ref_discard ( ref ) ;
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
k_cancel_timer ( & p_ptr - > timer ) ;
if ( p_ptr - > publ . connected ) {
buf = port_build_peer_abort_msg ( p_ptr , TIPC_ERR_NO_PORT ) ;
2006-01-18 02:38:21 +03:00
tipc_nodesub_unsubscribe ( & p_ptr - > subscription ) ;
2006-01-02 21:04:38 +03:00
}
if ( p_ptr - > user_port ) {
2006-01-18 02:38:21 +03:00
tipc_reg_remove_port ( p_ptr - > user_port ) ;
2006-01-02 21:04:38 +03:00
kfree ( p_ptr - > user_port ) ;
}
2006-01-18 02:38:21 +03:00
spin_lock_bh ( & tipc_port_list_lock ) ;
2006-01-02 21:04:38 +03:00
list_del ( & p_ptr - > port_list ) ;
list_del ( & p_ptr - > wait_list ) ;
2006-01-18 02:38:21 +03:00
spin_unlock_bh ( & tipc_port_list_lock ) ;
2006-01-02 21:04:38 +03:00
k_term_timer ( & p_ptr - > timer ) ;
kfree ( p_ptr ) ;
dbg ( " Deleted port %u \n " , ref ) ;
2006-01-18 02:38:21 +03:00
tipc_net_route_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
return TIPC_OK ;
}
/**
* tipc_get_port ( ) - return port associated with ' ref '
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Note : Port is not locked .
*/
struct tipc_port * tipc_get_port ( const u32 ref )
{
2006-01-18 02:38:21 +03:00
return ( struct tipc_port * ) tipc_ref_deref ( ref ) ;
2006-01-02 21:04:38 +03:00
}
/**
* tipc_get_handle - return user handle associated to port ' ref '
*/
void * tipc_get_handle ( const u32 ref )
{
struct port * p_ptr ;
void * handle ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
handle = p_ptr - > publ . usr_handle ;
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return handle ;
}
2006-03-21 09:37:04 +03:00
static int port_unreliable ( struct port * p_ptr )
2006-01-02 21:04:38 +03:00
{
return msg_src_droppable ( & p_ptr - > publ . phdr ) ;
}
int tipc_portunreliable ( u32 ref , unsigned int * isunreliable )
{
struct port * p_ptr ;
2007-02-09 17:25:21 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
* isunreliable = port_unreliable ( p_ptr ) ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
return TIPC_OK ;
}
int tipc_set_portunreliable ( u32 ref , unsigned int isunreliable )
{
struct port * p_ptr ;
2007-02-09 17:25:21 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
msg_set_src_droppable ( & p_ptr - > publ . phdr , ( isunreliable ! = 0 ) ) ;
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return TIPC_OK ;
}
2006-03-21 09:37:04 +03:00
static int port_unreturnable ( struct port * p_ptr )
2006-01-02 21:04:38 +03:00
{
return msg_dest_droppable ( & p_ptr - > publ . phdr ) ;
}
int tipc_portunreturnable ( u32 ref , unsigned int * isunrejectable )
{
struct port * p_ptr ;
2007-02-09 17:25:21 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
* isunrejectable = port_unreturnable ( p_ptr ) ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
return TIPC_OK ;
}
int tipc_set_portunreturnable ( u32 ref , unsigned int isunrejectable )
{
struct port * p_ptr ;
2007-02-09 17:25:21 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
msg_set_dest_droppable ( & p_ptr - > publ . phdr , ( isunrejectable ! = 0 ) ) ;
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return TIPC_OK ;
}
2007-02-09 17:25:21 +03:00
/*
* port_build_proto_msg ( ) : build a port level protocol
* or a connection abortion message . Called with
2006-01-02 21:04:38 +03:00
* tipc_port lock on .
*/
static struct sk_buff * port_build_proto_msg ( u32 destport , u32 destnode ,
u32 origport , u32 orignode ,
2007-02-09 17:25:21 +03:00
u32 usr , u32 type , u32 err ,
2006-01-02 21:04:38 +03:00
u32 seqno , u32 ack )
{
struct sk_buff * buf ;
struct tipc_msg * msg ;
2007-02-09 17:25:21 +03:00
2006-01-02 21:04:38 +03:00
buf = buf_acquire ( LONG_H_SIZE ) ;
if ( buf ) {
msg = buf_msg ( buf ) ;
msg_init ( msg , usr , type , err , LONG_H_SIZE , destnode ) ;
msg_set_destport ( msg , destport ) ;
msg_set_origport ( msg , origport ) ;
msg_set_destnode ( msg , destnode ) ;
msg_set_orignode ( msg , orignode ) ;
msg_set_transp_seqno ( msg , seqno ) ;
msg_set_msgcnt ( msg , ack ) ;
msg_dbg ( msg , " PORT>SEND>: " ) ;
}
return buf ;
}
int tipc_set_msg_option ( struct tipc_port * tp_ptr , const char * opt , const u32 sz )
{
msg_expand ( & tp_ptr - > phdr , msg_destnode ( & tp_ptr - > phdr ) ) ;
msg_set_options ( & tp_ptr - > phdr , opt , sz ) ;
return TIPC_OK ;
}
int tipc_reject_msg ( struct sk_buff * buf , u32 err )
{
struct tipc_msg * msg = buf_msg ( buf ) ;
struct sk_buff * rbuf ;
struct tipc_msg * rmsg ;
int hdr_sz ;
u32 imp = msg_importance ( msg ) ;
u32 data_sz = msg_data_sz ( msg ) ;
if ( data_sz > MAX_REJECT_SIZE )
data_sz = MAX_REJECT_SIZE ;
if ( msg_connected ( msg ) & & ( imp < TIPC_CRITICAL_IMPORTANCE ) )
imp + + ;
msg_dbg ( msg , " port->rej: " ) ;
/* discard rejected message if it shouldn't be returned to sender */
if ( msg_errcode ( msg ) | | msg_dest_droppable ( msg ) ) {
buf_discard ( buf ) ;
return data_sz ;
}
/* construct rejected message */
if ( msg_mcast ( msg ) )
hdr_sz = MCAST_H_SIZE ;
else
hdr_sz = LONG_H_SIZE ;
rbuf = buf_acquire ( data_sz + hdr_sz ) ;
if ( rbuf = = NULL ) {
buf_discard ( buf ) ;
return data_sz ;
}
rmsg = buf_msg ( rbuf ) ;
msg_init ( rmsg , imp , msg_type ( msg ) , err , hdr_sz , msg_orignode ( msg ) ) ;
msg_set_destport ( rmsg , msg_origport ( msg ) ) ;
msg_set_prevnode ( rmsg , tipc_own_addr ) ;
msg_set_origport ( rmsg , msg_destport ( msg ) ) ;
if ( msg_short ( msg ) )
msg_set_orignode ( rmsg , tipc_own_addr ) ;
else
msg_set_orignode ( rmsg , msg_destnode ( msg ) ) ;
2007-02-09 17:25:21 +03:00
msg_set_size ( rmsg , data_sz + hdr_sz ) ;
2006-01-02 21:04:38 +03:00
msg_set_nametype ( rmsg , msg_nametype ( msg ) ) ;
msg_set_nameinst ( rmsg , msg_nameinst ( msg ) ) ;
2007-03-31 18:55:19 +04:00
skb_copy_to_linear_data_offset ( rbuf , hdr_sz , msg_data ( msg ) , data_sz ) ;
2006-01-02 21:04:38 +03:00
/* send self-abort message when rejecting on a connected port */
if ( msg_connected ( msg ) ) {
2006-03-21 09:36:47 +03:00
struct sk_buff * abuf = NULL ;
2006-01-18 02:38:21 +03:00
struct port * p_ptr = tipc_port_lock ( msg_destport ( msg ) ) ;
2006-01-02 21:04:38 +03:00
if ( p_ptr ) {
if ( p_ptr - > publ . connected )
abuf = port_build_self_abort_msg ( p_ptr , err ) ;
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
tipc_net_route_msg ( abuf ) ;
2006-01-02 21:04:38 +03:00
}
/* send rejected message */
buf_discard ( buf ) ;
2006-01-18 02:38:21 +03:00
tipc_net_route_msg ( rbuf ) ;
2006-01-02 21:04:38 +03:00
return data_sz ;
}
2006-01-18 02:38:21 +03:00
int tipc_port_reject_sections ( struct port * p_ptr , struct tipc_msg * hdr ,
struct iovec const * msg_sect , u32 num_sect ,
int err )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * buf ;
int res ;
2007-02-09 17:25:21 +03:00
res = msg_build ( hdr , msg_sect , num_sect , MAX_MSG_SIZE ,
2006-01-02 21:04:38 +03:00
! p_ptr - > user_port , & buf ) ;
if ( ! buf )
return res ;
return tipc_reject_msg ( buf , err ) ;
}
static void port_timeout ( unsigned long ref )
{
2006-01-18 02:38:21 +03:00
struct port * p_ptr = tipc_port_lock ( ref ) ;
2006-03-21 09:36:47 +03:00
struct sk_buff * buf = NULL ;
2006-01-02 21:04:38 +03:00
2006-10-17 08:38:05 +04:00
if ( ! p_ptr )
return ;
if ( ! p_ptr - > publ . connected ) {
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return ;
2006-10-17 08:38:05 +04:00
}
2006-01-02 21:04:38 +03:00
/* Last probe answered ? */
if ( p_ptr - > probing_state = = PROBING ) {
buf = port_build_self_abort_msg ( p_ptr , TIPC_ERR_NO_PORT ) ;
} else {
buf = port_build_proto_msg ( port_peerport ( p_ptr ) ,
port_peernode ( p_ptr ) ,
p_ptr - > publ . ref ,
tipc_own_addr ,
CONN_MANAGER ,
CONN_PROBE ,
2007-02-09 17:25:21 +03:00
TIPC_OK ,
2006-01-02 21:04:38 +03:00
port_out_seqno ( p_ptr ) ,
0 ) ;
port_incr_out_seqno ( p_ptr ) ;
p_ptr - > probing_state = PROBING ;
k_start_timer ( & p_ptr - > timer , p_ptr - > probing_interval ) ;
}
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
}
static void port_handle_node_down ( unsigned long ref )
{
2006-01-18 02:38:21 +03:00
struct port * p_ptr = tipc_port_lock ( ref ) ;
2006-03-21 09:36:47 +03:00
struct sk_buff * buf = NULL ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return ;
buf = port_build_self_abort_msg ( p_ptr , TIPC_ERR_NO_NODE ) ;
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
}
static struct sk_buff * port_build_self_abort_msg ( struct port * p_ptr , u32 err )
{
u32 imp = msg_importance ( & p_ptr - > publ . phdr ) ;
if ( ! p_ptr - > publ . connected )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
if ( imp < TIPC_CRITICAL_IMPORTANCE )
imp + + ;
return port_build_proto_msg ( p_ptr - > publ . ref ,
tipc_own_addr ,
port_peerport ( p_ptr ) ,
port_peernode ( p_ptr ) ,
imp ,
TIPC_CONN_MSG ,
2007-02-09 17:25:21 +03:00
err ,
2006-01-02 21:04:38 +03:00
p_ptr - > last_in_seqno + 1 ,
0 ) ;
}
static struct sk_buff * port_build_peer_abort_msg ( struct port * p_ptr , u32 err )
{
u32 imp = msg_importance ( & p_ptr - > publ . phdr ) ;
if ( ! p_ptr - > publ . connected )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
if ( imp < TIPC_CRITICAL_IMPORTANCE )
imp + + ;
return port_build_proto_msg ( port_peerport ( p_ptr ) ,
port_peernode ( p_ptr ) ,
p_ptr - > publ . ref ,
tipc_own_addr ,
imp ,
TIPC_CONN_MSG ,
2007-02-09 17:25:21 +03:00
err ,
2006-01-02 21:04:38 +03:00
port_out_seqno ( p_ptr ) ,
0 ) ;
}
2006-01-18 02:38:21 +03:00
void tipc_port_recv_proto_msg ( struct sk_buff * buf )
2006-01-02 21:04:38 +03:00
{
struct tipc_msg * msg = buf_msg ( buf ) ;
2006-01-18 02:38:21 +03:00
struct port * p_ptr = tipc_port_lock ( msg_destport ( msg ) ) ;
2006-01-02 21:04:38 +03:00
u32 err = TIPC_OK ;
2006-03-21 09:36:47 +03:00
struct sk_buff * r_buf = NULL ;
struct sk_buff * abort_buf = NULL ;
2006-01-02 21:04:38 +03:00
msg_dbg ( msg , " PORT<RECV<: " ) ;
if ( ! p_ptr ) {
err = TIPC_ERR_NO_PORT ;
} else if ( p_ptr - > publ . connected ) {
if ( port_peernode ( p_ptr ) ! = msg_orignode ( msg ) )
err = TIPC_ERR_NO_PORT ;
if ( port_peerport ( p_ptr ) ! = msg_origport ( msg ) )
err = TIPC_ERR_NO_PORT ;
if ( ! err & & msg_routed ( msg ) ) {
u32 seqno = msg_transp_seqno ( msg ) ;
u32 myno = + + p_ptr - > last_in_seqno ;
if ( seqno ! = myno ) {
err = TIPC_ERR_NO_PORT ;
abort_buf = port_build_self_abort_msg ( p_ptr , err ) ;
}
}
if ( msg_type ( msg ) = = CONN_ACK ) {
2007-02-09 17:25:21 +03:00
int wakeup = tipc_port_congested ( p_ptr ) & &
2006-01-02 21:04:38 +03:00
p_ptr - > publ . congested & &
p_ptr - > wakeup ;
p_ptr - > acked + = msg_msgcnt ( msg ) ;
2006-01-18 02:38:21 +03:00
if ( tipc_port_congested ( p_ptr ) )
2006-01-02 21:04:38 +03:00
goto exit ;
p_ptr - > publ . congested = 0 ;
if ( ! wakeup )
goto exit ;
p_ptr - > wakeup ( & p_ptr - > publ ) ;
goto exit ;
}
} else if ( p_ptr - > publ . published ) {
err = TIPC_ERR_NO_PORT ;
}
if ( err ) {
r_buf = port_build_proto_msg ( msg_origport ( msg ) ,
2007-02-09 17:25:21 +03:00
msg_orignode ( msg ) ,
msg_destport ( msg ) ,
2006-01-02 21:04:38 +03:00
tipc_own_addr ,
DATA_HIGH ,
TIPC_CONN_MSG ,
err ,
0 ,
0 ) ;
goto exit ;
}
/* All is fine */
if ( msg_type ( msg ) = = CONN_PROBE ) {
2007-02-09 17:25:21 +03:00
r_buf = port_build_proto_msg ( msg_origport ( msg ) ,
msg_orignode ( msg ) ,
msg_destport ( msg ) ,
tipc_own_addr ,
2006-01-02 21:04:38 +03:00
CONN_MANAGER ,
CONN_PROBE_REPLY ,
TIPC_OK ,
port_out_seqno ( p_ptr ) ,
0 ) ;
}
p_ptr - > probing_state = CONFIRMED ;
port_incr_out_seqno ( p_ptr ) ;
exit :
if ( p_ptr )
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( r_buf ) ;
tipc_net_route_msg ( abort_buf ) ;
2006-01-02 21:04:38 +03:00
buf_discard ( buf ) ;
}
static void port_print ( struct port * p_ptr , struct print_buf * buf , int full_id )
{
2007-02-09 17:25:21 +03:00
struct publication * publ ;
2006-01-02 21:04:38 +03:00
if ( full_id )
2007-02-09 17:25:21 +03:00
tipc_printf ( buf , " <%u.%u.%u:%u>: " ,
2006-01-02 21:04:38 +03:00
tipc_zone ( tipc_own_addr ) , tipc_cluster ( tipc_own_addr ) ,
2007-02-09 17:25:21 +03:00
tipc_node ( tipc_own_addr ) , p_ptr - > publ . ref ) ;
2006-01-02 21:04:38 +03:00
else
tipc_printf ( buf , " %-10u: " , p_ptr - > publ . ref ) ;
2007-02-09 17:25:21 +03:00
if ( p_ptr - > publ . connected ) {
u32 dport = port_peerport ( p_ptr ) ;
u32 destnode = port_peernode ( p_ptr ) ;
tipc_printf ( buf , " connected to <%u.%u.%u:%u> " ,
tipc_zone ( destnode ) , tipc_cluster ( destnode ) ,
tipc_node ( destnode ) , dport ) ;
if ( p_ptr - > publ . conn_type ! = 0 )
tipc_printf ( buf , " via {%u,%u} " ,
p_ptr - > publ . conn_type ,
p_ptr - > publ . conn_instance ) ;
}
else if ( p_ptr - > publ . published ) {
tipc_printf ( buf , " bound to " ) ;
list_for_each_entry ( publ , & p_ptr - > publications , pport_list ) {
2006-01-02 21:04:38 +03:00
if ( publ - > lower = = publ - > upper )
tipc_printf ( buf , " {%u,%u} " , publ - > type ,
publ - > lower ) ;
else
2007-02-09 17:25:21 +03:00
tipc_printf ( buf , " {%u,%u,%u} " , publ - > type ,
2006-01-02 21:04:38 +03:00
publ - > lower , publ - > upper ) ;
2007-02-09 17:25:21 +03:00
}
}
tipc_printf ( buf , " \n " ) ;
2006-01-02 21:04:38 +03:00
}
# define MAX_PORT_QUERY 32768
2006-01-18 02:38:21 +03:00
struct sk_buff * tipc_port_get_ports ( void )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * buf ;
struct tlv_desc * rep_tlv ;
struct print_buf pb ;
struct port * p_ptr ;
int str_len ;
2006-01-18 02:38:21 +03:00
buf = tipc_cfg_reply_alloc ( TLV_SPACE ( MAX_PORT_QUERY ) ) ;
2006-01-02 21:04:38 +03:00
if ( ! buf )
return NULL ;
rep_tlv = ( struct tlv_desc * ) buf - > data ;
2006-01-18 02:38:21 +03:00
tipc_printbuf_init ( & pb , TLV_DATA ( rep_tlv ) , MAX_PORT_QUERY ) ;
spin_lock_bh ( & tipc_port_list_lock ) ;
2006-01-02 21:04:38 +03:00
list_for_each_entry ( p_ptr , & ports , port_list ) {
spin_lock_bh ( p_ptr - > publ . lock ) ;
port_print ( p_ptr , & pb , 0 ) ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
}
2006-01-18 02:38:21 +03:00
spin_unlock_bh ( & tipc_port_list_lock ) ;
str_len = tipc_printbuf_validate ( & pb ) ;
2006-01-02 21:04:38 +03:00
skb_put ( buf , TLV_SPACE ( str_len ) ) ;
TLV_SET ( rep_tlv , TIPC_TLV_ULTRA_STRING , NULL , str_len ) ;
return buf ;
}
#if 0
# define MAX_PORT_STATS 2000
struct sk_buff * port_show_stats ( const void * req_tlv_area , int req_tlv_space )
{
u32 ref ;
struct port * p_ptr ;
struct sk_buff * buf ;
struct tlv_desc * rep_tlv ;
struct print_buf pb ;
int str_len ;
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_PORT_REF ) )
return cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
ref = * ( u32 * ) TLV_DATA ( req_tlv_area ) ;
ref = ntohl ( ref ) ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return cfg_reply_error_string ( " port not found " ) ;
2006-01-18 02:38:21 +03:00
buf = tipc_cfg_reply_alloc ( TLV_SPACE ( MAX_PORT_STATS ) ) ;
2006-01-02 21:04:38 +03:00
if ( ! buf ) {
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return NULL ;
}
rep_tlv = ( struct tlv_desc * ) buf - > data ;
2006-01-18 02:38:21 +03:00
tipc_printbuf_init ( & pb , TLV_DATA ( rep_tlv ) , MAX_PORT_STATS ) ;
2006-01-02 21:04:38 +03:00
port_print ( p_ptr , & pb , 1 ) ;
/* NEED TO FILL IN ADDITIONAL PORT STATISTICS HERE */
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
str_len = tipc_printbuf_validate ( & pb ) ;
2006-01-02 21:04:38 +03:00
skb_put ( buf , TLV_SPACE ( str_len ) ) ;
TLV_SET ( rep_tlv , TIPC_TLV_ULTRA_STRING , NULL , str_len ) ;
return buf ;
}
# endif
2006-01-18 02:38:21 +03:00
void tipc_port_reinit ( void )
2006-01-02 21:04:38 +03:00
{
struct port * p_ptr ;
struct tipc_msg * msg ;
2006-01-18 02:38:21 +03:00
spin_lock_bh ( & tipc_port_list_lock ) ;
2006-01-02 21:04:38 +03:00
list_for_each_entry ( p_ptr , & ports , port_list ) {
msg = & p_ptr - > publ . phdr ;
if ( msg_orignode ( msg ) = = tipc_own_addr )
break ;
msg_set_orignode ( msg , tipc_own_addr ) ;
}
2006-01-18 02:38:21 +03:00
spin_unlock_bh ( & tipc_port_list_lock ) ;
2006-01-02 21:04:38 +03:00
}
/*
* port_dispatcher_sigh ( ) : Signal handler for messages destinated
* to the tipc_port interface .
*/
static void port_dispatcher_sigh ( void * dummy )
{
struct sk_buff * buf ;
spin_lock_bh ( & queue_lock ) ;
buf = msg_queue_head ;
2006-03-21 09:36:47 +03:00
msg_queue_head = NULL ;
2006-01-02 21:04:38 +03:00
spin_unlock_bh ( & queue_lock ) ;
while ( buf ) {
struct port * p_ptr ;
struct user_port * up_ptr ;
struct tipc_portid orig ;
struct tipc_name_seq dseq ;
void * usr_handle ;
int connected ;
int published ;
2006-06-26 10:38:58 +04:00
u32 message_type ;
2006-01-02 21:04:38 +03:00
struct sk_buff * next = buf - > next ;
struct tipc_msg * msg = buf_msg ( buf ) ;
u32 dref = msg_destport ( msg ) ;
2007-02-09 17:25:21 +03:00
2006-06-26 10:38:58 +04:00
message_type = msg_type ( msg ) ;
if ( message_type > TIPC_DIRECT_MSG )
goto reject ; /* Unsupported message type */
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( dref ) ;
2006-06-26 10:38:58 +04:00
if ( ! p_ptr )
goto reject ; /* Port deleted while msg in queue */
2006-01-02 21:04:38 +03:00
orig . ref = msg_origport ( msg ) ;
orig . node = msg_orignode ( msg ) ;
up_ptr = p_ptr - > user_port ;
usr_handle = up_ptr - > usr_handle ;
connected = p_ptr - > publ . connected ;
published = p_ptr - > publ . published ;
if ( unlikely ( msg_errcode ( msg ) ) )
goto err ;
2006-06-26 10:38:58 +04:00
switch ( message_type ) {
2007-02-09 17:25:21 +03:00
2006-01-02 21:04:38 +03:00
case TIPC_CONN_MSG : {
tipc_conn_msg_event cb = up_ptr - > conn_msg_cb ;
u32 peer_port = port_peerport ( p_ptr ) ;
u32 peer_node = port_peernode ( p_ptr ) ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
if ( unlikely ( ! connected ) ) {
if ( unlikely ( published ) )
goto reject ;
tipc_connect2port ( dref , & orig ) ;
}
if ( unlikely ( msg_origport ( msg ) ! = peer_port ) )
goto reject ;
if ( unlikely ( msg_orignode ( msg ) ! = peer_node ) )
goto reject ;
if ( unlikely ( ! cb ) )
goto reject ;
2007-02-09 17:25:21 +03:00
if ( unlikely ( + + p_ptr - > publ . conn_unacked > =
2006-01-02 21:04:38 +03:00
TIPC_FLOW_CONTROL_WIN ) )
2007-02-09 17:25:21 +03:00
tipc_acknowledge ( dref ,
2006-01-02 21:04:38 +03:00
p_ptr - > publ . conn_unacked ) ;
skb_pull ( buf , msg_hdr_sz ( msg ) ) ;
cb ( usr_handle , dref , & buf , msg_data ( msg ) ,
msg_data_sz ( msg ) ) ;
break ;
}
case TIPC_DIRECT_MSG : {
tipc_msg_event cb = up_ptr - > msg_cb ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
if ( unlikely ( connected ) )
goto reject ;
if ( unlikely ( ! cb ) )
goto reject ;
skb_pull ( buf , msg_hdr_sz ( msg ) ) ;
2007-02-09 17:25:21 +03:00
cb ( usr_handle , dref , & buf , msg_data ( msg ) ,
2006-01-02 21:04:38 +03:00
msg_data_sz ( msg ) , msg_importance ( msg ) ,
& orig ) ;
break ;
}
2006-06-26 10:38:58 +04:00
case TIPC_MCAST_MSG :
2006-01-02 21:04:38 +03:00
case TIPC_NAMED_MSG : {
tipc_named_msg_event cb = up_ptr - > named_msg_cb ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
if ( unlikely ( connected ) )
goto reject ;
if ( unlikely ( ! cb ) )
goto reject ;
if ( unlikely ( ! published ) )
goto reject ;
dseq . type = msg_nametype ( msg ) ;
dseq . lower = msg_nameinst ( msg ) ;
2006-06-26 10:38:58 +04:00
dseq . upper = ( message_type = = TIPC_NAMED_MSG )
? dseq . lower : msg_nameupper ( msg ) ;
2006-01-02 21:04:38 +03:00
skb_pull ( buf , msg_hdr_sz ( msg ) ) ;
2007-02-09 17:25:21 +03:00
cb ( usr_handle , dref , & buf , msg_data ( msg ) ,
2006-01-02 21:04:38 +03:00
msg_data_sz ( msg ) , msg_importance ( msg ) ,
& orig , & dseq ) ;
break ;
}
}
if ( buf )
buf_discard ( buf ) ;
buf = next ;
continue ;
err :
2006-06-26 10:38:58 +04:00
switch ( message_type ) {
2007-02-09 17:25:21 +03:00
2006-01-02 21:04:38 +03:00
case TIPC_CONN_MSG : {
2007-02-09 17:25:21 +03:00
tipc_conn_shutdown_event cb =
2006-01-02 21:04:38 +03:00
up_ptr - > conn_err_cb ;
u32 peer_port = port_peerport ( p_ptr ) ;
u32 peer_node = port_peernode ( p_ptr ) ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
if ( ! connected | | ! cb )
break ;
if ( msg_origport ( msg ) ! = peer_port )
break ;
if ( msg_orignode ( msg ) ! = peer_node )
break ;
tipc_disconnect ( dref ) ;
skb_pull ( buf , msg_hdr_sz ( msg ) ) ;
cb ( usr_handle , dref , & buf , msg_data ( msg ) ,
msg_data_sz ( msg ) , msg_errcode ( msg ) ) ;
break ;
}
case TIPC_DIRECT_MSG : {
tipc_msg_err_event cb = up_ptr - > err_cb ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
if ( connected | | ! cb )
break ;
skb_pull ( buf , msg_hdr_sz ( msg ) ) ;
cb ( usr_handle , dref , & buf , msg_data ( msg ) ,
msg_data_sz ( msg ) , msg_errcode ( msg ) , & orig ) ;
break ;
}
2006-06-26 10:38:58 +04:00
case TIPC_MCAST_MSG :
2006-01-02 21:04:38 +03:00
case TIPC_NAMED_MSG : {
2007-02-09 17:25:21 +03:00
tipc_named_msg_err_event cb =
2006-01-02 21:04:38 +03:00
up_ptr - > named_err_cb ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
if ( connected | | ! cb )
break ;
dseq . type = msg_nametype ( msg ) ;
dseq . lower = msg_nameinst ( msg ) ;
2006-06-26 10:38:58 +04:00
dseq . upper = ( message_type = = TIPC_NAMED_MSG )
? dseq . lower : msg_nameupper ( msg ) ;
2006-01-02 21:04:38 +03:00
skb_pull ( buf , msg_hdr_sz ( msg ) ) ;
2007-02-09 17:25:21 +03:00
cb ( usr_handle , dref , & buf , msg_data ( msg ) ,
2006-01-02 21:04:38 +03:00
msg_data_sz ( msg ) , msg_errcode ( msg ) , & dseq ) ;
break ;
}
}
if ( buf )
buf_discard ( buf ) ;
buf = next ;
continue ;
reject :
tipc_reject_msg ( buf , TIPC_ERR_NO_PORT ) ;
buf = next ;
}
}
/*
* port_dispatcher ( ) : Dispatcher for messages destinated
* to the tipc_port interface . Called with port locked .
*/
static u32 port_dispatcher ( struct tipc_port * dummy , struct sk_buff * buf )
{
buf - > next = NULL ;
spin_lock_bh ( & queue_lock ) ;
if ( msg_queue_head ) {
msg_queue_tail - > next = buf ;
msg_queue_tail = buf ;
} else {
msg_queue_tail = msg_queue_head = buf ;
2006-01-18 02:38:21 +03:00
tipc_k_signal ( ( Handler ) port_dispatcher_sigh , 0 ) ;
2006-01-02 21:04:38 +03:00
}
spin_unlock_bh ( & queue_lock ) ;
return TIPC_OK ;
}
2007-02-09 17:25:21 +03:00
/*
2006-01-02 21:04:38 +03:00
* Wake up port after congestion : Called with port locked ,
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
*/
static void port_wakeup_sh ( unsigned long ref )
{
struct port * p_ptr ;
struct user_port * up_ptr ;
2006-03-21 09:36:47 +03:00
tipc_continue_event cb = NULL ;
void * uh = NULL ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( p_ptr ) {
up_ptr = p_ptr - > user_port ;
if ( up_ptr ) {
cb = up_ptr - > continue_event_cb ;
uh = up_ptr - > usr_handle ;
}
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
}
if ( cb )
cb ( uh , ref ) ;
}
static void port_wakeup ( struct tipc_port * p_ptr )
{
2006-01-18 02:38:21 +03:00
tipc_k_signal ( ( Handler ) port_wakeup_sh , p_ptr - > ref ) ;
2006-01-02 21:04:38 +03:00
}
void tipc_acknowledge ( u32 ref , u32 ack )
{
struct port * p_ptr ;
2006-03-21 09:36:47 +03:00
struct sk_buff * buf = NULL ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return ;
if ( p_ptr - > publ . connected ) {
p_ptr - > publ . conn_unacked - = ack ;
buf = port_build_proto_msg ( port_peerport ( p_ptr ) ,
port_peernode ( p_ptr ) ,
ref ,
tipc_own_addr ,
CONN_MANAGER ,
CONN_ACK ,
2007-02-09 17:25:21 +03:00
TIPC_OK ,
2006-01-02 21:04:38 +03:00
port_out_seqno ( p_ptr ) ,
ack ) ;
}
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
}
/*
* tipc_createport ( ) : user level call . Will add port to
* registry if non - zero user_ref .
*/
2007-02-09 17:25:21 +03:00
int tipc_createport ( u32 user_ref ,
void * usr_handle ,
unsigned int importance ,
tipc_msg_err_event error_cb ,
tipc_named_msg_err_event named_error_cb ,
tipc_conn_shutdown_event conn_error_cb ,
tipc_msg_event msg_cb ,
tipc_named_msg_event named_msg_cb ,
tipc_conn_msg_event conn_msg_cb ,
2006-01-02 21:04:38 +03:00
tipc_continue_event continue_event_cb , /* May be zero */
u32 * portref )
{
struct user_port * up_ptr ;
2007-02-09 17:25:21 +03:00
struct port * p_ptr ;
2006-01-02 21:04:38 +03:00
u32 ref ;
2006-07-22 01:51:30 +04:00
up_ptr = kmalloc ( sizeof ( * up_ptr ) , GFP_ATOMIC ) ;
2006-06-26 10:52:17 +04:00
if ( ! up_ptr ) {
2006-06-26 10:50:01 +04:00
warn ( " Port creation failed, no memory \n " ) ;
2006-01-02 21:04:38 +03:00
return - ENOMEM ;
}
2006-03-21 09:36:47 +03:00
ref = tipc_createport_raw ( NULL , port_dispatcher , port_wakeup , importance ) ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr ) {
kfree ( up_ptr ) ;
return - ENOMEM ;
}
p_ptr - > user_port = up_ptr ;
up_ptr - > user_ref = user_ref ;
up_ptr - > usr_handle = usr_handle ;
up_ptr - > ref = p_ptr - > publ . ref ;
up_ptr - > err_cb = error_cb ;
up_ptr - > named_err_cb = named_error_cb ;
up_ptr - > conn_err_cb = conn_error_cb ;
up_ptr - > msg_cb = msg_cb ;
up_ptr - > named_msg_cb = named_msg_cb ;
up_ptr - > conn_msg_cb = conn_msg_cb ;
up_ptr - > continue_event_cb = continue_event_cb ;
INIT_LIST_HEAD ( & up_ptr - > uport_list ) ;
2006-01-18 02:38:21 +03:00
tipc_reg_add_port ( up_ptr ) ;
2006-01-02 21:04:38 +03:00
* portref = p_ptr - > publ . ref ;
2007-02-09 17:25:21 +03:00
dbg ( " tipc_createport: %x with ref %u \n " , p_ptr , p_ptr - > publ . ref ) ;
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return TIPC_OK ;
}
int tipc_ownidentity ( u32 ref , struct tipc_portid * id )
{
id - > ref = ref ;
id - > node = tipc_own_addr ;
return TIPC_OK ;
}
int tipc_portimportance ( u32 ref , unsigned int * importance )
{
struct port * p_ptr ;
2007-02-09 17:25:21 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
* importance = ( unsigned int ) msg_importance ( & p_ptr - > publ . phdr ) ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
return TIPC_OK ;
}
int tipc_set_portimportance ( u32 ref , unsigned int imp )
{
struct port * p_ptr ;
if ( imp > TIPC_CRITICAL_IMPORTANCE )
return - EINVAL ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
msg_set_importance ( & p_ptr - > publ . phdr , ( u32 ) imp ) ;
spin_unlock_bh ( p_ptr - > publ . lock ) ;
return TIPC_OK ;
}
int tipc_publish ( u32 ref , unsigned int scope , struct tipc_name_seq const * seq )
{
struct port * p_ptr ;
struct publication * publ ;
u32 key ;
int res = - EINVAL ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-11-01 03:59:35 +03:00
if ( ! p_ptr )
return - EINVAL ;
2006-01-02 21:04:38 +03:00
dbg ( " tipc_publ %u, p_ptr = %x, conn = %x, scope = %x, "
" lower = %u, upper = %u \n " ,
ref , p_ptr , p_ptr - > publ . connected , scope , seq - > lower , seq - > upper ) ;
if ( p_ptr - > publ . connected )
goto exit ;
if ( seq - > lower > seq - > upper )
goto exit ;
if ( ( scope < TIPC_ZONE_SCOPE ) | | ( scope > TIPC_NODE_SCOPE ) )
goto exit ;
key = ref + p_ptr - > pub_count + 1 ;
if ( key = = ref ) {
res = - EADDRINUSE ;
goto exit ;
}
2006-01-18 02:38:21 +03:00
publ = tipc_nametbl_publish ( seq - > type , seq - > lower , seq - > upper ,
scope , p_ptr - > publ . ref , key ) ;
2006-01-02 21:04:38 +03:00
if ( publ ) {
list_add ( & publ - > pport_list , & p_ptr - > publications ) ;
p_ptr - > pub_count + + ;
p_ptr - > publ . published = 1 ;
res = TIPC_OK ;
}
exit :
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
int tipc_withdraw ( u32 ref , unsigned int scope , struct tipc_name_seq const * seq )
{
struct port * p_ptr ;
struct publication * publ ;
struct publication * tpubl ;
int res = - EINVAL ;
2007-02-09 17:25:21 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
if ( ! seq ) {
2007-02-09 17:25:21 +03:00
list_for_each_entry_safe ( publ , tpubl ,
2006-01-02 21:04:38 +03:00
& p_ptr - > publications , pport_list ) {
2007-02-09 17:25:21 +03:00
tipc_nametbl_withdraw ( publ - > type , publ - > lower ,
2006-01-18 02:38:21 +03:00
publ - > ref , publ - > key ) ;
2006-01-02 21:04:38 +03:00
}
res = TIPC_OK ;
} else {
2007-02-09 17:25:21 +03:00
list_for_each_entry_safe ( publ , tpubl ,
2006-01-02 21:04:38 +03:00
& p_ptr - > publications , pport_list ) {
if ( publ - > scope ! = scope )
continue ;
if ( publ - > type ! = seq - > type )
continue ;
if ( publ - > lower ! = seq - > lower )
continue ;
if ( publ - > upper ! = seq - > upper )
break ;
2007-02-09 17:25:21 +03:00
tipc_nametbl_withdraw ( publ - > type , publ - > lower ,
2006-01-18 02:38:21 +03:00
publ - > ref , publ - > key ) ;
2006-01-02 21:04:38 +03:00
res = TIPC_OK ;
break ;
}
}
if ( list_empty ( & p_ptr - > publications ) )
p_ptr - > publ . published = 0 ;
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
int tipc_connect2port ( u32 ref , struct tipc_portid const * peer )
{
struct port * p_ptr ;
struct tipc_msg * msg ;
int res = - EINVAL ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
if ( p_ptr - > publ . published | | p_ptr - > publ . connected )
goto exit ;
if ( ! peer - > ref )
goto exit ;
msg = & p_ptr - > publ . phdr ;
msg_set_destnode ( msg , peer - > node ) ;
msg_set_destport ( msg , peer - > ref ) ;
msg_set_orignode ( msg , tipc_own_addr ) ;
msg_set_origport ( msg , p_ptr - > publ . ref ) ;
msg_set_transp_seqno ( msg , 42 ) ;
msg_set_type ( msg , TIPC_CONN_MSG ) ;
if ( ! may_route ( peer - > node ) )
msg_set_hdr_sz ( msg , SHORT_H_SIZE ) ;
else
msg_set_hdr_sz ( msg , LONG_H_SIZE ) ;
p_ptr - > probing_interval = PROBING_INTERVAL ;
p_ptr - > probing_state = CONFIRMED ;
p_ptr - > publ . connected = 1 ;
k_start_timer ( & p_ptr - > timer , p_ptr - > probing_interval ) ;
2006-01-18 02:38:21 +03:00
tipc_nodesub_subscribe ( & p_ptr - > subscription , peer - > node ,
2006-01-13 00:22:32 +03:00
( void * ) ( unsigned long ) ref ,
2006-01-02 21:04:38 +03:00
( net_ev_handler ) port_handle_node_down ) ;
res = TIPC_OK ;
exit :
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2007-06-11 04:25:24 +04:00
p_ptr - > publ . max_pkt = tipc_link_get_max_pkt ( peer - > node , ref ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
/*
* tipc_disconnect ( ) : Disconnect port form peer .
* This is a node local operation .
*/
int tipc_disconnect ( u32 ref )
{
struct port * p_ptr ;
int res = - ENOTCONN ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
if ( p_ptr - > publ . connected ) {
p_ptr - > publ . connected = 0 ;
/* let timer expire on it's own to avoid deadlock! */
2006-01-18 02:38:21 +03:00
tipc_nodesub_unsubscribe ( & p_ptr - > subscription ) ;
2006-01-02 21:04:38 +03:00
res = TIPC_OK ;
}
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
/*
* tipc_shutdown ( ) : Send a SHUTDOWN msg to peer and disconnect
*/
int tipc_shutdown ( u32 ref )
{
struct port * p_ptr ;
2006-03-21 09:36:47 +03:00
struct sk_buff * buf = NULL ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
if ( p_ptr - > publ . connected ) {
u32 imp = msg_importance ( & p_ptr - > publ . phdr ) ;
if ( imp < TIPC_CRITICAL_IMPORTANCE )
imp + + ;
buf = port_build_proto_msg ( port_peerport ( p_ptr ) ,
port_peernode ( p_ptr ) ,
ref ,
tipc_own_addr ,
imp ,
TIPC_CONN_MSG ,
2007-02-09 17:25:21 +03:00
TIPC_CONN_SHUTDOWN ,
2006-01-02 21:04:38 +03:00
port_out_seqno ( p_ptr ) ,
0 ) ;
}
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
return tipc_disconnect ( ref ) ;
}
int tipc_isconnected ( u32 ref , int * isconnected )
{
struct port * p_ptr ;
2007-02-09 17:25:21 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
* isconnected = p_ptr - > publ . connected ;
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return TIPC_OK ;
}
int tipc_peer ( u32 ref , struct tipc_portid * peer )
{
struct port * p_ptr ;
int res ;
2007-02-09 17:25:21 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr )
return - EINVAL ;
if ( p_ptr - > publ . connected ) {
peer - > ref = port_peerport ( p_ptr ) ;
peer - > node = port_peernode ( p_ptr ) ;
res = TIPC_OK ;
} else
res = - ENOTCONN ;
2006-01-18 02:38:21 +03:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
int tipc_ref_valid ( u32 ref )
{
/* Works irrespective of type */
2006-01-18 02:38:21 +03:00
return ! ! tipc_ref_deref ( ref ) ;
2006-01-02 21:04:38 +03:00
}
/*
2006-01-18 02:38:21 +03:00
* tipc_port_recv_sections ( ) : Concatenate and deliver sectioned
2006-01-02 21:04:38 +03:00
* message for this node .
*/
2006-01-18 02:38:21 +03:00
int tipc_port_recv_sections ( struct port * sender , unsigned int num_sect ,
2006-01-02 21:04:38 +03:00
struct iovec const * msg_sect )
{
struct sk_buff * buf ;
int res ;
2007-02-09 17:25:21 +03:00
2006-01-02 21:04:38 +03:00
res = msg_build ( & sender - > publ . phdr , msg_sect , num_sect ,
MAX_MSG_SIZE , ! sender - > user_port , & buf ) ;
if ( likely ( buf ) )
2006-01-18 02:38:21 +03:00
tipc_port_recv_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
/**
* tipc_send - send message sections on connection
*/
int tipc_send ( u32 ref , unsigned int num_sect , struct iovec const * msg_sect )
{
struct port * p_ptr ;
u32 destnode ;
int res ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_deref ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr | | ! p_ptr - > publ . connected )
return - EINVAL ;
p_ptr - > publ . congested = 1 ;
2006-01-18 02:38:21 +03:00
if ( ! tipc_port_congested ( p_ptr ) ) {
2006-01-02 21:04:38 +03:00
destnode = port_peernode ( p_ptr ) ;
if ( likely ( destnode ! = tipc_own_addr ) )
2006-01-18 02:38:21 +03:00
res = tipc_link_send_sections_fast ( p_ptr , msg_sect , num_sect ,
destnode ) ;
2006-01-02 21:04:38 +03:00
else
2006-01-18 02:38:21 +03:00
res = tipc_port_recv_sections ( p_ptr , num_sect , msg_sect ) ;
2006-01-02 21:04:38 +03:00
if ( likely ( res ! = - ELINKCONG ) ) {
port_incr_out_seqno ( p_ptr ) ;
p_ptr - > publ . congested = 0 ;
p_ptr - > sent + + ;
return res ;
}
}
if ( port_unreliable ( p_ptr ) ) {
p_ptr - > publ . congested = 0 ;
/* Just calculate msg length and return */
return msg_calc_data_size ( msg_sect , num_sect ) ;
}
return - ELINKCONG ;
}
2007-02-09 17:25:21 +03:00
/**
2006-01-02 21:04:38 +03:00
* tipc_send_buf - send message buffer on connection
*/
int tipc_send_buf ( u32 ref , struct sk_buff * buf , unsigned int dsz )
{
struct port * p_ptr ;
struct tipc_msg * msg ;
u32 destnode ;
u32 hsz ;
u32 sz ;
u32 res ;
2007-02-09 17:25:21 +03:00
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_deref ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr | | ! p_ptr - > publ . connected )
return - EINVAL ;
msg = & p_ptr - > publ . phdr ;
hsz = msg_hdr_sz ( msg ) ;
sz = hsz + dsz ;
msg_set_size ( msg , sz ) ;
if ( skb_cow ( buf , hsz ) )
return - ENOMEM ;
skb_push ( buf , hsz ) ;
2007-03-31 18:55:19 +04:00
skb_copy_to_linear_data ( buf , msg , hsz ) ;
2006-01-02 21:04:38 +03:00
destnode = msg_destnode ( msg ) ;
p_ptr - > publ . congested = 1 ;
2006-01-18 02:38:21 +03:00
if ( ! tipc_port_congested ( p_ptr ) ) {
2006-01-02 21:04:38 +03:00
if ( likely ( destnode ! = tipc_own_addr ) )
res = tipc_send_buf_fast ( buf , destnode ) ;
else {
2006-01-18 02:38:21 +03:00
tipc_port_recv_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
res = sz ;
}
if ( likely ( res ! = - ELINKCONG ) ) {
port_incr_out_seqno ( p_ptr ) ;
p_ptr - > sent + + ;
p_ptr - > publ . congested = 0 ;
return res ;
}
}
if ( port_unreliable ( p_ptr ) ) {
p_ptr - > publ . congested = 0 ;
return dsz ;
}
return - ELINKCONG ;
}
/**
* tipc_forward2name - forward message sections to port name
*/
2007-02-09 17:25:21 +03:00
int tipc_forward2name ( u32 ref ,
struct tipc_name const * name ,
2006-01-02 21:04:38 +03:00
u32 domain ,
2007-02-09 17:25:21 +03:00
u32 num_sect ,
2006-01-02 21:04:38 +03:00
struct iovec const * msg_sect ,
2007-02-09 17:25:21 +03:00
struct tipc_portid const * orig ,
2006-01-02 21:04:38 +03:00
unsigned int importance )
{
struct port * p_ptr ;
struct tipc_msg * msg ;
u32 destnode = domain ;
u32 destport = 0 ;
int res ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_deref ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr | | p_ptr - > publ . connected )
return - EINVAL ;
msg = & p_ptr - > publ . phdr ;
msg_set_type ( msg , TIPC_NAMED_MSG ) ;
msg_set_orignode ( msg , orig - > node ) ;
msg_set_origport ( msg , orig - > ref ) ;
msg_set_hdr_sz ( msg , LONG_H_SIZE ) ;
msg_set_nametype ( msg , name - > type ) ;
msg_set_nameinst ( msg , name - > instance ) ;
msg_set_lookup_scope ( msg , addr_scope ( domain ) ) ;
if ( importance < = TIPC_CRITICAL_IMPORTANCE )
msg_set_importance ( msg , importance ) ;
2006-01-18 02:38:21 +03:00
destport = tipc_nametbl_translate ( name - > type , name - > instance , & destnode ) ;
2006-01-02 21:04:38 +03:00
msg_set_destnode ( msg , destnode ) ;
msg_set_destport ( msg , destport ) ;
if ( likely ( destport | | destnode ) ) {
p_ptr - > sent + + ;
if ( likely ( destnode = = tipc_own_addr ) )
2006-01-18 02:38:21 +03:00
return tipc_port_recv_sections ( p_ptr , num_sect , msg_sect ) ;
2007-02-09 17:25:21 +03:00
res = tipc_link_send_sections_fast ( p_ptr , msg_sect , num_sect ,
2006-01-18 02:38:21 +03:00
destnode ) ;
2006-01-02 21:04:38 +03:00
if ( likely ( res ! = - ELINKCONG ) )
return res ;
if ( port_unreliable ( p_ptr ) ) {
/* Just calculate msg length and return */
return msg_calc_data_size ( msg_sect , num_sect ) ;
}
return - ELINKCONG ;
}
2007-02-09 17:25:21 +03:00
return tipc_port_reject_sections ( p_ptr , msg , msg_sect , num_sect ,
2006-01-18 02:38:21 +03:00
TIPC_ERR_NO_NAME ) ;
2006-01-02 21:04:38 +03:00
}
/**
* tipc_send2name - send message sections to port name
*/
2007-02-09 17:25:21 +03:00
int tipc_send2name ( u32 ref ,
2006-01-02 21:04:38 +03:00
struct tipc_name const * name ,
2007-02-09 17:25:21 +03:00
unsigned int domain ,
unsigned int num_sect ,
2006-01-02 21:04:38 +03:00
struct iovec const * msg_sect )
{
struct tipc_portid orig ;
orig . ref = ref ;
orig . node = tipc_own_addr ;
return tipc_forward2name ( ref , name , domain , num_sect , msg_sect , & orig ,
TIPC_PORT_IMPORTANCE ) ;
}
2007-02-09 17:25:21 +03:00
/**
2006-01-02 21:04:38 +03:00
* tipc_forward_buf2name - forward message buffer to port name
*/
int tipc_forward_buf2name ( u32 ref ,
struct tipc_name const * name ,
u32 domain ,
struct sk_buff * buf ,
unsigned int dsz ,
struct tipc_portid const * orig ,
unsigned int importance )
{
struct port * p_ptr ;
struct tipc_msg * msg ;
u32 destnode = domain ;
u32 destport = 0 ;
int res ;
2006-01-18 02:38:21 +03:00
p_ptr = ( struct port * ) tipc_ref_deref ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr | | p_ptr - > publ . connected )
return - EINVAL ;
msg = & p_ptr - > publ . phdr ;
if ( importance < = TIPC_CRITICAL_IMPORTANCE )
msg_set_importance ( msg , importance ) ;
msg_set_type ( msg , TIPC_NAMED_MSG ) ;
msg_set_orignode ( msg , orig - > node ) ;
msg_set_origport ( msg , orig - > ref ) ;
msg_set_nametype ( msg , name - > type ) ;
msg_set_nameinst ( msg , name - > instance ) ;
msg_set_lookup_scope ( msg , addr_scope ( domain ) ) ;
msg_set_hdr_sz ( msg , LONG_H_SIZE ) ;
msg_set_size ( msg , LONG_H_SIZE + dsz ) ;
2006-01-18 02:38:21 +03:00
destport = tipc_nametbl_translate ( name - > type , name - > instance , & destnode ) ;
2006-01-02 21:04:38 +03:00
msg_set_destnode ( msg , destnode ) ;
msg_set_destport ( msg , destport ) ;
msg_dbg ( msg , " forw2name ==> " ) ;
if ( skb_cow ( buf , LONG_H_SIZE ) )
return - ENOMEM ;
skb_push ( buf , LONG_H_SIZE ) ;
2007-03-31 18:55:19 +04:00
skb_copy_to_linear_data ( buf , msg , LONG_H_SIZE ) ;
2006-01-02 21:04:38 +03:00
msg_dbg ( buf_msg ( buf ) , " PREP: " ) ;
if ( likely ( destport | | destnode ) ) {
p_ptr - > sent + + ;
if ( destnode = = tipc_own_addr )
2006-01-18 02:38:21 +03:00
return tipc_port_recv_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
res = tipc_send_buf_fast ( buf , destnode ) ;
if ( likely ( res ! = - ELINKCONG ) )
return res ;
if ( port_unreliable ( p_ptr ) )
return dsz ;
return - ELINKCONG ;
}
return tipc_reject_msg ( buf , TIPC_ERR_NO_NAME ) ;
}
2007-02-09 17:25:21 +03:00
/**
2006-01-02 21:04:38 +03:00
* tipc_send_buf2name - send message buffer to port name
*/
2007-02-09 17:25:21 +03:00
int tipc_send_buf2name ( u32 ref ,
struct tipc_name const * dest ,
2006-01-02 21:04:38 +03:00
u32 domain ,
2007-02-09 17:25:21 +03:00
struct sk_buff * buf ,
2006-01-02 21:04:38 +03:00
unsigned int dsz )
{
struct tipc_portid orig ;
orig . ref = ref ;
orig . node = tipc_own_addr ;
return tipc_forward_buf2name ( ref , dest , domain , buf , dsz , & orig ,
TIPC_PORT_IMPORTANCE ) ;
}
2007-02-09 17:25:21 +03:00
/**
2006-01-02 21:04:38 +03:00
* tipc_forward2port - forward message sections to port identity
*/
int tipc_forward2port ( u32 ref ,
struct tipc_portid const * dest ,
2007-02-09 17:25:21 +03:00
unsigned int num_sect ,
2006-01-02 21:04:38 +03:00
struct iovec const * msg_sect ,
2007-02-09 17:25:21 +03:00
struct tipc_portid const * orig ,
2006-01-02 21:04:38 +03:00
unsigned int importance )
{
struct port * p_ptr ;
struct tipc_msg * msg ;
int res ;
2006-01-18 02:38:21 +03:00
p_ptr = tipc_port_deref ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr | | p_ptr - > publ . connected )
return - EINVAL ;
msg = & p_ptr - > publ . phdr ;
msg_set_type ( msg , TIPC_DIRECT_MSG ) ;
msg_set_orignode ( msg , orig - > node ) ;
msg_set_origport ( msg , orig - > ref ) ;
msg_set_destnode ( msg , dest - > node ) ;
msg_set_destport ( msg , dest - > ref ) ;
msg_set_hdr_sz ( msg , DIR_MSG_H_SIZE ) ;
if ( importance < = TIPC_CRITICAL_IMPORTANCE )
msg_set_importance ( msg , importance ) ;
p_ptr - > sent + + ;
if ( dest - > node = = tipc_own_addr )
2006-01-18 02:38:21 +03:00
return tipc_port_recv_sections ( p_ptr , num_sect , msg_sect ) ;
res = tipc_link_send_sections_fast ( p_ptr , msg_sect , num_sect , dest - > node ) ;
2006-01-02 21:04:38 +03:00
if ( likely ( res ! = - ELINKCONG ) )
return res ;
if ( port_unreliable ( p_ptr ) ) {
/* Just calculate msg length and return */
return msg_calc_data_size ( msg_sect , num_sect ) ;
}
return - ELINKCONG ;
}
2007-02-09 17:25:21 +03:00
/**
* tipc_send2port - send message sections to port identity
2006-01-02 21:04:38 +03:00
*/
2007-02-09 17:25:21 +03:00
int tipc_send2port ( u32 ref ,
2006-01-02 21:04:38 +03:00
struct tipc_portid const * dest ,
2007-02-09 17:25:21 +03:00
unsigned int num_sect ,
2006-01-02 21:04:38 +03:00
struct iovec const * msg_sect )
{
struct tipc_portid orig ;
orig . ref = ref ;
orig . node = tipc_own_addr ;
2007-02-09 17:25:21 +03:00
return tipc_forward2port ( ref , dest , num_sect , msg_sect , & orig ,
2006-01-02 21:04:38 +03:00
TIPC_PORT_IMPORTANCE ) ;
}
2007-02-09 17:25:21 +03:00
/**
2006-01-02 21:04:38 +03:00
* tipc_forward_buf2port - forward message buffer to port identity
*/
int tipc_forward_buf2port ( u32 ref ,
struct tipc_portid const * dest ,
struct sk_buff * buf ,
unsigned int dsz ,
struct tipc_portid const * orig ,
unsigned int importance )
{
struct port * p_ptr ;
struct tipc_msg * msg ;
int res ;
2006-01-18 02:38:21 +03:00
p_ptr = ( struct port * ) tipc_ref_deref ( ref ) ;
2006-01-02 21:04:38 +03:00
if ( ! p_ptr | | p_ptr - > publ . connected )
return - EINVAL ;
msg = & p_ptr - > publ . phdr ;
msg_set_type ( msg , TIPC_DIRECT_MSG ) ;
msg_set_orignode ( msg , orig - > node ) ;
msg_set_origport ( msg , orig - > ref ) ;
msg_set_destnode ( msg , dest - > node ) ;
msg_set_destport ( msg , dest - > ref ) ;
msg_set_hdr_sz ( msg , DIR_MSG_H_SIZE ) ;
if ( importance < = TIPC_CRITICAL_IMPORTANCE )
msg_set_importance ( msg , importance ) ;
msg_set_size ( msg , DIR_MSG_H_SIZE + dsz ) ;
if ( skb_cow ( buf , DIR_MSG_H_SIZE ) )
return - ENOMEM ;
skb_push ( buf , DIR_MSG_H_SIZE ) ;
2007-03-31 18:55:19 +04:00
skb_copy_to_linear_data ( buf , msg , DIR_MSG_H_SIZE ) ;
2006-01-02 21:04:38 +03:00
msg_dbg ( msg , " buf2port: " ) ;
p_ptr - > sent + + ;
if ( dest - > node = = tipc_own_addr )
2006-01-18 02:38:21 +03:00
return tipc_port_recv_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
res = tipc_send_buf_fast ( buf , dest - > node ) ;
if ( likely ( res ! = - ELINKCONG ) )
return res ;
if ( port_unreliable ( p_ptr ) )
return dsz ;
return - ELINKCONG ;
}
2007-02-09 17:25:21 +03:00
/**
2006-01-02 21:04:38 +03:00
* tipc_send_buf2port - send message buffer to port identity
*/
2007-02-09 17:25:21 +03:00
int tipc_send_buf2port ( u32 ref ,
2006-01-02 21:04:38 +03:00
struct tipc_portid const * dest ,
2007-02-09 17:25:21 +03:00
struct sk_buff * buf ,
2006-01-02 21:04:38 +03:00
unsigned int dsz )
{
struct tipc_portid orig ;
orig . ref = ref ;
orig . node = tipc_own_addr ;
2007-02-09 17:25:21 +03:00
return tipc_forward_buf2port ( ref , dest , buf , dsz , & orig ,
2006-01-02 21:04:38 +03:00
TIPC_PORT_IMPORTANCE ) ;
}