/*************************************************************************** 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.1.1.1 2002/02/04 14:30:41 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 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 #endif #include #include #include #include #include #include #include /* includes also ! */ #include #include #include 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 rec_msg_pool; /***********************************************************************/ /* 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; int string_size, datalen; signed int sctp_assoc_id; unsigned int sua_assoc_id; short stream_id = 0; int 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; 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; 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 ); #ifdef DEBUG cout << "routed to SCTP assoc " << sctp_assoc_id << "\n"; #endif /* does association exist? */ if (sctp_assoc_id > 0) { // send data to SCTP char* databuf = new char[msg.sua_msg.length()]; msg.sua_msg.copy(databuf, msg.sua_msg.length()); datalen = msg.sua_msg.length(); /* yes it does, continue, no problem, send the msg */ #ifdef DEBUG // display byte array display_byte_array(databuf , msg.sua_msg.length()); #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,msg.sua_msg.length()); result = sctp_send ( sctp_assoc_id, stream_id, (unsigned char *) databuf, datalen, SUA_PPI, SCTP_USE_PRIMARY, SCTP_NO_CONTEXT, SCTP_INFINITE_LIFETIME, delivery_type, SCTP_BUNDLING_DISABLED ); error_value = result; delete databuf; #ifdef DEBUG cout << "sua_cl.c:result sctp send = "<< result << "\n"; #endif } 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 = delivery_type; sua_msg.stream_id = 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; 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 = ITU24bit; 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.pc_pres == TRUE) { temp.called_pty_address.address_fields_present.pc = ss7_pc_present; temp.called_pty_address.pc.ss7.ITU24.family = ITU24bit; temp.called_pty_address.pc.ss7.ITU24.pc = msg.sua_prim.source_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"; // 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() ); return(0); } // end of module sua_cl.c