2006-01-02 19:04:38 +01:00
/*
* net / tipc / port . c : TIPC port code
2007-02-09 23:25:21 +09:00
*
2007-06-10 17:25:24 -07:00
* Copyright ( c ) 1992 - 2007 , Ericsson AB
2008-07-14 22:42:19 -07:00
* Copyright ( c ) 2004 - 2008 , Wind River Systems
2006-01-02 19:04:38 +01:00
* All rights reserved .
*
2006-01-11 13:30:43 +01:00
* Redistribution and use in source and binary forms , with or without
2006-01-02 19:04:38 +01:00
* modification , are permitted provided that the following conditions are met :
*
2006-01-11 13:30:43 +01:00
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission .
2006-01-02 19:04:38 +01:00
*
2006-01-11 13:30:43 +01:00
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
2006-01-02 19:04:38 +01:00
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "core.h"
# include "config.h"
# include "port.h"
# include "name_table.h"
/* Connection management: */
# define PROBING_INTERVAL 3600000 /* [ms] => 1 h */
# define CONFIRMED 0
# define PROBING 1
# define MAX_REJECT_SIZE 1024
2010-12-31 18:59:34 +00:00
static struct sk_buff * msg_queue_head ;
static struct sk_buff * msg_queue_tail ;
2006-01-02 19:04:38 +01:00
2006-06-27 02:53:55 -07:00
DEFINE_SPINLOCK ( tipc_port_list_lock ) ;
static DEFINE_SPINLOCK ( queue_lock ) ;
2006-01-02 19:04:38 +01:00
2006-01-18 00:38:21 +01:00
static LIST_HEAD ( ports ) ;
2006-01-02 19:04:38 +01:00
static void port_handle_node_down ( unsigned long ref ) ;
2010-12-31 18:59:32 +00:00
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 ) ;
2006-01-02 19:04:38 +01:00
static void port_timeout ( unsigned long ref ) ;
2006-03-20 22:37:04 -08:00
static u32 port_peernode ( struct port * p_ptr )
2006-01-02 19:04:38 +01:00
{
return msg_destnode ( & p_ptr - > publ . phdr ) ;
}
2006-03-20 22:37:04 -08:00
static u32 port_peerport ( struct port * p_ptr )
2006-01-02 19:04:38 +01:00
{
return msg_destport ( & p_ptr - > publ . phdr ) ;
}
2006-03-20 22:37:04 -08:00
static u32 port_out_seqno ( struct port * p_ptr )
2006-01-02 19:04:38 +01:00
{
return msg_transp_seqno ( & p_ptr - > publ . phdr ) ;
}
2006-03-20 22:37:04 -08:00
static void port_incr_out_seqno ( struct port * p_ptr )
2006-01-02 19:04:38 +01: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
*/
2010-11-30 12:00:59 +00:00
int tipc_multicast ( u32 ref , struct tipc_name_seq const * seq ,
2006-01-02 19:04:38 +01:00
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 00:38:21 +01:00
struct port * oport = tipc_port_deref ( ref ) ;
2006-01-02 19:04:38 +01: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 ) ;
2010-05-11 14:30:12 +00:00
res = tipc_msg_build ( hdr , msg_sect , num_sect , MAX_MSG_SIZE ,
2006-01-02 19:04:38 +01:00
! oport - > user_port , & buf ) ;
if ( unlikely ( ! buf ) )
return res ;
/* Figure out where to send multicast message */
2006-01-18 00:38:21 +01:00
ext_targets = tipc_nametbl_mc_translate ( seq - > type , seq - > lower , seq - > upper ,
TIPC_NODE_SCOPE , & dports ) ;
2007-02-09 23:25:21 +09:00
/* Send message to destinations (duplicate it only if necessary) */
2006-01-02 19:04:38 +01:00
if ( ext_targets ) {
if ( dports . count ! = 0 ) {
ibuf = skb_copy ( buf , GFP_ATOMIC ) ;
if ( ibuf = = NULL ) {
2006-01-18 00:38:21 +01:00
tipc_port_list_free ( & dports ) ;
2006-01-02 19:04:38 +01:00
buf_discard ( buf ) ;
return - ENOMEM ;
}
}
2006-01-18 00:38:21 +01:00
res = tipc_bclink_send_msg ( buf ) ;
2010-12-31 18:59:35 +00:00
if ( ( res < 0 ) & & ( dports . count ! = 0 ) )
2006-01-02 19:04:38 +01:00
buf_discard ( ibuf ) ;
} else {
ibuf = buf ;
}
if ( res > = 0 ) {
if ( ibuf )
2006-01-18 00:38:21 +01:00
tipc_port_recv_mcast ( ibuf , & dports ) ;
2006-01-02 19:04:38 +01:00
} else {
2006-01-18 00:38:21 +01:00
tipc_port_list_free ( & dports ) ;
2006-01-02 19:04:38 +01:00
}
return res ;
}
/**
2006-01-18 00:38:21 +01:00
* tipc_port_recv_mcast - deliver multicast message to all destination ports
2007-02-09 23:25:21 +09:00
*
2006-01-02 19:04:38 +01:00
* If there is no port list , perform a lookup to create one
*/
2006-01-18 00:38:21 +01:00
void tipc_port_recv_mcast ( struct sk_buff * buf , struct port_list * dp )
2006-01-02 19:04:38 +01:00
{
2010-12-31 18:59:32 +00:00
struct tipc_msg * msg ;
2006-01-02 19:04:38 +01:00
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 00:38:21 +01:00
tipc_nametbl_mc_translate ( msg_nametype ( msg ) ,
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
tipc_port_recv_msg ( buf ) ;
tipc_port_list_free ( dp ) ;
2006-01-02 19:04:38 +01: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-25 23:52:17 -07:00
warn ( " Unable to deliver multicast message(s) \n " ) ;
2006-01-02 19:04:38 +01:00
goto exit ;
}
2010-12-31 18:59:35 +00:00
if ( ( index = = 0 ) & & ( cnt ! = 0 ) )
2006-01-02 19:04:38 +01:00
item = item - > next ;
2010-12-31 18:59:32 +00:00
msg_set_destport ( buf_msg ( b ) , item - > ports [ index ] ) ;
2006-01-18 00:38:21 +01:00
tipc_port_recv_msg ( b ) ;
2006-01-02 19:04:38 +01:00
}
}
exit :
buf_discard ( buf ) ;
2006-01-18 00:38:21 +01:00
tipc_port_list_free ( dp ) ;
2006-01-02 19:04:38 +01:00
}
/**
2008-05-12 15:42:28 -07:00
* tipc_createport_raw - create a generic TIPC port
2007-02-09 23:25:21 +09:00
*
2008-07-14 22:42:19 -07:00
* Returns pointer to ( locked ) TIPC port , or NULL if unable to create it
2006-01-02 19:04:38 +01:00
*/
2008-07-14 22:42:19 -07:00
struct tipc_port * tipc_createport_raw ( void * usr_handle ,
2006-01-02 19:04:38 +01:00
u32 ( * dispatcher ) ( struct tipc_port * , struct sk_buff * ) ,
void ( * wakeup ) ( struct tipc_port * ) ,
2008-07-14 22:42:19 -07:00
const u32 importance )
2006-01-02 19:04:38 +01:00
{
struct port * p_ptr ;
struct tipc_msg * msg ;
u32 ref ;
2006-07-21 14:51:30 -07:00
p_ptr = kzalloc ( sizeof ( * p_ptr ) , GFP_ATOMIC ) ;
2006-06-25 23:52:17 -07:00
if ( ! p_ptr ) {
warn ( " Port creation failed, no memory \n " ) ;
2008-07-14 22:42:19 -07:00
return NULL ;
2006-01-02 19:04:38 +01:00
}
2006-01-18 00:38:21 +01:00
ref = tipc_ref_acquire ( p_ptr , & p_ptr - > publ . lock ) ;
2006-01-02 19:04:38 +01:00
if ( ! ref ) {
2006-06-25 23:52:17 -07:00
warn ( " Port creation failed, reference table exhausted \n " ) ;
2006-01-02 19:04:38 +01:00
kfree ( p_ptr ) ;
2008-07-14 22:42:19 -07:00
return NULL ;
2006-01-02 19:04:38 +01:00
}
2007-06-10 17:25:24 -07:00
p_ptr - > publ . usr_handle = usr_handle ;
p_ptr - > publ . max_pkt = MAX_PKT_DEFAULT ;
2006-01-02 19:04:38 +01:00
p_ptr - > publ . ref = ref ;
msg = & p_ptr - > publ . phdr ;
2010-05-11 14:30:12 +00:00
tipc_msg_init ( msg , importance , TIPC_NAMED_MSG , LONG_H_SIZE , 0 ) ;
2006-01-02 19:04:38 +01:00
msg_set_origport ( msg , ref ) ;
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 ) ;
p_ptr - > dispatcher = dispatcher ;
p_ptr - > wakeup = wakeup ;
2006-03-20 22:36:47 -08:00
p_ptr - > user_port = NULL ;
2006-01-02 19:04:38 +01:00
k_init_timer ( & p_ptr - > timer , ( Handler ) port_timeout , ref ) ;
2006-01-18 00:38:21 +01:00
spin_lock_bh ( & tipc_port_list_lock ) ;
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
spin_unlock_bh ( & tipc_port_list_lock ) ;
2008-07-14 22:42:19 -07:00
return & ( p_ptr - > publ ) ;
2006-01-02 19:04:38 +01:00
}
int tipc_deleteport ( u32 ref )
{
struct port * p_ptr ;
2006-03-20 22:36:47 -08:00
struct sk_buff * buf = NULL ;
2006-01-02 19:04:38 +01:00
2006-03-20 22:36:47 -08:00
tipc_withdraw ( ref , 0 , NULL ) ;
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2007-02-09 23:25:21 +09:00
if ( ! p_ptr )
2006-01-02 19:04:38 +01:00
return - EINVAL ;
2006-01-18 00:38:21 +01:00
tipc_ref_discard ( ref ) ;
tipc_port_unlock ( p_ptr ) ;
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
tipc_nodesub_unsubscribe ( & p_ptr - > subscription ) ;
2006-01-02 19:04:38 +01:00
}
2010-12-31 18:59:30 +00:00
kfree ( p_ptr - > user_port ) ;
2006-01-02 19:04:38 +01:00
2006-01-18 00:38:21 +01:00
spin_lock_bh ( & tipc_port_list_lock ) ;
2006-01-02 19:04:38 +01:00
list_del ( & p_ptr - > port_list ) ;
list_del ( & p_ptr - > wait_list ) ;
2006-01-18 00:38:21 +01:00
spin_unlock_bh ( & tipc_port_list_lock ) ;
2006-01-02 19:04:38 +01:00
k_term_timer ( & p_ptr - > timer ) ;
kfree ( p_ptr ) ;
2006-01-18 00:38:21 +01:00
tipc_net_route_msg ( buf ) ;
2008-07-14 22:44:01 -07:00
return 0 ;
2006-01-02 19:04:38 +01:00
}
2006-03-20 22:37:04 -08:00
static int port_unreliable ( struct port * p_ptr )
2006-01-02 19:04:38 +01:00
{
return msg_src_droppable ( & p_ptr - > publ . phdr ) ;
}
int tipc_portunreliable ( u32 ref , unsigned int * isunreliable )
{
struct port * p_ptr ;
2007-02-09 23:25:21 +09:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr )
return - EINVAL ;
* isunreliable = port_unreliable ( p_ptr ) ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-07-14 22:44:01 -07:00
return 0 ;
2006-01-02 19:04:38 +01:00
}
int tipc_set_portunreliable ( u32 ref , unsigned int isunreliable )
{
struct port * p_ptr ;
2007-02-09 23:25:21 +09:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr )
return - EINVAL ;
msg_set_src_droppable ( & p_ptr - > publ . phdr , ( isunreliable ! = 0 ) ) ;
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
2008-07-14 22:44:01 -07:00
return 0 ;
2006-01-02 19:04:38 +01:00
}
2006-03-20 22:37:04 -08:00
static int port_unreturnable ( struct port * p_ptr )
2006-01-02 19:04:38 +01:00
{
return msg_dest_droppable ( & p_ptr - > publ . phdr ) ;
}
int tipc_portunreturnable ( u32 ref , unsigned int * isunrejectable )
{
struct port * p_ptr ;
2007-02-09 23:25:21 +09:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr )
return - EINVAL ;
* isunrejectable = port_unreturnable ( p_ptr ) ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-07-14 22:44:01 -07:00
return 0 ;
2006-01-02 19:04:38 +01:00
}
int tipc_set_portunreturnable ( u32 ref , unsigned int isunrejectable )
{
struct port * p_ptr ;
2007-02-09 23:25:21 +09:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr )
return - EINVAL ;
msg_set_dest_droppable ( & p_ptr - > publ . phdr , ( isunrejectable ! = 0 ) ) ;
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
2008-07-14 22:44:01 -07:00
return 0 ;
2006-01-02 19:04:38 +01:00
}
2007-02-09 23:25:21 +09:00
/*
* port_build_proto_msg ( ) : build a port level protocol
* or a connection abortion message . Called with
2006-01-02 19:04:38 +01:00
* tipc_port lock on .
*/
static struct sk_buff * port_build_proto_msg ( u32 destport , u32 destnode ,
u32 origport , u32 orignode ,
2007-02-09 23:25:21 +09:00
u32 usr , u32 type , u32 err ,
2006-01-02 19:04:38 +01:00
u32 seqno , u32 ack )
{
struct sk_buff * buf ;
struct tipc_msg * msg ;
2007-02-09 23:25:21 +09:00
2010-10-13 13:20:35 +00:00
buf = tipc_buf_acquire ( LONG_H_SIZE ) ;
2006-01-02 19:04:38 +01:00
if ( buf ) {
msg = buf_msg ( buf ) ;
2010-05-11 14:30:12 +00:00
tipc_msg_init ( msg , usr , type , LONG_H_SIZE , destnode ) ;
2008-06-04 17:37:34 -07:00
msg_set_errcode ( msg , err ) ;
2006-01-02 19:04:38 +01:00
msg_set_destport ( msg , destport ) ;
msg_set_origport ( msg , origport ) ;
msg_set_orignode ( msg , orignode ) ;
msg_set_transp_seqno ( msg , seqno ) ;
msg_set_msgcnt ( msg , ack ) ;
}
return buf ;
}
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 + + ;
/* 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 ;
2010-10-13 13:20:35 +00:00
rbuf = tipc_buf_acquire ( data_sz + hdr_sz ) ;
2006-01-02 19:04:38 +01:00
if ( rbuf = = NULL ) {
buf_discard ( buf ) ;
return data_sz ;
}
rmsg = buf_msg ( rbuf ) ;
2010-05-11 14:30:12 +00:00
tipc_msg_init ( rmsg , imp , msg_type ( msg ) , hdr_sz , msg_orignode ( msg ) ) ;
2008-06-04 17:37:34 -07:00
msg_set_errcode ( rmsg , err ) ;
2006-01-02 19:04:38 +01:00
msg_set_destport ( rmsg , msg_origport ( msg ) ) ;
msg_set_origport ( rmsg , msg_destport ( msg ) ) ;
2008-06-04 17:48:25 -07:00
if ( msg_short ( msg ) ) {
2006-01-02 19:04:38 +01:00
msg_set_orignode ( rmsg , tipc_own_addr ) ;
2008-06-04 17:48:25 -07:00
/* leave name type & instance as zeroes */
} else {
2006-01-02 19:04:38 +01:00
msg_set_orignode ( rmsg , msg_destnode ( msg ) ) ;
2008-06-04 17:48:25 -07:00
msg_set_nametype ( rmsg , msg_nametype ( msg ) ) ;
msg_set_nameinst ( rmsg , msg_nameinst ( msg ) ) ;
}
2007-02-09 23:25:21 +09:00
msg_set_size ( rmsg , data_sz + hdr_sz ) ;
2007-03-31 11:55:19 -03:00
skb_copy_to_linear_data_offset ( rbuf , hdr_sz , msg_data ( msg ) , data_sz ) ;
2006-01-02 19:04:38 +01:00
/* send self-abort message when rejecting on a connected port */
if ( msg_connected ( msg ) ) {
2006-03-20 22:36:47 -08:00
struct sk_buff * abuf = NULL ;
2006-01-18 00:38:21 +01:00
struct port * p_ptr = tipc_port_lock ( msg_destport ( msg ) ) ;
2006-01-02 19:04:38 +01:00
if ( p_ptr ) {
if ( p_ptr - > publ . connected )
abuf = port_build_self_abort_msg ( p_ptr , err ) ;
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 19:04:38 +01:00
}
2006-01-18 00:38:21 +01:00
tipc_net_route_msg ( abuf ) ;
2006-01-02 19:04:38 +01:00
}
/* send rejected message */
buf_discard ( buf ) ;
2006-01-18 00:38:21 +01:00
tipc_net_route_msg ( rbuf ) ;
2006-01-02 19:04:38 +01:00
return data_sz ;
}
2006-01-18 00:38:21 +01: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 19:04:38 +01:00
{
struct sk_buff * buf ;
int res ;
2010-05-11 14:30:12 +00:00
res = tipc_msg_build ( hdr , msg_sect , num_sect , MAX_MSG_SIZE ,
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
struct port * p_ptr = tipc_port_lock ( ref ) ;
2006-03-20 22:36:47 -08:00
struct sk_buff * buf = NULL ;
2006-01-02 19:04:38 +01:00
2006-10-16 21:38:05 -07:00
if ( ! p_ptr )
return ;
if ( ! p_ptr - > publ . connected ) {
tipc_port_unlock ( p_ptr ) ;
2006-01-02 19:04:38 +01:00
return ;
2006-10-16 21:38:05 -07:00
}
2006-01-02 19:04:38 +01: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 23:25:21 +09:00
TIPC_OK ,
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( buf ) ;
2006-01-02 19:04:38 +01:00
}
static void port_handle_node_down ( unsigned long ref )
{
2006-01-18 00:38:21 +01:00
struct port * p_ptr = tipc_port_lock ( ref ) ;
2010-12-31 18:59:32 +00:00
struct sk_buff * buf = NULL ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr )
return ;
buf = port_build_self_abort_msg ( p_ptr , TIPC_ERR_NO_NODE ) ;
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( buf ) ;
2006-01-02 19:04:38 +01: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-20 22:36:47 -08:00
return NULL ;
2006-01-02 19:04:38 +01: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 23:25:21 +09:00
err ,
2006-01-02 19:04:38 +01: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-20 22:36:47 -08:00
return NULL ;
2006-01-02 19:04:38 +01: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 23:25:21 +09:00
err ,
2006-01-02 19:04:38 +01:00
port_out_seqno ( p_ptr ) ,
0 ) ;
}
2006-01-18 00:38:21 +01:00
void tipc_port_recv_proto_msg ( struct sk_buff * buf )
2006-01-02 19:04:38 +01:00
{
struct tipc_msg * msg = buf_msg ( buf ) ;
2006-01-18 00:38:21 +01:00
struct port * p_ptr = tipc_port_lock ( msg_destport ( msg ) ) ;
2006-01-02 19:04:38 +01:00
u32 err = TIPC_OK ;
2006-03-20 22:36:47 -08:00
struct sk_buff * r_buf = NULL ;
struct sk_buff * abort_buf = NULL ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr ) {
err = TIPC_ERR_NO_PORT ;
} else if ( p_ptr - > publ . connected ) {
2010-08-17 11:00:11 +00:00
if ( ( port_peernode ( p_ptr ) ! = msg_orignode ( msg ) ) | |
( port_peerport ( p_ptr ) ! = msg_origport ( msg ) ) ) {
2006-01-02 19:04:38 +01:00
err = TIPC_ERR_NO_PORT ;
2010-08-17 11:00:11 +00:00
} else if ( msg_type ( msg ) = = CONN_ACK ) {
2007-02-09 23:25:21 +09:00
int wakeup = tipc_port_congested ( p_ptr ) & &
2006-01-02 19:04:38 +01:00
p_ptr - > publ . congested & &
p_ptr - > wakeup ;
p_ptr - > acked + = msg_msgcnt ( msg ) ;
2006-01-18 00:38:21 +01:00
if ( tipc_port_congested ( p_ptr ) )
2006-01-02 19:04:38 +01: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 23:25:21 +09:00
msg_orignode ( msg ) ,
msg_destport ( msg ) ,
2006-01-02 19:04:38 +01:00
tipc_own_addr ,
2008-03-06 15:06:55 -08:00
TIPC_HIGH_IMPORTANCE ,
2006-01-02 19:04:38 +01:00
TIPC_CONN_MSG ,
err ,
0 ,
0 ) ;
goto exit ;
}
/* All is fine */
if ( msg_type ( msg ) = = CONN_PROBE ) {
2007-02-09 23:25:21 +09:00
r_buf = port_build_proto_msg ( msg_origport ( msg ) ,
msg_orignode ( msg ) ,
msg_destport ( msg ) ,
tipc_own_addr ,
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( r_buf ) ;
tipc_net_route_msg ( abort_buf ) ;
2006-01-02 19:04:38 +01:00
buf_discard ( buf ) ;
}
static void port_print ( struct port * p_ptr , struct print_buf * buf , int full_id )
{
2007-02-09 23:25:21 +09:00
struct publication * publ ;
2006-01-02 19:04:38 +01:00
if ( full_id )
2007-02-09 23:25:21 +09:00
tipc_printf ( buf , " <%u.%u.%u:%u>: " ,
2006-01-02 19:04:38 +01:00
tipc_zone ( tipc_own_addr ) , tipc_cluster ( tipc_own_addr ) ,
2007-02-09 23:25:21 +09:00
tipc_node ( tipc_own_addr ) , p_ptr - > publ . ref ) ;
2006-01-02 19:04:38 +01:00
else
tipc_printf ( buf , " %-10u: " , p_ptr - > publ . ref ) ;
2007-02-09 23:25:21 +09: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 ) ;
2010-12-31 18:59:32 +00:00
} else if ( p_ptr - > publ . published ) {
2007-02-09 23:25:21 +09:00
tipc_printf ( buf , " bound to " ) ;
list_for_each_entry ( publ , & p_ptr - > publications , pport_list ) {
2006-01-02 19:04:38 +01:00
if ( publ - > lower = = publ - > upper )
tipc_printf ( buf , " {%u,%u} " , publ - > type ,
publ - > lower ) ;
else
2007-02-09 23:25:21 +09:00
tipc_printf ( buf , " {%u,%u,%u} " , publ - > type ,
2006-01-02 19:04:38 +01:00
publ - > lower , publ - > upper ) ;
2007-02-09 23:25:21 +09:00
}
}
tipc_printf ( buf , " \n " ) ;
2006-01-02 19:04:38 +01:00
}
# define MAX_PORT_QUERY 32768
2006-01-18 00:38:21 +01:00
struct sk_buff * tipc_port_get_ports ( void )
2006-01-02 19:04:38 +01:00
{
struct sk_buff * buf ;
struct tlv_desc * rep_tlv ;
struct print_buf pb ;
struct port * p_ptr ;
int str_len ;
2006-01-18 00:38:21 +01:00
buf = tipc_cfg_reply_alloc ( TLV_SPACE ( MAX_PORT_QUERY ) ) ;
2006-01-02 19:04:38 +01:00
if ( ! buf )
return NULL ;
rep_tlv = ( struct tlv_desc * ) buf - > data ;
2006-01-18 00:38:21 +01:00
tipc_printbuf_init ( & pb , TLV_DATA ( rep_tlv ) , MAX_PORT_QUERY ) ;
spin_lock_bh ( & tipc_port_list_lock ) ;
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
spin_unlock_bh ( & tipc_port_list_lock ) ;
str_len = tipc_printbuf_validate ( & pb ) ;
2006-01-02 19:04:38 +01:00
skb_put ( buf , TLV_SPACE ( str_len ) ) ;
TLV_SET ( rep_tlv , TIPC_TLV_ULTRA_STRING , NULL , str_len ) ;
return buf ;
}
2006-01-18 00:38:21 +01:00
void tipc_port_reinit ( void )
2006-01-02 19:04:38 +01:00
{
struct port * p_ptr ;
struct tipc_msg * msg ;
2006-01-18 00:38:21 +01:00
spin_lock_bh ( & tipc_port_list_lock ) ;
2006-01-02 19:04:38 +01:00
list_for_each_entry ( p_ptr , & ports , port_list ) {
msg = & p_ptr - > publ . phdr ;
if ( msg_orignode ( msg ) = = tipc_own_addr )
break ;
2008-05-21 14:54:12 -07:00
msg_set_prevnode ( msg , tipc_own_addr ) ;
2006-01-02 19:04:38 +01:00
msg_set_orignode ( msg , tipc_own_addr ) ;
}
2006-01-18 00:38:21 +01:00
spin_unlock_bh ( & tipc_port_list_lock ) ;
2006-01-02 19:04:38 +01: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-20 22:36:47 -08:00
msg_queue_head = NULL ;
2006-01-02 19:04:38 +01: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-25 23:38:58 -07:00
u32 message_type ;
2006-01-02 19:04:38 +01:00
struct sk_buff * next = buf - > next ;
struct tipc_msg * msg = buf_msg ( buf ) ;
u32 dref = msg_destport ( msg ) ;
2007-02-09 23:25:21 +09:00
2006-06-25 23:38:58 -07:00
message_type = msg_type ( msg ) ;
if ( message_type > TIPC_DIRECT_MSG )
goto reject ; /* Unsupported message type */
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( dref ) ;
2006-06-25 23:38:58 -07:00
if ( ! p_ptr )
goto reject ; /* Port deleted while msg in queue */
2006-01-02 19:04:38 +01: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-25 23:38:58 -07:00
switch ( message_type ) {
2007-02-09 23:25:21 +09:00
2006-01-02 19:04:38 +01: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 ) ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-06-04 17:28:45 -07:00
if ( unlikely ( ! cb ) )
goto reject ;
2006-01-02 19:04:38 +01:00
if ( unlikely ( ! connected ) ) {
2008-06-04 17:28:21 -07:00
if ( tipc_connect2port ( dref , & orig ) )
2006-01-02 19:04:38 +01:00
goto reject ;
2008-06-04 17:28:21 -07:00
} else if ( ( msg_origport ( msg ) ! = peer_port ) | |
( msg_orignode ( msg ) ! = peer_node ) )
2006-01-02 19:04:38 +01:00
goto reject ;
2007-02-09 23:25:21 +09:00
if ( unlikely ( + + p_ptr - > publ . conn_unacked > =
2006-01-02 19:04:38 +01:00
TIPC_FLOW_CONTROL_WIN ) )
2007-02-09 23:25:21 +09:00
tipc_acknowledge ( dref ,
2006-01-02 19:04:38 +01: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 ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-06-04 17:28:45 -07:00
if ( unlikely ( ! cb | | connected ) )
2006-01-02 19:04:38 +01:00
goto reject ;
skb_pull ( buf , msg_hdr_sz ( msg ) ) ;
2007-02-09 23:25:21 +09:00
cb ( usr_handle , dref , & buf , msg_data ( msg ) ,
2006-01-02 19:04:38 +01:00
msg_data_sz ( msg ) , msg_importance ( msg ) ,
& orig ) ;
break ;
}
2006-06-25 23:38:58 -07:00
case TIPC_MCAST_MSG :
2006-01-02 19:04:38 +01:00
case TIPC_NAMED_MSG : {
tipc_named_msg_event cb = up_ptr - > named_msg_cb ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-06-04 17:28:45 -07:00
if ( unlikely ( ! cb | | connected | | ! published ) )
2006-01-02 19:04:38 +01:00
goto reject ;
dseq . type = msg_nametype ( msg ) ;
dseq . lower = msg_nameinst ( msg ) ;
2006-06-25 23:38:58 -07:00
dseq . upper = ( message_type = = TIPC_NAMED_MSG )
? dseq . lower : msg_nameupper ( msg ) ;
2006-01-02 19:04:38 +01:00
skb_pull ( buf , msg_hdr_sz ( msg ) ) ;
2007-02-09 23:25:21 +09:00
cb ( usr_handle , dref , & buf , msg_data ( msg ) ,
2006-01-02 19:04:38 +01:00
msg_data_sz ( msg ) , msg_importance ( msg ) ,
& orig , & dseq ) ;
break ;
}
}
if ( buf )
buf_discard ( buf ) ;
buf = next ;
continue ;
err :
2006-06-25 23:38:58 -07:00
switch ( message_type ) {
2007-02-09 23:25:21 +09:00
2006-01-02 19:04:38 +01:00
case TIPC_CONN_MSG : {
2007-02-09 23:25:21 +09:00
tipc_conn_shutdown_event cb =
2006-01-02 19:04:38 +01:00
up_ptr - > conn_err_cb ;
u32 peer_port = port_peerport ( p_ptr ) ;
u32 peer_node = port_peernode ( p_ptr ) ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-06-04 17:28:45 -07:00
if ( ! cb | | ! connected )
2006-01-02 19:04:38 +01:00
break ;
2008-06-04 17:28:45 -07:00
if ( ( msg_origport ( msg ) ! = peer_port ) | |
( msg_orignode ( msg ) ! = peer_node ) )
2006-01-02 19:04:38 +01:00
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 ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-06-04 17:28:45 -07:00
if ( ! cb | | connected )
2006-01-02 19:04:38 +01:00
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-25 23:38:58 -07:00
case TIPC_MCAST_MSG :
2006-01-02 19:04:38 +01:00
case TIPC_NAMED_MSG : {
2007-02-09 23:25:21 +09:00
tipc_named_msg_err_event cb =
2006-01-02 19:04:38 +01:00
up_ptr - > named_err_cb ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-06-04 17:28:45 -07:00
if ( ! cb | | connected )
2006-01-02 19:04:38 +01:00
break ;
dseq . type = msg_nametype ( msg ) ;
dseq . lower = msg_nameinst ( msg ) ;
2006-06-25 23:38:58 -07:00
dseq . upper = ( message_type = = TIPC_NAMED_MSG )
? dseq . lower : msg_nameupper ( msg ) ;
2006-01-02 19:04:38 +01:00
skb_pull ( buf , msg_hdr_sz ( msg ) ) ;
2007-02-09 23:25:21 +09:00
cb ( usr_handle , dref , & buf , msg_data ( msg ) ,
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
tipc_k_signal ( ( Handler ) port_dispatcher_sigh , 0 ) ;
2006-01-02 19:04:38 +01:00
}
spin_unlock_bh ( & queue_lock ) ;
2008-07-14 22:44:01 -07:00
return 0 ;
2006-01-02 19:04:38 +01:00
}
2007-02-09 23:25:21 +09:00
/*
2006-01-02 19:04:38 +01:00
* Wake up port after congestion : Called with port locked ,
2007-02-09 23:25:21 +09:00
*
2006-01-02 19:04:38 +01:00
*/
static void port_wakeup_sh ( unsigned long ref )
{
struct port * p_ptr ;
struct user_port * up_ptr ;
2006-03-20 22:36:47 -08:00
tipc_continue_event cb = NULL ;
void * uh = NULL ;
2006-01-02 19:04:38 +01:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 19:04:38 +01:00
}
if ( cb )
cb ( uh , ref ) ;
}
static void port_wakeup ( struct tipc_port * p_ptr )
{
2006-01-18 00:38:21 +01:00
tipc_k_signal ( ( Handler ) port_wakeup_sh , p_ptr - > ref ) ;
2006-01-02 19:04:38 +01:00
}
void tipc_acknowledge ( u32 ref , u32 ack )
{
struct port * p_ptr ;
2006-03-20 22:36:47 -08:00
struct sk_buff * buf = NULL ;
2006-01-02 19:04:38 +01:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01: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 23:25:21 +09:00
TIPC_OK ,
2006-01-02 19:04:38 +01:00
port_out_seqno ( p_ptr ) ,
ack ) ;
}
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( buf ) ;
2006-01-02 19:04:38 +01:00
}
/*
2010-12-31 18:59:22 +00:00
* tipc_createport ( ) : user level call .
2006-01-02 19:04:38 +01:00
*/
2010-12-31 18:59:22 +00:00
int tipc_createport ( void * usr_handle ,
2007-02-09 23:25:21 +09:00
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 19:04:38 +01:00
tipc_continue_event continue_event_cb , /* May be zero */
u32 * portref )
{
struct user_port * up_ptr ;
2007-02-09 23:25:21 +09:00
struct port * p_ptr ;
2006-01-02 19:04:38 +01:00
2006-07-21 14:51:30 -07:00
up_ptr = kmalloc ( sizeof ( * up_ptr ) , GFP_ATOMIC ) ;
2006-06-25 23:52:17 -07:00
if ( ! up_ptr ) {
2006-06-25 23:50:01 -07:00
warn ( " Port creation failed, no memory \n " ) ;
2006-01-02 19:04:38 +01:00
return - ENOMEM ;
}
2008-07-14 22:42:19 -07:00
p_ptr = ( struct port * ) tipc_createport_raw ( NULL , port_dispatcher ,
port_wakeup , importance ) ;
if ( ! p_ptr ) {
2006-01-02 19:04:38 +01:00
kfree ( up_ptr ) ;
return - ENOMEM ;
}
p_ptr - > user_port = up_ptr ;
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 ;
* portref = p_ptr - > publ . ref ;
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
2008-07-14 22:44:01 -07:00
return 0 ;
2006-01-02 19:04:38 +01:00
}
int tipc_portimportance ( u32 ref , unsigned int * importance )
{
struct port * p_ptr ;
2007-02-09 23:25:21 +09:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr )
return - EINVAL ;
* importance = ( unsigned int ) msg_importance ( & p_ptr - > publ . phdr ) ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-07-14 22:44:01 -07:00
return 0 ;
2006-01-02 19:04:38 +01:00
}
int tipc_set_portimportance ( u32 ref , unsigned int imp )
{
struct port * p_ptr ;
if ( imp > TIPC_CRITICAL_IMPORTANCE )
return - EINVAL ;
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr )
return - EINVAL ;
msg_set_importance ( & p_ptr - > publ . phdr , ( u32 ) imp ) ;
2008-01-08 23:48:20 -08:00
tipc_port_unlock ( p_ptr ) ;
2008-07-14 22:44:01 -07:00
return 0 ;
2006-01-02 19:04:38 +01:00
}
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 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-10-31 16:59:35 -08:00
if ( ! p_ptr )
return - EINVAL ;
2006-01-02 19:04:38 +01:00
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 00:38:21 +01:00
publ = tipc_nametbl_publish ( seq - > type , seq - > lower , seq - > upper ,
scope , p_ptr - > publ . ref , key ) ;
2006-01-02 19:04:38 +01:00
if ( publ ) {
list_add ( & publ - > pport_list , & p_ptr - > publications ) ;
p_ptr - > pub_count + + ;
p_ptr - > publ . published = 1 ;
2008-07-14 22:44:01 -07:00
res = 0 ;
2006-01-02 19:04:38 +01:00
}
exit :
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 19:04:38 +01: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 23:25:21 +09:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr )
return - EINVAL ;
if ( ! seq ) {
2007-02-09 23:25:21 +09:00
list_for_each_entry_safe ( publ , tpubl ,
2006-01-02 19:04:38 +01:00
& p_ptr - > publications , pport_list ) {
2007-02-09 23:25:21 +09:00
tipc_nametbl_withdraw ( publ - > type , publ - > lower ,
2006-01-18 00:38:21 +01:00
publ - > ref , publ - > key ) ;
2006-01-02 19:04:38 +01:00
}
2008-07-14 22:44:01 -07:00
res = 0 ;
2006-01-02 19:04:38 +01:00
} else {
2007-02-09 23:25:21 +09:00
list_for_each_entry_safe ( publ , tpubl ,
2006-01-02 19:04:38 +01: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 23:25:21 +09:00
tipc_nametbl_withdraw ( publ - > type , publ - > lower ,
2006-01-18 00:38:21 +01:00
publ - > ref , publ - > key ) ;
2008-07-14 22:44:01 -07:00
res = 0 ;
2006-01-02 19:04:38 +01:00
break ;
}
}
if ( list_empty ( & p_ptr - > publications ) )
p_ptr - > publ . published = 0 ;
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01: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 ) ;
2010-12-31 18:59:17 +00:00
msg_set_hdr_sz ( msg , SHORT_H_SIZE ) ;
2006-01-02 19:04:38 +01:00
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 ) ;
2010-12-31 18:59:32 +00:00
tipc_nodesub_subscribe ( & p_ptr - > subscription , peer - > node ,
2006-01-12 13:22:32 -08:00
( void * ) ( unsigned long ) ref ,
2006-01-02 19:04:38 +01:00
( net_ev_handler ) port_handle_node_down ) ;
2008-07-14 22:44:01 -07:00
res = 0 ;
2006-01-02 19:04:38 +01:00
exit :
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
2007-06-10 17:25:24 -07:00
p_ptr - > publ . max_pkt = tipc_link_get_max_pkt ( peer - > node , ref ) ;
2006-01-02 19:04:38 +01:00
return res ;
}
2008-04-15 00:22:02 -07:00
/**
* tipc_disconnect_port - disconnect port from peer
*
* Port must be locked .
*/
int tipc_disconnect_port ( struct tipc_port * tp_ptr )
{
int res ;
if ( tp_ptr - > connected ) {
tp_ptr - > connected = 0 ;
/* let timer expire on it's own to avoid deadlock! */
tipc_nodesub_unsubscribe (
& ( ( struct port * ) tp_ptr ) - > subscription ) ;
2008-07-14 22:44:01 -07:00
res = 0 ;
2008-04-15 00:22:02 -07:00
} else {
res = - ENOTCONN ;
}
return res ;
}
2006-01-02 19:04:38 +01:00
/*
* tipc_disconnect ( ) : Disconnect port form peer .
* This is a node local operation .
*/
int tipc_disconnect ( u32 ref )
{
struct port * p_ptr ;
2008-04-15 00:22:02 -07:00
int res ;
2006-01-02 19:04:38 +01:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr )
return - EINVAL ;
2008-04-15 00:22:02 -07:00
res = tipc_disconnect_port ( ( struct tipc_port * ) p_ptr ) ;
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
2006-01-02 19:04:38 +01:00
return res ;
}
/*
* tipc_shutdown ( ) : Send a SHUTDOWN msg to peer and disconnect
*/
int tipc_shutdown ( u32 ref )
{
struct port * p_ptr ;
2006-03-20 22:36:47 -08:00
struct sk_buff * buf = NULL ;
2006-01-02 19:04:38 +01:00
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_lock ( ref ) ;
2006-01-02 19:04:38 +01: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 23:25:21 +09:00
TIPC_CONN_SHUTDOWN ,
2006-01-02 19:04:38 +01:00
port_out_seqno ( p_ptr ) ,
0 ) ;
}
2006-01-18 00:38:21 +01:00
tipc_port_unlock ( p_ptr ) ;
tipc_net_route_msg ( buf ) ;
2006-01-02 19:04:38 +01:00
return tipc_disconnect ( ref ) ;
}
/*
2006-01-18 00:38:21 +01:00
* tipc_port_recv_sections ( ) : Concatenate and deliver sectioned
2006-01-02 19:04:38 +01:00
* message for this node .
*/
2010-10-13 13:20:35 +00:00
static int tipc_port_recv_sections ( struct port * sender , unsigned int num_sect ,
struct iovec const * msg_sect )
2006-01-02 19:04:38 +01:00
{
struct sk_buff * buf ;
int res ;
2007-02-09 23:25:21 +09:00
2010-05-11 14:30:12 +00:00
res = tipc_msg_build ( & sender - > publ . phdr , msg_sect , num_sect ,
2006-01-02 19:04:38 +01:00
MAX_MSG_SIZE , ! sender - > user_port , & buf ) ;
if ( likely ( buf ) )
2006-01-18 00:38:21 +01:00
tipc_port_recv_msg ( buf ) ;
2006-01-02 19:04:38 +01: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 00:38:21 +01:00
p_ptr = tipc_port_deref ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr | | ! p_ptr - > publ . connected )
return - EINVAL ;
p_ptr - > publ . congested = 1 ;
2006-01-18 00:38:21 +01:00
if ( ! tipc_port_congested ( p_ptr ) ) {
2006-01-02 19:04:38 +01:00
destnode = port_peernode ( p_ptr ) ;
if ( likely ( destnode ! = tipc_own_addr ) )
2006-01-18 00:38:21 +01:00
res = tipc_link_send_sections_fast ( p_ptr , msg_sect , num_sect ,
destnode ) ;
2006-01-02 19:04:38 +01:00
else
2006-01-18 00:38:21 +01:00
res = tipc_port_recv_sections ( p_ptr , num_sect , msg_sect ) ;
2006-01-02 19:04:38 +01: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 */
2010-05-11 14:30:12 +00:00
return tipc_msg_calc_data_size ( msg_sect , num_sect ) ;
2006-01-02 19:04:38 +01:00
}
return - ELINKCONG ;
}
/**
2010-11-30 12:01:02 +00:00
* tipc_send2name - send message sections to port name
2006-01-02 19:04:38 +01:00
*/
2010-11-30 12:01:02 +00:00
int tipc_send2name ( u32 ref , struct tipc_name const * name , unsigned int domain ,
unsigned int num_sect , struct iovec const * msg_sect )
2006-01-02 19:04:38 +01:00
{
struct port * p_ptr ;
struct tipc_msg * msg ;
u32 destnode = domain ;
2010-05-11 14:30:06 +00:00
u32 destport ;
2006-01-02 19:04:38 +01:00
int res ;
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_deref ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr | | p_ptr - > publ . connected )
return - EINVAL ;
msg = & p_ptr - > publ . phdr ;
msg_set_type ( msg , TIPC_NAMED_MSG ) ;
2010-11-30 12:01:02 +00:00
msg_set_orignode ( msg , tipc_own_addr ) ;
msg_set_origport ( msg , ref ) ;
2006-01-02 19:04:38 +01:00
msg_set_hdr_sz ( msg , LONG_H_SIZE ) ;
msg_set_nametype ( msg , name - > type ) ;
msg_set_nameinst ( msg , name - > instance ) ;
2010-05-11 14:30:12 +00:00
msg_set_lookup_scope ( msg , tipc_addr_scope ( domain ) ) ;
2006-01-18 00:38:21 +01:00
destport = tipc_nametbl_translate ( name - > type , name - > instance , & destnode ) ;
2006-01-02 19:04:38 +01:00
msg_set_destnode ( msg , destnode ) ;
msg_set_destport ( msg , destport ) ;
2010-09-03 08:33:39 +00:00
if ( likely ( destport ) ) {
2006-01-02 19:04:38 +01:00
p_ptr - > sent + + ;
if ( likely ( destnode = = tipc_own_addr ) )
2006-01-18 00:38:21 +01:00
return tipc_port_recv_sections ( p_ptr , num_sect , msg_sect ) ;
2007-02-09 23:25:21 +09:00
res = tipc_link_send_sections_fast ( p_ptr , msg_sect , num_sect ,
2006-01-18 00:38:21 +01:00
destnode ) ;
2006-01-02 19:04:38 +01:00
if ( likely ( res ! = - ELINKCONG ) )
return res ;
if ( port_unreliable ( p_ptr ) ) {
/* Just calculate msg length and return */
2010-05-11 14:30:12 +00:00
return tipc_msg_calc_data_size ( msg_sect , num_sect ) ;
2006-01-02 19:04:38 +01:00
}
return - ELINKCONG ;
}
2007-02-09 23:25:21 +09:00
return tipc_port_reject_sections ( p_ptr , msg , msg_sect , num_sect ,
2006-01-18 00:38:21 +01:00
TIPC_ERR_NO_NAME ) ;
2006-01-02 19:04:38 +01:00
}
/**
2010-11-30 12:01:02 +00:00
* tipc_send2port - send message sections to port identity
2006-01-02 19:04:38 +01:00
*/
2010-11-30 12:01:02 +00:00
int tipc_send2port ( u32 ref , struct tipc_portid const * dest ,
unsigned int num_sect , struct iovec const * msg_sect )
2006-01-02 19:04:38 +01:00
{
struct port * p_ptr ;
struct tipc_msg * msg ;
int res ;
2006-01-18 00:38:21 +01:00
p_ptr = tipc_port_deref ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr | | p_ptr - > publ . connected )
return - EINVAL ;
msg = & p_ptr - > publ . phdr ;
msg_set_type ( msg , TIPC_DIRECT_MSG ) ;
2010-11-30 12:01:02 +00:00
msg_set_orignode ( msg , tipc_own_addr ) ;
msg_set_origport ( msg , ref ) ;
2006-01-02 19:04:38 +01:00
msg_set_destnode ( msg , dest - > node ) ;
msg_set_destport ( msg , dest - > ref ) ;
msg_set_hdr_sz ( msg , DIR_MSG_H_SIZE ) ;
p_ptr - > sent + + ;
if ( dest - > node = = tipc_own_addr )
2006-01-18 00:38:21 +01: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 19:04:38 +01:00
if ( likely ( res ! = - ELINKCONG ) )
return res ;
if ( port_unreliable ( p_ptr ) ) {
/* Just calculate msg length and return */
2010-05-11 14:30:12 +00:00
return tipc_msg_calc_data_size ( msg_sect , num_sect ) ;
2006-01-02 19:04:38 +01:00
}
return - ELINKCONG ;
}
2007-02-09 23:25:21 +09:00
/**
2010-11-30 12:01:02 +00:00
* tipc_send_buf2port - send message buffer to port identity
2006-01-02 19:04:38 +01:00
*/
2010-11-30 12:01:02 +00:00
int tipc_send_buf2port ( u32 ref , struct tipc_portid const * dest ,
struct sk_buff * buf , unsigned int dsz )
2006-01-02 19:04:38 +01:00
{
struct port * p_ptr ;
struct tipc_msg * msg ;
int res ;
2006-01-18 00:38:21 +01:00
p_ptr = ( struct port * ) tipc_ref_deref ( ref ) ;
2006-01-02 19:04:38 +01:00
if ( ! p_ptr | | p_ptr - > publ . connected )
return - EINVAL ;
msg = & p_ptr - > publ . phdr ;
msg_set_type ( msg , TIPC_DIRECT_MSG ) ;
2010-11-30 12:01:02 +00:00
msg_set_orignode ( msg , tipc_own_addr ) ;
msg_set_origport ( msg , ref ) ;
2006-01-02 19:04:38 +01:00
msg_set_destnode ( msg , dest - > node ) ;
msg_set_destport ( msg , dest - > ref ) ;
msg_set_hdr_sz ( msg , DIR_MSG_H_SIZE ) ;
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 11:55:19 -03:00
skb_copy_to_linear_data ( buf , msg , DIR_MSG_H_SIZE ) ;
2006-01-02 19:04:38 +01:00
p_ptr - > sent + + ;
if ( dest - > node = = tipc_own_addr )
2006-01-18 00:38:21 +01:00
return tipc_port_recv_msg ( buf ) ;
2006-01-02 19:04:38 +01:00
res = tipc_send_buf_fast ( buf , dest - > node ) ;
if ( likely ( res ! = - ELINKCONG ) )
return res ;
if ( port_unreliable ( p_ptr ) )
return dsz ;
return - ELINKCONG ;
}