libsua/sualibrary/sua/sua_cl.cpp

727 lines
24 KiB
C++

/***************************************************************************
sua_cl.cpp - description
-------------------
begin : Tue Jan 8 2002
copyright : (C) 2002 by Lode Coene
email : lode.coene@siemens.atea.be
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/*
* $Id: sua_cl.cpp,v 1.3 2002/03/01 12:57:38 p82609 Exp $
*
* SUA implementation according to SUA draft issue 6.
*
* Author(s): Lode Coene
*
*
* Copyright (C) 2001 by Siemens Atea, Herentals, Belgium.
*
* Realized in co-operation between Siemens Atea and
* Siemens AG, Munich, Germany.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Contact: gery.verwimp@siemens.atea.be
* lode.coene@siemens.atea.be
*
* The alternative comment
* inspiration : Dorothee
* "Always admire the local beauties in their natural enviroment."
*
* Purpose: This code-file defines the SUA connectionless message handling:
* - send a SUA message(CL or CO) to SCTP
* - route a SUA message(CL or CO)
* - send a Unitdata msg to remote node
* (- send a Unitdata Service msg to remote node)
* - Process a Unitdata msg
* (- Process a Unitdata Service msg)
*/
#include "sua_debug.h"
#include "sua_syntax.h"
#include "sua_database.h"
#include "sua_logging.h"
#include "sua_distribution.h"
#include "sua_tcb.h"
#ifdef LINUX
#include <unistd.h>
#endif
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
#include <netinet/in_systm.h>
#include <netinet/ip.h> /* includes <netinet/in.h> also ! */
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <arpa/inet.h>
using namespace std;
// import the dataobjects of SUA
extern db_Sua_LocalList local_sua;
extern db_Sua_RemoteList remote_sua;
extern db_Sua_AssociationList Assoc_sua;
extern tcb_Sua_msgqueue_pool msg_store;
// import the received msg pool
extern vector<sua_save_str> rec_msg_pool;
/***********************************************************************/
/* sua_send_Message */
/***********************************************************************/
int sua_send_Message( signed int sctp_assoc_id,
short int sctp_stream_id,
int sctp_delivery_type,
unsigned int sctp_loadshare,
char *databuf,
unsigned int datalen
)
{
signed int result;
/* send data to SCTP */
/* yes it does, continue, no problem, send the msg */
#ifdef DEBUG
/* display byte array */
display_byte_array(databuf , datalen);
#endif
char logstring[100];
sprintf(logstring, "SUA encoded message, ready for being send to SCTP assoc %d", sctp_assoc_id);
event_log("sua_cl.c",logstring);
log_byte_array("sua_cl.c", databuf,datalen);
result = sctp_send ( sctp_assoc_id,
sctp_stream_id,
(unsigned char *) databuf,
datalen,
SUA_PPI,
SCTP_USE_PRIMARY, /* replace in future with sctp_loadshare*/
SCTP_NO_CONTEXT,
SCTP_INFINITE_LIFETIME,
sctp_delivery_type,
SCTP_BUNDLING_DISABLED
);
#ifdef DEBUG
cout << "sua_cl.c:result sctp send = "<< result << "\n";
printf( "%d \n", result);
#endif
return(result);
}
/***********************************************************************/
/* sua_route_Message */
/***********************************************************************/
int sua_route_Message( unsigned int sctp_assoc_id,
unsigned int local_sua_id,
Sua_container &msg,
sccp_addr_str &called_pty_address,
sccp_addr_str &calling_pty_address
)
{
int result = 0;
short int sctp_stream_id = 0;
int sctp_delivery_type = SCTP_UNORDERED_DELIVERY;
signed int sctp_loadshare = SCTP_USE_PRIMARY;
int sua_assoc_id = 0;
int datalen = 0;
Sua_syntax_error_struct error;
// call routing to figure out which association to take for sending
// out the message
#ifdef DEBUG
cout << "call routing function\n";
#endif
sctp_assoc_id = Assoc_sua.route_msg( called_pty_address,
calling_pty_address,
sua_assoc_id
);
#ifdef DEBUG
cout << "routed to SCTP assoc " << sctp_assoc_id << "/SUA assoc id " << sua_assoc_id <<"\n";
#endif
/* does association exist? */
if (sctp_assoc_id > 0)
{
/* YES, encode the SUA unitdata message and ... */
error = msg.sua_encode();
/* figure out SCTP delivery type, stream to send msg on,...and.. */
if (msg.sua_prim.prot_class_pres)
{
switch(msg.sua_prim.prot_class.pcl)
{
case(prot_class_0): /* connectionless transport, non sequenced */
sctp_delivery_type = SCTP_UNORDERED_DELIVERY;
break;
case(prot_class_1): /* connectionless transport, sequenced */
sctp_delivery_type = SCTP_ORDERED_DELIVERY;
break;
case(prot_class_2): /* connection-oriented transport, ... */
sctp_delivery_type = SCTP_ORDERED_DELIVERY;
break;
case(prot_class_3): /* connection-oriented transport, ... */
sctp_delivery_type = SCTP_ORDERED_DELIVERY;
break;
default:
sctp_delivery_type = SCTP_UNORDERED_DELIVERY;
break;
}
sctp_stream_id = Assoc_sua.instance[sua_assoc_id].nr_of_outbound_streams;
sctp_stream_id = 0;
}
else
{
sctp_stream_id = 0;
}
/* copy data into buffer, then finally... */
char* databuf = new char[msg.sua_msg.length()];
msg.sua_msg.copy(databuf, msg.sua_msg.length());
datalen = msg.sua_msg.length();
// send data to SCTP
result = sua_send_Message( sctp_assoc_id,
sctp_stream_id,
sctp_delivery_type,
sctp_loadshare,
databuf,
datalen
);
delete databuf;
#ifdef DEBUG
cout.setf(ios::internal);
cout << "sua_cl.c:result sua send = "<< result << "\n";
#endif
}
else if (sctp_assoc_id < 0)
{
/* NOPE, message is routable, but destination is blocked */
/* due to administration or management descisions */
#ifdef DEBUG
cout << "sua_cl.c:sending msg prohibited \n";
#endif
result = -1;
}
else
{
/* NOPE message is NOT routable, destination not found. */
/* drop the message, no route present for that address */
result = 0;
}
return(result);
}
/***********************************************************************/
/* sua_send_Unitdata */
/***********************************************************************/
int sua_send_Unitdata ( sccp_QOS_str &QOS,
sccp_addr_str &called_pty_address,
sccp_addr_str &calling_pty_address,
char *buffer,
unsigned int len
)
{
Sua_container msg;
Sua_syntax_error_struct error;
int error_value = 0;
int string_size, datalen;
signed int sctp_assoc_id;
int sua_assoc_id;
short sctp_stream_id = 0;
signed int sctp_loadshare = SCTP_USE_PRIMARY;
int sctp_delivery_type, result;
tcb_Sua_msg_elem sua_msg;
// init the message
msg.sua_init();
// fill in the main sua header
msg.sua_prim.hdr_msg_class = sua_cl;
msg.sua_prim.hdr_msg_type.cl = cl_data_transfer;
msg.sua_prim.rout_con_pres = TRUE;
msg.sua_prim.rout_con = 1;
msg.sua_prim.importance_pres = TRUE;
msg.sua_prim.importance = 5;
msg.sua_prim.hop_count_pres = TRUE;
msg.sua_prim.hop_count = 15;
// QOS choice
switch (QOS.prot_class)
{
case(class0): // connectionless transport, non-sequenced
msg.sua_prim.prot_class_pres = TRUE;
msg.sua_prim.prot_class.pcl = prot_class_0;
msg.sua_prim.seq_control_pres = TRUE;
msg.sua_prim.seq_control = QOS.sequence_number;
sctp_delivery_type = SCTP_UNORDERED_DELIVERY;
break;
case(class1):
msg.sua_prim.prot_class_pres = TRUE;
msg.sua_prim.prot_class.pcl = prot_class_1;
msg.sua_prim.seq_control_pres = TRUE;
msg.sua_prim.seq_control = QOS.sequence_number;
sctp_delivery_type = SCTP_ORDERED_DELIVERY;
break;
default:
return(PROTOCOL_CLASS_NOT_SPECIFIED);
break;
}
if (QOS.return_msg_on_error)
msg.sua_prim.prot_class.return_option = TRUE;
else
msg.sua_prim.prot_class.return_option = FALSE;
// fill in the source address (=local sua address/CLG)
switch (calling_pty_address.routing_ind)
{
case (route_on_ssn):
if (calling_pty_address.address_fields_present.pc == ipvx_pc_present)
{
msg.sua_prim.source_addr.ip_addr_pres = TRUE;
msg.sua_prim.source_addr.pc_pres = FALSE;
if (calling_pty_address.pc.ipvx.sa.sa_family == AF_INET)
{
msg.sua_prim.source_addr.ip_addr_type = ip_v4;
msg.sua_prim.source_addr.ip_addr.ipv4 = calling_pty_address.pc.ipvx.sin;
}
else if (calling_pty_address.pc.ipvx.sa.sa_family == AF_INET6)
{
msg.sua_prim.source_addr.ip_addr_type = ip_v6;
msg.sua_prim.source_addr.ip_addr.ipv6 = calling_pty_address.pc.ipvx.sin6;
}
else
cout << "error filling in CLG IP address \n";
msg.sua_prim.source_addr_pres = TRUE;
msg.sua_prim.source_addr.rout_ind = ri_route_IP_SSN;
msg.sua_prim.source_addr.ssn_incl = TRUE;
msg.sua_prim.source_addr.pc_incl = FALSE;
msg.sua_prim.source_addr.gt_incl = FALSE;
msg.sua_prim.source_addr.ssn = calling_pty_address.ssn;
}
else if (calling_pty_address.address_fields_present.pc == ss7_pc_present)
{
msg.sua_prim.source_addr_pres = TRUE;
msg.sua_prim.source_addr.ip_addr_pres = FALSE;
msg.sua_prim.source_addr.pc_pres = TRUE;
msg.sua_prim.source_addr.pc = calling_pty_address.pc.ss7.ITU24.pc;
msg.sua_prim.source_addr.rout_ind = ri_route_PC_SSN;
msg.sua_prim.source_addr.ssn_incl = TRUE;
msg.sua_prim.source_addr.pc_incl = TRUE;
msg.sua_prim.source_addr.gt_incl = FALSE;
msg.sua_prim.source_addr.ssn = calling_pty_address.ssn;
cout << "SS7 PC in CLG address \n";
}
else
cout << "unsupported CLG address option\n";
break;
case(route_on_name_gt):
msg.sua_prim.source_addr.ip_addr_pres = FALSE;
msg.sua_prim.source_addr.pc_pres = FALSE;
msg.sua_prim.source_addr.hostname_pres = TRUE;
msg.sua_prim.source_addr.hostname = calling_pty_address.name.HostName;
msg.sua_prim.source_addr_pres = TRUE;
msg.sua_prim.source_addr.rout_ind = ri_route_hostname;
msg.sua_prim.source_addr.ssn_incl = TRUE;
msg.sua_prim.source_addr.pc_incl = FALSE;
msg.sua_prim.source_addr.gt_incl = TRUE;
msg.sua_prim.source_addr.ssn = called_pty_address.ssn;
break;
case(route_on_name_gt_next_office):
break;
default:
return(INVALID_CLG_ADDRESS);
break;
}
// fill in the destination address(=remote sua address/CLD)
switch (called_pty_address.routing_ind)
{
case (route_on_ssn):
if (called_pty_address.address_fields_present.pc == ipvx_pc_present)
{
msg.sua_prim.dest_addr.ip_addr_pres = TRUE;
msg.sua_prim.dest_addr.pc_pres = FALSE;
if (called_pty_address.pc.ipvx.sa.sa_family == AF_INET)
{
msg.sua_prim.dest_addr.ip_addr_type = ip_v4;
msg.sua_prim.dest_addr.ip_addr.ipv4 = called_pty_address.pc.ipvx.sin;
}
else if (called_pty_address.pc.ipvx.sa.sa_family == AF_INET6)
{
msg.sua_prim.dest_addr.ip_addr_type = ip_v6;
msg.sua_prim.dest_addr.ip_addr.ipv6 = called_pty_address.pc.ipvx.sin6;
}
else
cout << "error filling in CLD IP address \n";
msg.sua_prim.dest_addr_pres = TRUE;
msg.sua_prim.dest_addr.rout_ind = ri_route_IP_SSN;
msg.sua_prim.dest_addr.ssn_incl = TRUE;
msg.sua_prim.dest_addr.pc_incl = FALSE;
msg.sua_prim.dest_addr.gt_incl = FALSE;
msg.sua_prim.dest_addr.ssn = called_pty_address.ssn;
}
else if (called_pty_address.address_fields_present.pc == ss7_pc_present)
{
msg.sua_prim.dest_addr_pres = TRUE;
msg.sua_prim.dest_addr.ip_addr_pres = FALSE;
msg.sua_prim.dest_addr.pc_pres = TRUE;
msg.sua_prim.dest_addr.pc = called_pty_address.pc.ss7.ITU24.pc;
msg.sua_prim.dest_addr.rout_ind = ri_route_PC_SSN;
msg.sua_prim.dest_addr.ssn_incl = TRUE;
msg.sua_prim.dest_addr.pc_incl = TRUE;
msg.sua_prim.dest_addr.gt_incl = FALSE;
msg.sua_prim.dest_addr.ssn = called_pty_address.ssn;
cout << "SS7 PC in CLD address \n";
}
else
cout << "unsupported CLD address option\n";
break;
case(route_on_name_gt):
msg.sua_prim.dest_addr.ip_addr_pres = FALSE;
msg.sua_prim.dest_addr.hostname_pres = TRUE;
msg.sua_prim.dest_addr.pc_pres = FALSE;
msg.sua_prim.dest_addr.hostname = called_pty_address.name.HostName;
msg.sua_prim.dest_addr_pres = TRUE;
msg.sua_prim.dest_addr.rout_ind = ri_route_hostname;
msg.sua_prim.dest_addr.ssn_incl = TRUE;
msg.sua_prim.dest_addr.pc_incl = FALSE;
msg.sua_prim.dest_addr.gt_incl = TRUE;
msg.sua_prim.dest_addr.ssn = called_pty_address.ssn;
break;
case(route_on_name_gt_next_office):
break;
default:
return(INVALID_CLD_ADDRESS);
break;
}
// fill in the user data
msg.sua_prim.data_pres = TRUE;
string stemp(buffer,len);
msg.sua_prim.data_string = stemp;
// encode the SUA unitdata message
error = msg.sua_encode();
string_size = msg.sua_msg.size();
// call routing to figure out which association to take for sending
// out the message
#ifdef DEBUG
cout << "call routing function\n";
#endif
sctp_assoc_id = Assoc_sua.route_msg( called_pty_address,
calling_pty_address,
sua_assoc_id
);
#ifdef DEBUG
cout << "routed to SCTP assoc " << sctp_assoc_id << "\n";
#endif
/* does association exist? */
if (sctp_assoc_id > 0)
{
/* copy data into buffer, then finally... */
char* databuf = new char[msg.sua_msg.length()];
msg.sua_msg.copy(databuf, msg.sua_msg.length());
datalen = msg.sua_msg.length();
// send data to SCTP
result = sua_send_Message( sctp_assoc_id,
sctp_stream_id,
sctp_delivery_type,
sctp_loadshare,
databuf,
datalen
);
delete databuf;
#ifdef DEBUG
cout << "sua_cl.c:result sctp send = "<< result << "\n";
#endif
error_value = 0;
}
else if (sctp_assoc_id < 0)
{
#ifdef DEBUG
cout << "sua_cl.c:sending msg prohibited \n";
#endif
error_value = -1;
}
else
{
/* NO it does NOT exist. */
/* - Try to set up the association */
sua_assoc_id = Assoc_sua.Dynamic_Associate ( local_sua,
remote_sua,
called_pty_address,
calling_pty_address,
1,
1,
1
);
/* - save the msg till the association is setup or */
/* association setup fails -> drop saved msg */
sua_msg.byte = msg.sua_msg;
sua_msg.delivery_type = sctp_delivery_type;
sua_msg.stream_id = sctp_stream_id;
sua_msg.valid = true;
msg_store.add_msg ( sua_assoc_id,
sua_msg
);
error_value = -1;
}
return(error_value);
}
/***********************************************************************/
/* SUA receive a connectionless message */
/***********************************************************************/
/***********************************************************************/
/* sua_process_unitdata */
/***********************************************************************/
short process_unitdata_msg ( int local_sua_id,
unsigned int sua_assoc_id,
Sua_container &msg
)
{
sua_save_str temp;
int result = 0;
int sctp_assoc_id = 0;
temp.primitive = N_UNITDATA;
temp.user_ref = 0;
if (msg.sua_prim.prot_class_pres)
{
// QOS choice
switch ( msg.sua_prim.prot_class.pcl)
{
case(prot_class_0): // connectionless transport, non-sequenced
temp.QOS.prot_class = class0;
temp.QOS.in_sequence = false;
break;
case(prot_class_1):
temp.QOS.prot_class = class1;
temp.QOS.in_sequence = true;
break;
default:
return(PROTOCOL_CLASS_NOT_SPECIFIED);
break;
}
temp.QOS.return_msg_on_error = (msg.sua_prim.prot_class.return_option == TRUE);
}
temp.QOS.sequence_number = 0;
temp.QOS.importance = msg.sua_prim.importance;
// retrieve the clg(=source) address (=remote sua address)
// which types are present in the address(ip pc, SS7 pc, GT, hostname)
if (msg.sua_prim.source_addr.ip_addr_pres == TRUE)
{
temp.calling_pty_address.address_fields_present.pc = ipvx_pc_present;
if (msg.sua_prim.source_addr.ip_addr_type == ip_v4) {
temp.calling_pty_address.pc.ipvx.sin = msg.sua_prim.source_addr.ip_addr.ipv4;
temp.calling_pty_address.pc.ipvx.sa.sa_family = AF_INET;
temp.calling_pty_address.pc.ipvx.sin.sin_port = Assoc_sua.instance[sua_assoc_id].Dest.addrs[0].sin.sin_port;
}
else if (msg.sua_prim.source_addr.ip_addr_type == ip_v6) {
temp.calling_pty_address.pc.ipvx.sin6 = msg.sua_prim.source_addr.ip_addr.ipv6;
temp.calling_pty_address.pc.ipvx.sa.sa_family = AF_INET6;
temp.calling_pty_address.pc.ipvx.sin6.sin6_port = Assoc_sua.instance[sua_assoc_id].Dest.addrs[0].sin.sin_port;
}
else
cout << "Unknown IP address format\n";
}
if (msg.sua_prim.source_addr.pc_pres == TRUE)
{
temp.calling_pty_address.address_fields_present.pc = ss7_pc_present;
temp.calling_pty_address.pc.ss7.ITU24.family = Assoc_sua.instance[sua_assoc_id].Dest.pc.ITU14.family;
temp.calling_pty_address.pc.ss7.ITU24.pc = msg.sua_prim.source_addr.pc;
}
if (msg.sua_prim.source_addr.gt_pres == TRUE)
{
cout << "Global Title : unsupported address format\n";
}
if (msg.sua_prim.source_addr.hostname_pres == TRUE)
{
temp.calling_pty_address.address_fields_present.name_gt = hostname_present;
msg.sua_prim.source_addr.hostname.copy( temp.calling_pty_address.name.HostName,
(msg.sua_prim.source_addr.hostname.length()+1 )
);
temp.calling_pty_address.name.HostName[msg.sua_prim.source_addr.hostname.length()] = '\0';
}
if ((msg.sua_prim.source_addr.ip_addr_pres /= TRUE) &&
(msg.sua_prim.source_addr.pc_pres /= TRUE) &&
(msg.sua_prim.source_addr.gt_pres /= TRUE) &&
(msg.sua_prim.source_addr.hostname_pres /= TRUE))
{
cout << "No valid address format found in msg\n";
}
// routing indicator
switch (msg.sua_prim.source_addr.rout_ind)
{
case(ri_route_PC_SSN):
temp.calling_pty_address.routing_ind = route_on_ssn;
break;
case(ri_route_IP_SSN):
temp.calling_pty_address.routing_ind = route_on_ssn;
break;
case (ri_route_GT):
temp.calling_pty_address.routing_ind = route_on_name_gt;
break;
case (ri_route_hostname):
temp.calling_pty_address.routing_ind = route_on_name_gt;
break;
default:
break;
}
temp.calling_pty_address.address_fields_present.ssn_port = ssn_present;
temp.calling_pty_address.ssn = msg.sua_prim.source_addr.ssn;
// retrieve the called(=destination) address(=should be our own local addr)
// not completely done yet
if (msg.sua_prim.dest_addr.ip_addr_pres == TRUE)
{
temp.called_pty_address.address_fields_present.pc = ipvx_pc_present;
if (msg.sua_prim.dest_addr.ip_addr_type == ip_v4) {
temp.called_pty_address.pc.ipvx.sin = msg.sua_prim.dest_addr.ip_addr.ipv4;
temp.called_pty_address.pc.ipvx.sa.sa_family = AF_INET;
temp.called_pty_address.pc.ipvx.sin.sin_port = Assoc_sua.instance[sua_assoc_id].Dest.addrs[0].sin.sin_port;
}
else if (msg.sua_prim.dest_addr.ip_addr_type == ip_v6) {
temp.called_pty_address.pc.ipvx.sin6 = msg.sua_prim.dest_addr.ip_addr.ipv6;
temp.called_pty_address.pc.ipvx.sa.sa_family = AF_INET6;
temp.called_pty_address.pc.ipvx.sin6.sin6_port = Assoc_sua.instance[sua_assoc_id].Dest.addrs[0].sin.sin_port;
}
}
if (msg.sua_prim.dest_addr.pc_pres == TRUE)
{
temp.called_pty_address.address_fields_present.pc = ss7_pc_present;
temp.called_pty_address.pc.ss7.ITU24.family = Assoc_sua.instance[sua_assoc_id].Dest.pc.ITU14.family;
temp.called_pty_address.pc.ss7.ITU24.pc = msg.sua_prim.dest_addr.pc;
}
if (msg.sua_prim.dest_addr.hostname_pres == TRUE)
{
temp.called_pty_address.address_fields_present.name_gt = hostname_present;
msg.sua_prim.dest_addr.hostname.copy( temp.called_pty_address.name.HostName,
(msg.sua_prim.dest_addr.hostname.length()+1 )
);
temp.called_pty_address.name.HostName[msg.sua_prim.dest_addr.hostname.length()] = '\0';
}
// routing indicator
switch (msg.sua_prim.dest_addr.rout_ind)
{
case(ri_route_PC_SSN):
temp.called_pty_address.routing_ind = route_on_ssn;
break;
case(ri_route_IP_SSN):
temp.called_pty_address.routing_ind = route_on_ssn;
break;
case (ri_route_GT):
temp.called_pty_address.routing_ind = route_on_name_gt;
break;
case (ri_route_hostname):
temp.called_pty_address.routing_ind = route_on_name_gt;
break;
default:
break;
}
temp.called_pty_address.address_fields_present.ssn_port = ssn_present;
temp.called_pty_address.ssn = msg.sua_prim.dest_addr.ssn;
if (msg.sua_prim.data_pres == TRUE)
temp.userdata = msg.sua_prim.data_string;
else
cout << "sua_cl.c: no sua user data in unitdata msg \n";
/* Is this the final destination ? */
if ( Assoc_sua.Find_local_sua ( temp.called_pty_address) > 0 )
{
/* Yes, message has arrived at its final destination -> send to upper layer */
/* store primitive in a list(is retrieve via sua_receive_msg) */
rec_msg_pool.push_back(temp);
/* call the application/user callBack function */
local_sua.instance[local_sua_id].SUA_APLCallBack.ulp_ClDataIndNotif
( local_sua_id,
N_UNITDATA,
temp.userdata.length()
);
}
else
{
/* No, Message has not arrived at its final destination -> */
/* route it to the next SUA node via an SCTP association nr x */
result = sua_route_Message( sctp_assoc_id,
local_sua_id,
msg,
temp.called_pty_address,
temp.calling_pty_address
);
}
return(0);
}
// end of module sua_cl.c