diff --git a/openbsc/configure.in b/openbsc/configure.in index 50189a4aa..b877e6b84 100644 --- a/openbsc/configure.in +++ b/openbsc/configure.in @@ -22,6 +22,27 @@ AC_SEARCH_LIBS(gtp_new, gtp, AM_CONDITIONAL(HAVE_LIBGTP, test "x$GPRS_LIBGTP" != "x") + +AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Requires SCCP])], + [ + PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp) + osmo_ac_build_nat="yes" + ], + [ + osmo_ac_build_nat="no" + ]) +AM_CONDITIONAL(BUILD_NAT, test "x$osmo_ac_build_nat" = "xyes") + +AC_ARG_ENABLE([osmo-bsc], [AS_HELP_STRING([--enable-bsc], [Build the Osmo BSC])], + [ + PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp) + osmo_ac_build_bsc="yes" + ], + [ + osmo_ac_build_bsc="no" + ]) +AM_CONDITIONAL(BUILD_BSC, test "x$osmo_ac_build_bsc" = "xyes") + PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.15) PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.1.9) @@ -47,9 +68,7 @@ AM_CONFIG_HEADER(bscconfig.h) AC_OUTPUT( openbsc.pc - libsccp.pc include/openbsc/Makefile - include/sccp/Makefile include/Makefile src/Makefile src/ipaccess/Makefile @@ -61,6 +80,5 @@ AC_OUTPUT( tests/gsm0408/Makefile tests/db/Makefile tests/channel/Makefile - tests/sccp/Makefile tests/bsc-nat/Makefile Makefile) diff --git a/openbsc/include/Makefile.am b/openbsc/include/Makefile.am index a4acc23b2..4596b6e3c 100644 --- a/openbsc/include/Makefile.am +++ b/openbsc/include/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = openbsc sccp +SUBDIRS = openbsc noinst_HEADERS = mISDNif.h compat_af_isdn.h diff --git a/openbsc/include/sccp/Makefile.am b/openbsc/include/sccp/Makefile.am deleted file mode 100644 index 6c8a51714..000000000 --- a/openbsc/include/sccp/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -sccp_HEADERS = sccp_types.h sccp.h -sccpdir = $(includedir)/sccp diff --git a/openbsc/include/sccp/sccp.h b/openbsc/include/sccp/sccp.h deleted file mode 100644 index a0cdf0bae..000000000 --- a/openbsc/include/sccp/sccp.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SCCP management code - * - * (C) 2009, 2010 by Holger Hans Peter Freyther - * - * All Rights Reserved - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#ifndef SCCP_H -#define SCCP_H - -#include - -#include -#include - -#include "sccp_types.h" - -struct msgb; -struct sccp_system; - -enum { - SCCP_CONNECTION_STATE_NONE, - SCCP_CONNECTION_STATE_REQUEST, - SCCP_CONNECTION_STATE_CONFIRM, - SCCP_CONNECTION_STATE_ESTABLISHED, - SCCP_CONNECTION_STATE_RELEASE, - SCCP_CONNECTION_STATE_RELEASE_COMPLETE, - SCCP_CONNECTION_STATE_REFUSED, - SCCP_CONNECTION_STATE_SETUP_ERROR, -}; - -struct sockaddr_sccp { - sa_family_t sccp_family; /* AF_SCCP in the future??? */ - uint8_t sccp_ssn; /* subssystem number for routing */ - - /* TODO fill in address indicator... if that is ever needed */ - - /* not sure about these */ - /* uint8_t sccp_class; */ -}; - -/* - * parsed structure of an address - */ -struct sccp_address { - struct sccp_called_party_address address; - uint8_t ssn; - uint8_t poi[2]; -}; - -struct sccp_optional_data { - uint8_t data_len; - uint8_t data_start; -}; - -struct sccp_connection { - /* public */ - void *data_ctx; - void (*data_cb)(struct sccp_connection *conn, struct msgb *msg, unsigned int len); - - void *state_ctx; - void (*state_cb)(struct sccp_connection *, int old_state); - - struct sccp_source_reference source_local_reference; - struct sccp_source_reference destination_local_reference; - - int connection_state; - - /* private */ - /* list of active connections */ - struct llist_head list; - struct sccp_system *system; - int incoming; -}; - -/** - * system functionality to implement on top of any other transport layer: - * call sccp_system_incoming for incoming data (from the network) - * sccp will call outgoing whenever outgoing data exists - */ -int sccp_system_init(void (*outgoing)(struct msgb *data, void *ctx), void *context); -int sccp_system_incoming(struct msgb *data); - -/** - * Send data on an existing connection - */ -int sccp_connection_write(struct sccp_connection *connection, struct msgb *data); -int sccp_connection_send_it(struct sccp_connection *connection); -int sccp_connection_close(struct sccp_connection *connection, int cause); -int sccp_connection_free(struct sccp_connection *connection); - -/** - * internal.. - */ -int sccp_connection_force_free(struct sccp_connection *conn); - -/** - * Create a new socket. Set your callbacks and then call bind to open - * the connection. - */ -struct sccp_connection *sccp_connection_socket(void); - -/** - * Open the connection and send additional data - */ -int sccp_connection_connect(struct sccp_connection *conn, - const struct sockaddr_sccp *sccp_called, - struct msgb *data); - -/** - * mostly for testing purposes only. Set the accept callback. - * TODO: add true routing information... in analogy to socket, bind, accept - */ -int sccp_connection_set_incoming(const struct sockaddr_sccp *sock, - int (*accept_cb)(struct sccp_connection *connection, void *data), - void *user_data); - -/** - * Send data in terms of unit data. A fixed address indicator will be used. - */ -int sccp_write(struct msgb *data, - const struct sockaddr_sccp *sock_sender, - const struct sockaddr_sccp *sock_target, int class); -int sccp_set_read(const struct sockaddr_sccp *sock, - int (*read_cb)(struct msgb *msgb, unsigned int, void *user_data), - void *user_data); - -/* generic sock addresses */ -extern const struct sockaddr_sccp sccp_ssn_bssap; - -/* helpers */ -uint32_t sccp_src_ref_to_int(struct sccp_source_reference *ref); -struct sccp_source_reference sccp_src_ref_from_int(uint32_t); - -struct msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *data, int length); -struct msgb *sccp_create_cc(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref); -struct msgb *sccp_create_rlsd(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref, int cause); -struct msgb *sccp_create_dt1(struct sccp_source_reference *dst_ref, uint8_t *data, uint8_t len); - -/** - * Below this are helper functions and structs for parsing SCCP messages - */ -struct sccp_parse_result { - struct sccp_address called; - struct sccp_address calling; - - /* point to the msg packet */ - struct sccp_source_reference *source_local_reference; - struct sccp_source_reference *destination_local_reference; - - /* data pointer */ - int data_len; -}; - -/* - * helper functions for the nat code - */ -int sccp_determine_msg_type(struct msgb *msg); -int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result); - -#endif diff --git a/openbsc/include/sccp/sccp_types.h b/openbsc/include/sccp/sccp_types.h deleted file mode 100644 index 4b1406495..000000000 --- a/openbsc/include/sccp/sccp_types.h +++ /dev/null @@ -1,420 +0,0 @@ -/* - * ITU Q.713 defined types for SCCP - * - * (C) 2009 by Holger Hans Peter Freyther - * - * All Rights Reserved - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#ifndef SCCP_TYPES_H -#define SCCP_TYPES_H - -#include - -/* Table 1/Q.713 - SCCP message types */ -enum sccp_message_types { - SCCP_MSG_TYPE_CR = 1, - SCCP_MSG_TYPE_CC = 2, - SCCP_MSG_TYPE_CREF = 3, - SCCP_MSG_TYPE_RLSD = 4, - SCCP_MSG_TYPE_RLC = 5, - SCCP_MSG_TYPE_DT1 = 6, - SCCP_MSG_TYPE_DT2 = 7, - SCCP_MSG_TYPE_AK = 8, - SCCP_MSG_TYPE_UDT = 9, - SCCP_MSG_TYPE_UDTS = 10, - SCCP_MSG_TYPE_ED = 11, - SCCP_MSG_TYPE_EA = 12, - SCCP_MSG_TYPE_RSR = 13, - SCCP_MSG_TYPE_RSC = 14, - SCCP_MSG_TYPE_ERR = 15, - SCCP_MSG_TYPE_IT = 16, - SCCP_MSG_TYPE_XUDT = 17, - SCCP_MSG_TYPE_XUDTS = 18, - SCCP_MSG_TYPE_LUDT = 19, - SCCP_MSG_TYPE_LUDTS = 20 -}; - -/* Table 2/Q.713 - SCCP parameter name codes */ -enum sccp_parameter_name_codes { - SCCP_PNC_END_OF_OPTIONAL = 0, - SCCP_PNC_DESTINATION_LOCAL_REFERENCE = 1, - SCCP_PNC_SOURCE_LOCAL_REFERENCE = 2, - SCCP_PNC_CALLED_PARTY_ADDRESS = 3, - SCCP_PNC_CALLING_PARTY_ADDRESS = 4, - SCCP_PNC_PROTOCOL_CLASS = 5, - SCCP_PNC_SEGMENTING = 6, - SCCP_PNC_RECEIVE_SEQ_NUMBER = 7, - SCCP_PNC_SEQUENCING = 8, - SCCP_PNC_CREDIT = 9, - SCCP_PNC_RELEASE_CAUSE = 10, - SCCP_PNC_RETURN_CAUSE = 11, - SCCP_PNC_RESET_CAUSE = 12, - SCCP_PNC_ERROR_CAUSE = 13, - SCCP_PNC_REFUSAL_CAUSE = 14, - SCCP_PNC_DATA = 15, - SCCP_PNC_SEGMENTATION = 16, - SCCP_PNC_HOP_COUNTER = 17, - SCCP_PNC_IMPORTANCE = 18, - SCCP_PNC_LONG_DATA = 19, -}; - -/* Figure 3/Q.713 Called/calling party address */ -enum { - SCCP_TITLE_IND_NONE = 0, - SCCP_TITLE_IND_NATURE_ONLY = 1, - SCCP_TITLE_IND_TRANSLATION_ONLY = 2, - SCCP_TITLE_IND_TRANS_NUM_ENC = 3, - SCCP_TITLE_IND_TRANS_NUM_ENC_NATURE = 4, -}; - -enum { - SCCP_CALL_ROUTE_ON_SSN = 1, - SCCP_CALL_ROUTE_ON_GT = 0, -}; - -struct sccp_called_party_address { -#if __BYTE_ORDER == __LITTLE_ENDIAN - uint8_t point_code_indicator : 1, - ssn_indicator : 1, - global_title_indicator : 4, - routing_indicator : 1, - reserved : 1; -#elif __BYTE_ORDER == __BIG_ENDIAN - uint8_t reserved : 1, - routing_indicator : 1, - global_title_indicator : 4, - ssn_indicator : 1, - point_code_indicator : 1; -#endif - uint8_t data[0]; -} __attribute__((packed)); - -/* indicator indicates presence in the above order */ - -/* Figure 6/Q.713 */ -struct sccp_signalling_point_code { - uint8_t lsb; -#if __BYTE_ORDER == __LITTLE_ENDIAN - uint8_t msb : 6, - reserved : 2; -#elif __BYTE_ORDER == __BIG_ENDIAN - uint8_t reserved : 2, - msb : 6; -#endif -} __attribute__((packed)); - -/* SSN == subsystem number */ -enum sccp_subsystem_number { - SCCP_SSN_NOT_KNOWN_OR_USED = 0, - SCCP_SSN_MANAGEMENT = 1, - SCCP_SSN_RESERVED_ITU = 2, - SCCP_SSN_ISDN_USER_PART = 3, - SCCP_SSN_OMAP = 4, /* operation, maint and administration part */ - SCCP_SSN_MAP = 5, /* mobile application part */ - SCCP_SSN_HLR = 6, - SCCP_SSN_VLR = 7, - SCCP_SSN_MSC = 8, - SCCP_SSN_EIC = 9, /* equipent identifier centre */ - SCCP_SSN_AUC = 10, /* authentication centre */ - SCCP_SSN_ISDN_SUPPL_SERVICES = 11, - SCCP_SSN_RESERVED_INTL = 12, - SCCP_SSN_ISDN_EDGE_TO_EDGE = 13, - SCCP_SSN_TC_TEST_RESPONDER = 14, - - /* From GSM 03.03 8.2 */ - SCCP_SSN_BSSAP = 254, - SCCP_SSN_BSSOM = 253, -}; - -/* Q.713, 3.4.2.3 */ -enum { - SCCP_NAI_UNKNOWN = 0, - SCCP_NAI_SUBSCRIBER_NUMBER = 1, - SCCP_NAI_RESERVED_NATIONAL = 2, - SCCP_NAI_NATIONAL_SIGNIFICANT = 3, - SCCP_NAI_INTERNATIONAL = 4, -}; - -struct sccp_global_title { -#if __BYTE_ORDER == __LITTLE_ENDIAN - uint8_t nature_of_addr_ind : 7, - odd_even : 1; -#elif __BYTE_ORDER == __BIG_ENDIAN - uint8_t odd_even : 1, - nature_of_addr_ind : 7; -#endif - uint8_t data[0]; -} __attribute__((packed)); - -/* Q.713, 3.3 */ -struct sccp_source_reference { - uint8_t octet1; - uint8_t octet2; - uint8_t octet3; -} __attribute__((packed)); - -/* Q.714, 3.6 */ -enum sccp_protocol_class { - SCCP_PROTOCOL_CLASS_0 = 0, - SCCP_PROTOCOL_CLASS_1 = 1, - SCCP_PROTOCOL_CLASS_2 = 2, - SCCP_PROTOCOL_CLASS_3 = 3, -}; - -/* bits 5-8 when class0, class1 is used */ -enum sccp_protocol_options { - SCCP_PROTOCOL_NO_SPECIAL = 0, - SCCP_PROTOCOL_RETURN_MESSAGE = 8, -}; - -enum sccp_release_cause { - SCCP_RELEASE_CAUSE_END_USER_ORIGINATED = 0, - SCCP_RELEASE_CAUSE_END_USER_CONGESTION = 1, - SCCP_RELEASE_CAUSE_END_USER_FAILURE = 2, - SCCP_RELEASE_CAUSE_SCCP_USER_ORIGINATED = 3, - SCCP_RELEASE_CAUSE_REMOTE_PROCEDURE_ERROR = 4, - SCCP_RELEASE_CAUSE_INCONSISTENT_CONN_DATA = 5, - SCCP_RELEASE_CAUSE_ACCESS_FAILURE = 6, - SCCP_RELEASE_CAUSE_ACCESS_CONGESTION = 7, - SCCP_RELEASE_CAUSE_SUBSYSTEM_FAILURE = 8, - SCCP_RELEASE_CAUSE_SUBSYSTEM_CONGESTION = 9, - SCCP_RELEASE_CAUSE_MTP_FAILURE = 10, - SCCP_RELEASE_CAUSE_NETWORK_CONGESTION = 11, - SCCP_RELEASE_CAUSE_EXPIRATION_RESET = 12, - SCCP_RELEASE_CAUSE_EXPIRATION_INACTIVE = 13, - SCCP_RELEASE_CAUSE_RESERVED = 14, - SCCP_RELEASE_CAUSE_UNQUALIFIED = 15, - SCCP_RELEASE_CAUSE_SCCP_FAILURE = 16, -}; - -enum sccp_return_cause { - SCCP_RETURN_CAUSE_NO_TRANSLATION_NATURE = 0, - SCCP_RETURN_CAUSE_NO_TRANSLATION = 1, - SCCP_RETURN_CAUSE_SUBSYSTEM_CONGESTION = 2, - SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE = 3, - SCCP_RETURN_CAUSE_UNEQUIPPED_USER = 4, - SCCP_RETURN_CAUSE_MTP_FAILURE = 5, - SCCP_RETURN_CAUSE_NETWORK_CONGESTION = 6, - SCCP_RETURN_CAUSE_UNQUALIFIED = 7, - SCCP_RETURN_CAUSE_ERROR_IN_MSG_TRANSPORT = 8, - SCCP_RETURN_CAUSE_ERROR_IN_LOCAL_PROCESSING = 9, - SCCP_RETURN_CAUSE_DEST_CANNOT_PERFORM_REASSEMBLY = 10, - SCCP_RETURN_CAUSE_SCCP_FAILURE = 11, - SCCP_RETURN_CAUSE_HOP_COUNTER_VIOLATION = 12, - SCCP_RETURN_CAUSE_SEGMENTATION_NOT_SUPPORTED= 13, - SCCP_RETURN_CAUSE_SEGMENTATION_FAOLURE = 14 -}; - -enum sccp_reset_cause { - SCCP_RESET_CAUSE_END_USER_ORIGINATED = 0, - SCCP_RESET_CAUSE_SCCP_USER_ORIGINATED = 1, - SCCP_RESET_CAUSE_MSG_OUT_OF_ORDER_PS = 2, - SCCP_RESET_CAUSE_MSG_OUT_OF_ORDER_PR = 3, - SCCP_RESET_CAUSE_RPC_OUT_OF_WINDOW = 4, - SCCP_RESET_CAUSE_RPC_INCORRECT_PS = 5, - SCCP_RESET_CAUSE_RPC_GENERAL = 6, - SCCP_RESET_CAUSE_REMOTE_END_USER_OPERATIONAL= 7, - SCCP_RESET_CAUSE_NETWORK_OPERATIONAL = 8, - SCCP_RESET_CAUSE_ACCESS_OPERATIONAL = 9, - SCCP_RESET_CAUSE_NETWORK_CONGESTION = 10, - SCCP_RESET_CAUSE_RESERVED = 11, -}; - -enum sccp_error_cause { - SCCP_ERROR_LRN_MISMATCH_UNASSIGNED = 0, /* local reference number */ - SCCP_ERROR_LRN_MISMATCH_INCONSISTENT = 1, - SCCP_ERROR_POINT_CODE_MISMATCH = 2, - SCCP_ERROR_SERVICE_CLASS_MISMATCH = 3, - SCCP_ERROR_UNQUALIFIED = 4, -}; - -enum sccp_refusal_cause { - SCCP_REFUSAL_END_USER_ORIGINATED = 0, - SCCP_REFUSAL_END_USER_CONGESTION = 1, - SCCP_REFUSAL_END_USER_FAILURE = 2, - SCCP_REFUSAL_SCCP_USER_ORIGINATED = 3, - SCCP_REFUSAL_DESTINATION_ADDRESS_UKNOWN = 4, - SCCP_REFUSAL_DESTINATION_INACCESSIBLE = 5, - SCCP_REFUSAL_NET_QOS_NON_TRANSIENT = 6, - SCCP_REFUSAL_NET_QOS_TRANSIENT = 7, - SCCP_REFUSAL_ACCESS_FAILURE = 8, - SCCP_REFUSAL_ACCESS_CONGESTION = 9, - SCCP_REFUSAL_SUBSYSTEM_FAILURE = 10, - SCCP_REFUSAL_SUBSYTEM_CONGESTION = 11, - SCCP_REFUSAL_EXPIRATION = 12, - SCCP_REFUSAL_INCOMPATIBLE_USER_DATA = 13, - SCCP_REFUSAL_RESERVED = 14, - SCCP_REFUSAL_UNQUALIFIED = 15, - SCCP_REFUSAL_HOP_COUNTER_VIOLATION = 16, - SCCP_REFUSAL_SCCP_FAILURE = 17, - SCCP_REFUSAL_UNEQUIPPED_USER = 18, -}; - -/* - * messages... as of Q.713 Chapter 4 - */ -struct sccp_connection_request { - /* mandantory */ - uint8_t type; - struct sccp_source_reference source_local_reference; - uint8_t proto_class; - - - /* variable */ - uint8_t variable_called; -#if VARIABLE - called_party_address -#endif - - /* optional */ - uint8_t optional_start; - -#if OPTIONAL - credit 3 - callingparty var 4-n - data 3-130 - hop_counter 3 - importance 3 - end_of_optional 1 -#endif - - uint8_t data[0]; -} __attribute__((packed)); - -struct sccp_connection_confirm { - /* mandantory */ - uint8_t type; - struct sccp_source_reference destination_local_reference; - struct sccp_source_reference source_local_reference; - uint8_t proto_class; - - /* optional */ - uint8_t optional_start; - - /* optional */ -#if OPTIONAL - credit 3 - called party 4 - data 3-130 - importance 3 - end_of_optional 1 -#endif - - uint8_t data[0]; -} __attribute__((packed)); - -struct sccp_connection_refused { - /* mandantory */ - uint8_t type; - struct sccp_source_reference destination_local_reference; - uint8_t cause; - - /* optional */ - uint8_t optional_start; - - /* optional */ -#if OPTIONAL - called party 4 - data 3-130 - importance 3 - end_of_optional 1 -#endif - - uint8_t data[0]; -} __attribute__((packed)); - -struct sccp_connection_released { - /* mandantory */ - uint8_t type; - struct sccp_source_reference destination_local_reference; - struct sccp_source_reference source_local_reference; - uint8_t release_cause; - - - /* optional */ - uint8_t optional_start; - -#if OPTIONAL - data 3-130 - importance 3 - end_of_optional 1 -#endif - uint8_t data[0]; -} __attribute__((packed)); - -struct sccp_connection_release_complete { - uint8_t type; - struct sccp_source_reference destination_local_reference; - struct sccp_source_reference source_local_reference; -} __attribute__((packed)); - -struct sccp_data_form1 { - /* mandantory */ - uint8_t type; - struct sccp_source_reference destination_local_reference; - uint8_t segmenting; - - /* variable */ - uint8_t variable_start; - -#if VARIABLE - data 2-256; -#endif - - uint8_t data[0]; -} __attribute__((packed)); - - -struct sccp_data_unitdata { - /* mandantory */ - uint8_t type; - uint8_t proto_class; - - - /* variable */ - uint8_t variable_called; - uint8_t variable_calling; - uint8_t variable_data; - -#if VARIABLE - called party address - calling party address -#endif - - uint8_t data[0]; -} __attribute__((packed)); - -struct sccp_data_it { - /* mandantory */ - uint8_t type; - struct sccp_source_reference destination_local_reference; - struct sccp_source_reference source_local_reference; - uint8_t proto_class; - - uint8_t sequencing[2]; - uint8_t credit; -} __attribute__((packed)); - -struct sccp_proto_err { - uint8_t type; - struct sccp_source_reference destination_local_reference; - uint8_t error_cause; -}; - -#endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index af77f503c..523ff6c34 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -3,13 +3,18 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) # build current directory before building gprs -SUBDIRS = . ipaccess gprs nat bsc +SUBDIRS = . ipaccess gprs + +# Conditional modules +if BUILD_NAT +SUBDIRS += nat +endif +if BUILD_BSC +SUBDIRS += bsc +endif sbin_PROGRAMS = bsc_hack bs11_config isdnsync bsc_mgcp -noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a libmgcp.a - -bscdir = $(libdir) -bsc_LIBRARIES = libsccp.a +noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libmgcp.a libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ chan_alloc.c debug.c socket.c abis_nm_vty.c \ @@ -28,8 +33,6 @@ libmsc_a_SOURCES = gsm_subscriber.c db.c \ libvty_a_SOURCES = common_vty.c -libsccp_a_SOURCES = sccp/sccp.c - libmgcp_a_SOURCES = mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c bsc_hack_SOURCES = bsc_hack.c bsc_init.c bsc_vty.c vty_interface_layer3.c diff --git a/openbsc/src/bsc/Makefile.am b/openbsc/src/bsc/Makefile.am index 3a289c52d..6e179a0c1 100644 --- a/openbsc/src/bsc/Makefile.am +++ b/openbsc/src/bsc/Makefile.am @@ -1,5 +1,5 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) -AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOSCCP_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) bin_PROGRAMS = osmo-bsc @@ -8,5 +8,6 @@ bin_PROGRAMS = osmo-bsc osmo_bsc_SOURCES = osmo_bsc_main.c osmo_bsc_rf.c osmo_bsc_vty.c osmo_bsc_api.c \ $(top_srcdir)/src/debug.c $(top_srcdir)/src/bsc_msc.c \ $(top_srcdir)/src/bsc_init.c -osmo_bsc_LDADD = $(top_builddir)/src/libvty.a $(top_builddir)/src/libsccp.a \ - $(top_builddir)/src/libmgcp.a $(top_builddir)/src/libbsc.a +osmo_bsc_LDADD = $(top_builddir)/src/libvty.a \ + $(top_builddir)/src/libmgcp.a $(top_builddir)/src/libbsc.a \ + $(LIBOSMOSCCP_LIBS) diff --git a/openbsc/src/bsc/osmo_bsc_main.c b/openbsc/src/bsc/osmo_bsc_main.c index b1c5001a9..a6782276b 100644 --- a/openbsc/src/bsc/osmo_bsc_main.c +++ b/openbsc/src/bsc/osmo_bsc_main.c @@ -26,6 +26,8 @@ #include #include +#include + #define _GNU_SOURCE #include @@ -158,6 +160,9 @@ int main(int argc, char **argv) /* seed the PRNG */ srand(time(NULL)); + /* initialize SCCP */ + sccp_set_log_area(DSCCP); + rc = bsc_bootstrap_network(NULL, config_file); if (rc < 0) { diff --git a/openbsc/src/nat/Makefile.am b/openbsc/src/nat/Makefile.am index 0ca3bdfc2..2f37f5cd2 100644 --- a/openbsc/src/nat/Makefile.am +++ b/openbsc/src/nat/Makefile.am @@ -1,5 +1,5 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) -AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOSCCP_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) bin_PROGRAMS = bsc_nat @@ -8,6 +8,6 @@ bin_PROGRAMS = bsc_nat bsc_nat_SOURCES = bsc_filter.c bsc_mgcp_utils.c bsc_nat.c bsc_nat_utils.c \ bsc_nat_vty.c bsc_sccp.c \ $(top_srcdir)/src/debug.c $(top_srcdir)/src/bsc_msc.c -bsc_nat_LDADD = $(top_builddir)/src/libvty.a $(top_builddir)/src/libsccp.a \ +bsc_nat_LDADD = $(top_builddir)/src/libvty.a \ $(top_builddir)/src/libmgcp.a $(top_builddir)/src/libbsc.a \ - -lrt + -lrt $(LIBOSMOSCCP_LIBS) diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c index 538472ac2..0a3719341 100644 --- a/openbsc/src/nat/bsc_nat.c +++ b/openbsc/src/nat/bsc_nat.c @@ -1178,6 +1178,7 @@ int main(int argc, char** argv) signal(SIGPIPE, SIG_IGN); /* recycle timer */ + sccp_set_log_area(DSCCP); sccp_close.cb = sccp_close_unconfirmed; sccp_close.data = NULL; bsc_schedule_timer(&sccp_close, SCCP_CLOSE_TIME, 0); diff --git a/openbsc/src/sccp/sccp.c b/openbsc/src/sccp/sccp.c deleted file mode 100644 index 36570808b..000000000 --- a/openbsc/src/sccp/sccp.c +++ /dev/null @@ -1,1425 +0,0 @@ -/* - * SCCP management code - * - * (C) 2009, 2010 by Holger Hans Peter Freyther - * (C) 2009, 2010 by On-Waves - * - * All Rights Reserved - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include - -#include -#include -#include - -#include - - -static void *tall_sccp_ctx; -static LLIST_HEAD(sccp_connections); - -#define SCCP_MSG_SIZE 4096 -#define SCCP_MSG_HEADROOM 128 - -/* global data */ -const struct sockaddr_sccp sccp_ssn_bssap = { - .sccp_family = 0, - .sccp_ssn = SCCP_SSN_BSSAP, -}; - -struct sccp_system { - /* layer3 -> layer2 */ - void (*write_data)(struct msgb *data, void *context); - void *write_context; -}; - - -static struct sccp_system sccp_system = { - .write_data = NULL, -}; - -struct sccp_data_callback { - /* connection based */ - int (*accept_cb)(struct sccp_connection *, void *); - void *accept_context; - - /* connection less */ - int (*read_cb)(struct msgb *, unsigned int, void *); - void *read_context; - - uint8_t ssn; - struct llist_head callback; -}; - -static LLIST_HEAD(sccp_callbacks); - -static struct sccp_data_callback *_find_ssn(uint8_t ssn) -{ - struct sccp_data_callback *cb; - - llist_for_each_entry(cb, &sccp_callbacks, callback) { - if (cb->ssn == ssn) - return cb; - } - - /* need to add one */ - cb = talloc_zero(tall_sccp_ctx, struct sccp_data_callback); - if (!cb) { - LOGP(DSCCP, LOGL_ERROR, "Failed to allocate sccp callback.\n"); - return NULL; - } - - cb->ssn = ssn; - llist_add_tail(&cb->callback, &sccp_callbacks); - return cb; -} - - -static void _send_msg(struct msgb *msg) -{ - sccp_system.write_data(msg, sccp_system.write_context); -} - -/* - * parsing routines - */ -static int copy_address(struct sccp_address *addr, uint8_t offset, struct msgb *msgb) -{ - struct sccp_called_party_address *party; - - int room = msgb_l2len(msgb) - offset; - uint8_t read = 0; - uint8_t length; - - if (room <= 0) { - LOGP(DSCCP, LOGL_ERROR, "Not enough room for an address: %u\n", room); - return -1; - } - - length = msgb->l2h[offset]; - if (room <= length) { - LOGP(DSCCP, LOGL_ERROR, "Not enough room for optional data %u %u\n", room, length); - return -1; - } - - - party = (struct sccp_called_party_address *)(msgb->l2h + offset + 1); - if (party->point_code_indicator) { - if (length <= read + 2) { - LOGP(DSCCP, LOGL_ERROR, "POI does not fit %u\n", length); - return -1; - } - - - memcpy(&addr->poi, &party->data[read], 2); - read += 2; - } - - if (party->ssn_indicator) { - if (length <= read + 1) { - LOGP(DSCCP, LOGL_ERROR, "SSN does not fit %u\n", length); - return -1; - } - - addr->ssn = party->data[read]; - read += 1; - } - - if (party->global_title_indicator) { - LOGP(DSCCP, LOGL_ERROR, "GTI not supported %u\n", *(uint8_t *)party); - return -1; - } - - addr->address = *party; - return 0; -} - -static int check_address(struct sccp_address *addr) -{ - /* ignore point_code_indicator... it should be zero... but */ - if (addr->address.ssn_indicator != 1 - || addr->address.global_title_indicator == 1 - || addr->address.routing_indicator != 1) { - LOGP(DSCCP, LOGL_ERROR, - "Invalid called address according to 08.06: 0x%x 0x%x\n", - *(uint8_t *)&addr->address, addr->ssn); - return -1; - } - - return 0; -} - -static int _sccp_parse_optional_data(const int offset, - struct msgb *msgb, struct sccp_optional_data *data) -{ - uint16_t room = msgb_l2len(msgb) - offset; - uint16_t read = 0; - - while (room > read) { - uint8_t type = msgb->l2h[offset + read]; - if (type == SCCP_PNC_END_OF_OPTIONAL) - return 0; - - if (read + 1 >= room) { - LOGP(DSCCP, LOGL_ERROR, "no place for length\n"); - return 0; - } - - uint8_t length = msgb->l2h[offset + read + 1]; - read += 2 + length; - - - if (room <= read) { - LOGP(DSCCP, LOGL_ERROR, - "no space for the data: type: %d read: %d room: %d l2: %d\n", - type, read, room, msgb_l2len(msgb)); - return 0; - } - - if (type == SCCP_PNC_DATA) { - data->data_len = length; - data->data_start = offset + read - length; - } - - } - - return -1; -} - -int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *result) -{ - static const uint32_t header_size = - sizeof(struct sccp_connection_request); - static const uint32_t optional_offset = - offsetof(struct sccp_connection_request, optional_start); - static const uint32_t called_offset = - offsetof(struct sccp_connection_request, variable_called); - - struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->l2h; - struct sccp_optional_data optional_data; - - /* header check */ - if (msgb_l2len(msgb) < header_size) { - LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", - msgb_l2len(msgb), header_size); - return -1; - } - - /* copy out the calling and called address. Add the offset */ - if (copy_address(&result->called, called_offset + req->variable_called, msgb) != 0) - return -1; - - if (check_address(&result->called) != 0) { - LOGP(DSCCP, LOGL_ERROR, "Invalid called address according to 08.06: 0x%x 0x%x\n", - *(uint8_t *)&result->called.address, result->called.ssn); - return -1; - } - - result->source_local_reference = &req->source_local_reference; - - /* - * parse optional data. - */ - memset(&optional_data, 0, sizeof(optional_data)); - if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) { - LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n"); - return -1; - } - - if (optional_data.data_len != 0) { - msgb->l3h = &msgb->l2h[optional_data.data_start]; - result->data_len = optional_data.data_len; - } else { - result->data_len = 0; - } - - return 0; -} - -int _sccp_parse_connection_released(struct msgb *msgb, struct sccp_parse_result *result) -{ - static int header_size = sizeof(struct sccp_connection_released); - static int optional_offset = offsetof(struct sccp_connection_released, optional_start); - - struct sccp_optional_data optional_data; - struct sccp_connection_released *rls = (struct sccp_connection_released *) msgb->l2h; - - /* we don't have enough size for the struct */ - if (msgb_l2len(msgb) < header_size) { - LOGP(DSCCP, LOGL_ERROR, "msgb > header_size %u %u\n", - msgb_l2len(msgb), header_size); - return -1; - } - - memset(&optional_data, 0, sizeof(optional_data)); - if (_sccp_parse_optional_data(optional_offset + rls->optional_start, msgb, &optional_data) != 0) { - LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n"); - return -1; - } - - result->source_local_reference = &rls->source_local_reference; - result->destination_local_reference = &rls->destination_local_reference; - - if (optional_data.data_len != 0) { - msgb->l3h = &msgb->l2h[optional_data.data_start]; - result->data_len = optional_data.data_len; - } else { - result->data_len = 0; - } - - return 0; -} - -int _sccp_parse_connection_refused(struct msgb *msgb, struct sccp_parse_result *result) -{ - static const uint32_t header_size = - sizeof(struct sccp_connection_refused); - static int optional_offset = offsetof(struct sccp_connection_refused, optional_start); - - struct sccp_optional_data optional_data; - struct sccp_connection_refused *ref; - - /* header check */ - if (msgb_l2len(msgb) < header_size) { - LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", - msgb_l2len(msgb), header_size); - return -1; - } - - ref = (struct sccp_connection_refused *) msgb->l2h; - - result->destination_local_reference = &ref->destination_local_reference; - - memset(&optional_data, 0, sizeof(optional_data)); - if (_sccp_parse_optional_data(optional_offset + ref->optional_start, msgb, &optional_data) != 0) { - LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n"); - return -1; - } - - /* optional data */ - if (optional_data.data_len != 0) { - msgb->l3h = &msgb->l2h[optional_data.data_start]; - result->data_len = optional_data.data_len; - } else { - result->data_len = 0; - } - - return 0; -} - -int _sccp_parse_connection_confirm(struct msgb *msgb, struct sccp_parse_result *result) -{ - static uint32_t header_size = - sizeof(struct sccp_connection_confirm); - static const uint32_t optional_offset = - offsetof(struct sccp_connection_confirm, optional_start); - - struct sccp_optional_data optional_data; - struct sccp_connection_confirm *con; - - /* header check */ - if (msgb_l2len(msgb) < header_size) { - LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", - msgb_l2len(msgb), header_size); - return -1; - } - - con = (struct sccp_connection_confirm *) msgb->l2h; - result->destination_local_reference = &con->destination_local_reference; - result->source_local_reference = &con->source_local_reference; - - memset(&optional_data, 0, sizeof(optional_data)); - if (_sccp_parse_optional_data(optional_offset + con->optional_start, msgb, &optional_data) != 0) { - LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n"); - return -1; - } - - if (optional_data.data_len != 0) { - msgb->l3h = &msgb->l2h[optional_data.data_start]; - result->data_len = optional_data.data_len; - } else { - result->data_len = 0; - } - - return 0; -} - -int _sccp_parse_connection_release_complete(struct msgb *msgb, struct sccp_parse_result *result) -{ - static int header_size = sizeof(struct sccp_connection_release_complete); - - struct sccp_connection_release_complete *cmpl; - - /* header check */ - if (msgb_l2len(msgb) < header_size) { - LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", - msgb_l2len(msgb), header_size); - return -1; - } - - cmpl = (struct sccp_connection_release_complete *) msgb->l2h; - result->source_local_reference = &cmpl->source_local_reference; - result->destination_local_reference = &cmpl->destination_local_reference; - - return 0; -} - -int _sccp_parse_connection_dt1(struct msgb *msgb, struct sccp_parse_result *result) -{ - static int header_size = sizeof(struct sccp_data_form1); - static int variable_offset = offsetof(struct sccp_data_form1, variable_start); - - struct sccp_data_form1 *dt1 = (struct sccp_data_form1 *)msgb->l2h; - - /* we don't have enough size for the struct */ - if (msgb_l2len(msgb) < header_size) { - LOGP(DSCCP, LOGL_ERROR, "msgb > header_size %u %u\n", - msgb_l2len(msgb), header_size); - return -1; - } - - if (dt1->segmenting != 0) { - LOGP(DSCCP, LOGL_ERROR, "This packet has segmenting, not supported: %d\n", dt1->segmenting); - return -1; - } - - result->destination_local_reference = &dt1->destination_local_reference; - - /* some more size checks in here */ - if (msgb_l2len(msgb) < variable_offset + dt1->variable_start + 1) { - LOGP(DSCCP, LOGL_ERROR, "Not enough space for variable start: %u %u\n", - msgb_l2len(msgb), dt1->variable_start); - return -1; - } - - result->data_len = msgb->l2h[variable_offset + dt1->variable_start]; - msgb->l3h = &msgb->l2h[dt1->variable_start + variable_offset + 1]; - - if (msgb_l3len(msgb) < result->data_len) { - LOGP(DSCCP, LOGL_ERROR, "Not enough room for the payload: %u %u\n", - msgb_l3len(msgb), result->data_len); - return -1; - } - - return 0; -} - -int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result) -{ - static const uint32_t header_size = sizeof(struct sccp_data_unitdata); - static const uint32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called); - static const uint32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling); - static const uint32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data); - - struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h; - - if (msgb_l2len(msgb) < header_size) { - LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", - msgb_l2len(msgb), header_size); - return -1; - } - - /* copy out the calling and called address. Add the off */ - if (copy_address(&result->called, called_offset + udt->variable_called, msgb) != 0) - return -1; - - if (check_address(&result->called) != 0) { - LOGP(DSCCP, LOGL_ERROR, "Invalid called address according to 08.06: 0x%x 0x%x\n", - *(uint8_t *)&result->called.address, result->called.ssn); - return -1; - } - - if (copy_address(&result->calling, calling_offset + udt->variable_calling, msgb) != 0) - return -1; - - if (check_address(&result->calling) != 0) { - LOGP(DSCCP, LOGL_ERROR, "Invalid called address according to 08.06: 0x%x 0x%x\n", - *(uint8_t *)&result->called.address, result->called.ssn); - } - - /* we don't have enough size for the data */ - if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) { - LOGP(DSCCP, LOGL_ERROR, "msgb < header + offset %u %u %u\n", - msgb_l2len(msgb), header_size, udt->variable_data); - return -1; - } - - - msgb->l3h = &udt->data[udt->variable_data]; - result->data_len = msgb_l3len(msgb); - - if (msgb_l3len(msgb) != msgb->l3h[-1]) { - LOGP(DSCCP, LOGL_ERROR, "msgb is truncated is: %u should: %u\n", - msgb_l3len(msgb), msgb->l3h[-1]); - return -1; - } - - return 0; -} - -static int _sccp_parse_it(struct msgb *msgb, struct sccp_parse_result *result) -{ - static const uint32_t header_size = sizeof(struct sccp_data_it); - - struct sccp_data_it *it; - - if (msgb_l2len(msgb) < header_size) { - LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", - msgb_l2len(msgb), header_size); - return -1; - } - - it = (struct sccp_data_it *) msgb->l2h; - result->data_len = 0; - result->source_local_reference = &it->source_local_reference; - result->destination_local_reference = &it->destination_local_reference; - return 0; -} - -static int _sccp_parse_err(struct msgb *msgb, struct sccp_parse_result *result) -{ - static const uint32_t header_size = sizeof(struct sccp_proto_err); - - struct sccp_proto_err *err; - - if (msgb_l2len(msgb) < header_size) { - LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", - msgb_l2len(msgb), header_size); - return -1; - } - - err = (struct sccp_proto_err *) msgb->l2h; - result->data_len = 0; - result->destination_local_reference = &err->destination_local_reference; - return 0; -} - -/* - * Send UDT. Currently we have a fixed address... - */ -static int _sccp_send_data(int class, const struct sockaddr_sccp *in, - const struct sockaddr_sccp *out, struct msgb *payload) -{ - struct sccp_data_unitdata *udt; - uint8_t *data; - - if (msgb_l3len(payload) > 256) { - LOGP(DSCCP, LOGL_ERROR, "The payload is too big for one udt\n"); - return -1; - } - - struct msgb *msg = msgb_alloc_headroom(SCCP_MSG_SIZE, - SCCP_MSG_HEADROOM, "sccp: udt"); - msg->l2h = &msg->data[0]; - udt = (struct sccp_data_unitdata *)msgb_put(msg, sizeof(*udt)); - - udt->type = SCCP_MSG_TYPE_UDT; - udt->proto_class = class; - udt->variable_called = 3; - udt->variable_calling = 5; - udt->variable_data = 7; - - /* for variable data we start with a size and the data */ - data = msgb_put(msg, 1 + 2); - data[0] = 2; - data[1] = 0x42; - data[2] = out->sccp_ssn; - - data = msgb_put(msg, 1 + 2); - data[0] = 2; - data[1] = 0x42; - data[2] = in->sccp_ssn; - - /* copy the payload */ - data = msgb_put(msg, 1 + msgb_l3len(payload)); - data[0] = msgb_l3len(payload); - memcpy(&data[1], payload->l3h, msgb_l3len(payload)); - - _send_msg(msg); - return 0; -} - -static int _sccp_handle_read(struct msgb *msgb) -{ - struct sccp_data_callback *cb; - struct sccp_parse_result result; - - if (_sccp_parse_udt(msgb, &result) != 0) - return -1; - - cb = _find_ssn(result.called.ssn); - if (!cb || !cb->read_cb) { - LOGP(DSCCP, LOGL_ERROR, "No routing for UDT for called SSN: %u\n", result.called.ssn); - return -1; - } - - /* sanity check */ - return cb->read_cb(msgb, msgb_l3len(msgb), cb->read_context); -} - -/* - * handle connection orientated methods - */ -static int source_local_reference_is_free(struct sccp_source_reference *reference) -{ - struct sccp_connection *connection; - - llist_for_each_entry(connection, &sccp_connections, list) { - if (memcmp(reference, &connection->source_local_reference, sizeof(*reference)) == 0) - return -1; - } - - return 0; -} - -static int destination_local_reference_is_free(struct sccp_source_reference *reference) -{ - struct sccp_connection *connection; - - llist_for_each_entry(connection, &sccp_connections, list) { - if (memcmp(reference, &connection->destination_local_reference, sizeof(*reference)) == 0) - return -1; - } - - return 0; -} - -static int assign_source_local_reference(struct sccp_connection *connection) -{ - static uint32_t last_ref = 0x30000; - int wrapped = 0; - - do { - struct sccp_source_reference reference; - reference.octet1 = (last_ref >> 0) & 0xff; - reference.octet2 = (last_ref >> 8) & 0xff; - reference.octet3 = (last_ref >> 16) & 0xff; - - ++last_ref; - /* do not use the reversed word and wrap around */ - if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) { - LOGP(DSCCP, LOGL_DEBUG, "Wrapped searching for a free code\n"); - last_ref = 0; - ++wrapped; - } - - if (source_local_reference_is_free(&reference) == 0) { - connection->source_local_reference = reference; - return 0; - } - } while (wrapped != 2); - - LOGP(DSCCP, LOGL_ERROR, "Finding a free reference failed\n"); - return -1; -} - -static void _sccp_set_connection_state(struct sccp_connection *connection, int new_state) -{ - int old_state = connection->connection_state; - - connection->connection_state = new_state; - if (connection->state_cb) - connection->state_cb(connection, old_state); -} - -struct msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *inp, int length) -{ - struct msgb *msgb; - struct sccp_connection_refused *ref; - uint8_t *data; - - msgb = msgb_alloc_headroom(SCCP_MSG_SIZE, - SCCP_MSG_HEADROOM, "sccp ref"); - if (!msgb) { - LOGP(DSCCP, LOGL_ERROR, "Failed to allocate refusal msg.\n"); - return NULL; - } - - msgb->l2h = &msgb->data[0]; - - ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref)); - ref->type = SCCP_MSG_TYPE_CREF; - memcpy(&ref->destination_local_reference, src_ref, - sizeof(struct sccp_source_reference)); - ref->cause = cause; - ref->optional_start = 1; - - if (inp) { - data = msgb_put(msgb, 1 + 1 + length); - data[0] = SCCP_PNC_DATA; - data[1] = length; - memcpy(&data[2], inp, length); - } - - data = msgb_put(msgb, 1); - data[0] = SCCP_PNC_END_OF_OPTIONAL; - return msgb; -} - -static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause) -{ - struct msgb *msgb = sccp_create_refuse(src_ref, cause, NULL, 0); - if (!msgb) - return -1; - - _send_msg(msgb); - return 0; -} - -struct msgb *sccp_create_cc(struct sccp_source_reference *src_ref, - struct sccp_source_reference *dst_ref) -{ - struct msgb *response; - struct sccp_connection_confirm *confirm; - uint8_t *optional_data; - - response = msgb_alloc_headroom(SCCP_MSG_SIZE, - SCCP_MSG_HEADROOM, "sccp confirm"); - if (!response) { - LOGP(DSCCP, LOGL_ERROR, "Failed to create SCCP Confirm.\n"); - return NULL; - } - - response->l2h = &response->data[0]; - - confirm = (struct sccp_connection_confirm *) msgb_put(response, sizeof(*confirm)); - - confirm->type = SCCP_MSG_TYPE_CC; - memcpy(&confirm->destination_local_reference, - dst_ref, sizeof(*dst_ref)); - memcpy(&confirm->source_local_reference, - src_ref, sizeof(*src_ref)); - confirm->proto_class = 2; - confirm->optional_start = 1; - - optional_data = (uint8_t *) msgb_put(response, 1); - optional_data[0] = SCCP_PNC_END_OF_OPTIONAL; - return response; -} - -static int _sccp_send_connection_confirm(struct sccp_connection *connection) -{ - struct msgb *response; - - if (assign_source_local_reference(connection) != 0) - return -1; - - response = sccp_create_cc(&connection->source_local_reference, - &connection->destination_local_reference); - if (!response) - return -1; - - _send_msg(response); - _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_ESTABLISHED); - return 0; -} - -static int _sccp_send_connection_request(struct sccp_connection *connection, - const struct sockaddr_sccp *called, struct msgb *msg) -{ - struct msgb *request; - struct sccp_connection_request *req; - uint8_t *data; - uint8_t extra_size = 3 + 1; - - - if (msg && (msgb_l3len(msg) < 3 || msgb_l3len(msg) > 130)) { - LOGP(DSCCP, LOGL_ERROR, "Invalid amount of data... %d\n", msgb_l3len(msg)); - return -1; - } - - /* try to find a id */ - if (assign_source_local_reference(connection) != 0) { - LOGP(DSCCP, LOGL_ERROR, "Assigning a local reference failed.\n"); - _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_SETUP_ERROR); - return -1; - } - - - if (msg) - extra_size += 2 + msgb_l3len(msg); - request = msgb_alloc_headroom(SCCP_MSG_SIZE, - SCCP_MSG_HEADROOM, "sccp connection request"); - request->l2h = &request->data[0]; - req = (struct sccp_connection_request *) msgb_put(request, sizeof(*req)); - - req->type = SCCP_MSG_TYPE_CR; - memcpy(&req->source_local_reference, &connection->source_local_reference, - sizeof(connection->source_local_reference)); - req->proto_class = 2; - req->variable_called = 2; - req->optional_start = 4; - - /* write the called party address */ - data = msgb_put(request, 1 + 2); - data[0] = 2; - data[1] = 0x42; - data[2] = called->sccp_ssn; - - /* write the payload */ - if (msg) { - data = msgb_put(request, 2 + msgb_l3len(msg)); - data[0] = SCCP_PNC_DATA; - data[1] = msgb_l3len(msg); - memcpy(&data[2], msg->l3h, msgb_l3len(msg)); - } - - data = msgb_put(request, 1); - data[0] = SCCP_PNC_END_OF_OPTIONAL; - - llist_add_tail(&connection->list, &sccp_connections); - _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REQUEST); - - _send_msg(request); - return 0; -} - -struct msgb *sccp_create_dt1(struct sccp_source_reference *dst_ref, uint8_t *inp_data, uint8_t len) -{ - struct msgb *msgb; - struct sccp_data_form1 *dt1; - uint8_t *data; - - msgb = msgb_alloc_headroom(SCCP_MSG_SIZE, - SCCP_MSG_HEADROOM, "sccp dt1"); - if (!msgb) { - LOGP(DSCCP, LOGL_ERROR, "Failed to create DT1 msg.\n"); - return NULL; - } - - msgb->l2h = &msgb->data[0]; - - dt1 = (struct sccp_data_form1 *) msgb_put(msgb, sizeof(*dt1)); - dt1->type = SCCP_MSG_TYPE_DT1; - memcpy(&dt1->destination_local_reference, dst_ref, - sizeof(struct sccp_source_reference)); - dt1->segmenting = 0; - - /* copy the data */ - dt1->variable_start = 1; - data = msgb_put(msgb, 1 + len); - data[0] = len; - memcpy(&data[1], inp_data, len); - - return msgb; -} - -static int _sccp_send_connection_data(struct sccp_connection *conn, struct msgb *_data) -{ - struct msgb *msgb; - - if (msgb_l3len(_data) < 2 || msgb_l3len(_data) > 256) { - LOGP(DSCCP, LOGL_ERROR, "data size too big, segmenting unimplemented.\n"); - return -1; - } - - msgb = sccp_create_dt1(&conn->destination_local_reference, - _data->l3h, msgb_l3len(_data)); - if (!msgb) - return -1; - - _send_msg(msgb); - return 0; -} - -static int _sccp_send_connection_it(struct sccp_connection *conn) -{ - struct msgb *msgb; - struct sccp_data_it *it; - - msgb = msgb_alloc_headroom(SCCP_MSG_SIZE, - SCCP_MSG_HEADROOM, "sccp it"); - msgb->l2h = &msgb->data[0]; - it = (struct sccp_data_it *) msgb_put(msgb, sizeof(*it)); - it->type = SCCP_MSG_TYPE_IT; - memcpy(&it->destination_local_reference, &conn->destination_local_reference, - sizeof(struct sccp_source_reference)); - memcpy(&it->source_local_reference, &conn->source_local_reference, - sizeof(struct sccp_source_reference)); - - it->proto_class = 0x2; - it->sequencing[0] = it->sequencing[1] = 0; - it->credit = 0; - - _send_msg(msgb); - return 0; -} - -struct msgb *sccp_create_rlsd(struct sccp_source_reference *src_ref, - struct sccp_source_reference *dst_ref, int cause) -{ - struct msgb *msg; - struct sccp_connection_released *rel; - uint8_t *data; - - msg = msgb_alloc_headroom(SCCP_MSG_SIZE, SCCP_MSG_HEADROOM, - "sccp: connection released"); - if (!msg) { - LOGP(DSCCP, LOGL_ERROR, "Failed to allocate RLSD.\n"); - return NULL; - } - - msg->l2h = &msg->data[0]; - rel = (struct sccp_connection_released *) msgb_put(msg, sizeof(*rel)); - rel->type = SCCP_MSG_TYPE_RLSD; - rel->release_cause = cause; - - /* copy the source references */ - memcpy(&rel->destination_local_reference, dst_ref, - sizeof(struct sccp_source_reference)); - memcpy(&rel->source_local_reference, src_ref, - sizeof(struct sccp_source_reference)); - - data = msgb_put(msg, 1); - data[0] = SCCP_PNC_END_OF_OPTIONAL; - return msg; -} - -static int _sccp_send_connection_released(struct sccp_connection *conn, int cause) -{ - struct msgb *msg; - - msg = sccp_create_rlsd(&conn->source_local_reference, - &conn->destination_local_reference, - cause); - if (!msg) - return -1; - - _sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_RELEASE); - _send_msg(msg); - return 0; -} - -/* - * Open a connection. The following is going to happen: - * - * - Verify the packet, e.g. that we have no other connection - * that id. - * - Ask the user if he wants to accept the connection - * - Try to open the connection by assigning a source local reference - * and sending the packet - */ -static int _sccp_handle_connection_request(struct msgb *msgb) -{ - struct sccp_parse_result result; - - struct sccp_data_callback *cb; - struct sccp_connection *connection; - - if (_sccp_parse_connection_request(msgb, &result) != 0) - return -1; - - cb = _find_ssn(result.called.ssn); - if (!cb || !cb->accept_cb) { - LOGP(DSCCP, LOGL_ERROR, "No routing for CR for called SSN: %u\n", result.called.ssn); - return -1; - } - - /* check if the system wants this connection */ - connection = talloc_zero(tall_sccp_ctx, struct sccp_connection); - if (!connection) { - LOGP(DSCCP, LOGL_ERROR, "Allocation failed\n"); - return -1; - } - - /* - * sanity checks: - * - Is the source_local_reference in any other connection? - * then will call accept, assign a "destination" local reference - * and send a connection confirm, otherwise we will send a refuseed - * one.... - */ - if (destination_local_reference_is_free(result.source_local_reference) != 0) { - LOGP(DSCCP, LOGL_ERROR, "Need to reject connection with existing reference\n"); - _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE); - talloc_free(connection); - return -1; - } - - connection->incoming = 1; - connection->destination_local_reference = *result.source_local_reference; - - if (cb->accept_cb(connection, cb->accept_context) != 0) { - _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_END_USER_ORIGINATED); - _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED); - talloc_free(connection); - return 0; - } - - - llist_add_tail(&connection->list, &sccp_connections); - - if (_sccp_send_connection_confirm(connection) != 0) { - LOGP(DSCCP, LOGL_ERROR, "Sending confirm failed... no available source reference?\n"); - - _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE); - _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED); - llist_del(&connection->list); - talloc_free(connection); - - return -1; - } - - /* - * If we have data let us forward things. - */ - if (result.data_len != 0 && connection->data_cb) { - connection->data_cb(connection, msgb, result.data_len); - } - - return 0; -} - -/* Handle the release confirmed */ -static int _sccp_handle_connection_release_complete(struct msgb *msgb) -{ - struct sccp_parse_result result; - struct sccp_connection *conn; - - if (_sccp_parse_connection_release_complete(msgb, &result) != 0) - return -1; - - /* find the connection */ - llist_for_each_entry(conn, &sccp_connections, list) { - if (conn->data_cb - && memcmp(&conn->source_local_reference, - result.destination_local_reference, - sizeof(conn->source_local_reference)) == 0 - && memcmp(&conn->destination_local_reference, - result.source_local_reference, - sizeof(conn->destination_local_reference)) == 0) { - goto found; - } - } - - - LOGP(DSCCP, LOGL_ERROR, "Release complete of unknown connection\n"); - return -1; - -found: - llist_del(&conn->list); - _sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_RELEASE_COMPLETE); - return 0; -} - -/* Handle the Data Form 1 message */ -static int _sccp_handle_connection_dt1(struct msgb *msgb) -{ - struct sccp_parse_result result; - struct sccp_connection *conn; - - if (_sccp_parse_connection_dt1(msgb, &result) != 0) - return -1; - - /* lookup if we have a connection with the given reference */ - llist_for_each_entry(conn, &sccp_connections, list) { - if (conn->data_cb - && memcmp(&conn->source_local_reference, - result.destination_local_reference, - sizeof(conn->source_local_reference)) == 0) { - goto found; - } - } - - LOGP(DSCCP, LOGL_ERROR, "No connection found for dt1 data\n"); - return -1; - -found: - conn->data_cb(conn, msgb, result.data_len); - return 0; -} - -/* confirm a connection release */ -static int _sccp_send_connection_release_complete(struct sccp_connection *connection) -{ - struct msgb *msgb; - struct sccp_connection_release_complete *rlc; - - msgb = msgb_alloc_headroom(SCCP_MSG_SIZE, - SCCP_MSG_HEADROOM, "sccp rlc"); - msgb->l2h = &msgb->data[0]; - - rlc = (struct sccp_connection_release_complete *) msgb_put(msgb, sizeof(*rlc)); - rlc->type = SCCP_MSG_TYPE_RLC; - memcpy(&rlc->destination_local_reference, - &connection->destination_local_reference, sizeof(struct sccp_source_reference)); - memcpy(&rlc->source_local_reference, - &connection->source_local_reference, sizeof(struct sccp_source_reference)); - - _send_msg(msgb); - - /* - * Remove from the list of active connections and set the state. User code - * should now free the entry. - */ - llist_del(&connection->list); - _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_RELEASE_COMPLETE); - return 0; -} - -/* connection released, send a released confirm */ -static int _sccp_handle_connection_released(struct msgb *msgb) -{ - struct sccp_parse_result result; - struct sccp_connection *conn; - - if (_sccp_parse_connection_released(msgb, &result) == -1) - return -1; - - /* lookup if we have a connection with the given reference */ - llist_for_each_entry(conn, &sccp_connections, list) { - if (conn->data_cb - && memcmp(&conn->source_local_reference, - result.destination_local_reference, - sizeof(conn->source_local_reference)) == 0 - && memcmp(&conn->destination_local_reference, - result.source_local_reference, - sizeof(conn->destination_local_reference)) == 0) { - goto found; - } - } - - - LOGP(DSCCP, LOGL_ERROR, "Unknown connection was released.\n"); - return -1; - - /* we have found a connection */ -found: - /* optional data */ - if (result.data_len != 0 && conn->data_cb) { - conn->data_cb(conn, msgb, result.data_len); - } - - /* generate a response */ - if (_sccp_send_connection_release_complete(conn) != 0) { - LOGP(DSCCP, LOGL_ERROR, "Sending release confirmed failed\n"); - return -1; - } - - return 0; -} - -static int _sccp_handle_connection_refused(struct msgb *msgb) -{ - struct sccp_parse_result result; - struct sccp_connection *conn; - - if (_sccp_parse_connection_refused(msgb, &result) != 0) - return -1; - - /* lookup if we have a connection with the given reference */ - llist_for_each_entry(conn, &sccp_connections, list) { - if (conn->incoming == 0 && conn->data_cb - && memcmp(&conn->source_local_reference, - result.destination_local_reference, - sizeof(conn->source_local_reference)) == 0) { - goto found; - } - } - - LOGP(DSCCP, LOGL_ERROR, "Refused but no connection found\n"); - return -1; - -found: - /* optional data */ - if (result.data_len != 0 && conn->data_cb) { - conn->data_cb(conn, msgb, result.data_len); - } - - - llist_del(&conn->list); - _sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_REFUSED); - return 0; -} - -static int _sccp_handle_connection_confirm(struct msgb *msgb) -{ - struct sccp_parse_result result; - struct sccp_connection *conn; - - if (_sccp_parse_connection_confirm(msgb, &result) != 0) - return -1; - - /* lookup if we have a connection with the given reference */ - llist_for_each_entry(conn, &sccp_connections, list) { - if (conn->incoming == 0 && conn->data_cb - && memcmp(&conn->source_local_reference, - result.destination_local_reference, - sizeof(conn->source_local_reference)) == 0) { - goto found; - } - } - - LOGP(DSCCP, LOGL_ERROR, "Confirmed but no connection found\n"); - return -1; - -found: - /* copy the addresses of the connection */ - conn->destination_local_reference = *result.source_local_reference; - _sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_ESTABLISHED); - - /* optional data */ - if (result.data_len != 0 && conn->data_cb) { - conn->data_cb(conn, msgb, result.data_len); - } - - return 0; -} - - -int sccp_system_init(void (*outgoing)(struct msgb *data, void *ctx), void *ctx) -{ - sccp_system.write_data = outgoing; - sccp_system.write_context = ctx; - - return 0; -} - -/* oh my god a real SCCP packet. need to dispatch it now */ -int sccp_system_incoming(struct msgb *msgb) -{ - if (msgb_l2len(msgb) < 1 ) { - LOGP(DSCCP, LOGL_ERROR, "Too short packet\n"); - return -1; - } - - int type = msgb->l2h[0]; - - switch(type) { - case SCCP_MSG_TYPE_CR: - return _sccp_handle_connection_request(msgb); - break; - case SCCP_MSG_TYPE_RLSD: - return _sccp_handle_connection_released(msgb); - break; - case SCCP_MSG_TYPE_CREF: - return _sccp_handle_connection_refused(msgb); - break; - case SCCP_MSG_TYPE_CC: - return _sccp_handle_connection_confirm(msgb); - break; - case SCCP_MSG_TYPE_RLC: - return _sccp_handle_connection_release_complete(msgb); - break; - case SCCP_MSG_TYPE_DT1: - return _sccp_handle_connection_dt1(msgb); - break; - case SCCP_MSG_TYPE_UDT: - return _sccp_handle_read(msgb); - break; - default: - LOGP(DSCCP, LOGL_ERROR, "unimplemented msg type: %d\n", type); - }; - - return -1; -} - -/* create a packet from the data */ -int sccp_connection_write(struct sccp_connection *connection, struct msgb *data) -{ - if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM - || connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) { - LOGP(DSCCP, LOGL_ERROR, "sccp_connection_write: Wrong connection state: %p %d\n", - connection, connection->connection_state); - return -1; - } - - return _sccp_send_connection_data(connection, data); -} - -/* - * Send a Inactivity Test message. The owner of the connection - * should start a timer and call this method regularily. Calling - * this every 60 seconds should be good enough. - */ -int sccp_connection_send_it(struct sccp_connection *connection) -{ - if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM - || connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) { - LOGP(DSCCP, LOGL_ERROR, "sccp_connection_write: Wrong connection state: %p %d\n", - connection, connection->connection_state); - return -1; - } - - return _sccp_send_connection_it(connection); -} - -/* send a connection release and wait for the connection released */ -int sccp_connection_close(struct sccp_connection *connection, int cause) -{ - if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM - || connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) { - LOGP(DSCCP, LOGL_ERROR, "Can not close the connection. It was never opened: %p %d\n", - connection, connection->connection_state); - return -1; - } - - return _sccp_send_connection_released(connection, cause); -} - -int sccp_connection_free(struct sccp_connection *connection) -{ - if (connection->connection_state > SCCP_CONNECTION_STATE_NONE - && connection->connection_state < SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { - LOGP(DSCCP, LOGL_ERROR, "The connection needs to be released before it is freed"); - return -1; - } - - talloc_free(connection); - return 0; -} - -int sccp_connection_force_free(struct sccp_connection *con) -{ - if (con->connection_state > SCCP_CONNECTION_STATE_NONE && - con->connection_state < SCCP_CONNECTION_STATE_RELEASE_COMPLETE) - llist_del(&con->list); - - con->connection_state = SCCP_CONNECTION_STATE_REFUSED; - sccp_connection_free(con); - return 0; -} - -struct sccp_connection *sccp_connection_socket(void) -{ - return talloc_zero(tall_sccp_ctx, struct sccp_connection); -} - -int sccp_connection_connect(struct sccp_connection *conn, - const struct sockaddr_sccp *local, - struct msgb *data) -{ - return _sccp_send_connection_request(conn, local, data); -} - -int sccp_connection_set_incoming(const struct sockaddr_sccp *sock, - int (*accept_cb)(struct sccp_connection *, void *), void *context) -{ - struct sccp_data_callback *cb; - - if (!sock) - return -2; - - cb = _find_ssn(sock->sccp_ssn); - if (!cb) - return -1; - - cb->accept_cb = accept_cb; - cb->accept_context = context; - return 0; -} - -int sccp_write(struct msgb *data, const struct sockaddr_sccp *in, - const struct sockaddr_sccp *out, int class) -{ - return _sccp_send_data(class, in, out, data); -} - -int sccp_set_read(const struct sockaddr_sccp *sock, - int (*read_cb)(struct msgb *, unsigned int, void *), void *context) -{ - struct sccp_data_callback *cb; - - if (!sock) - return -2; - - cb = _find_ssn(sock->sccp_ssn); - if (!cb) - return -1; - - cb->read_cb = read_cb; - cb->read_context = context; - return 0; -} - -static_assert(sizeof(struct sccp_source_reference) <= sizeof(uint32_t), enough_space); - -uint32_t sccp_src_ref_to_int(struct sccp_source_reference *ref) -{ - uint32_t src_ref = 0; - memcpy(&src_ref, ref, sizeof(*ref)); - return src_ref; -} - -struct sccp_source_reference sccp_src_ref_from_int(uint32_t int_ref) -{ - struct sccp_source_reference ref; - memcpy(&ref, &int_ref, sizeof(ref)); - return ref; -} - -int sccp_determine_msg_type(struct msgb *msg) -{ - if (msgb_l2len(msg) < 1) - return -1; - - return msg->l2h[0]; -} - -int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result) -{ - int type; - - if (msgb_l2len(msg) < 1) - return -1; - - type = msg->l2h[0]; - switch(type) { - case SCCP_MSG_TYPE_CR: - return _sccp_parse_connection_request(msg, result); - break; - case SCCP_MSG_TYPE_RLSD: - return _sccp_parse_connection_released(msg, result); - break; - case SCCP_MSG_TYPE_CREF: - return _sccp_parse_connection_refused(msg, result); - break; - case SCCP_MSG_TYPE_CC: - return _sccp_parse_connection_confirm(msg, result); - break; - case SCCP_MSG_TYPE_RLC: - return _sccp_parse_connection_release_complete(msg, result); - break; - case SCCP_MSG_TYPE_DT1: - return _sccp_parse_connection_dt1(msg, result); - break; - case SCCP_MSG_TYPE_UDT: - return _sccp_parse_udt(msg, result); - break; - case SCCP_MSG_TYPE_IT: - return _sccp_parse_it(msg, result); - break; - case SCCP_MSG_TYPE_ERR: - return _sccp_parse_err(msg, result); - break; - }; - - LOGP(DSCCP, LOGL_ERROR, "Unimplemented MSG Type: 0x%x\n", type); - return -1; -} - -static __attribute__((constructor)) void on_dso_load(void) -{ - tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp"); -} - -static __attribute__((destructor)) void on_dso_unload(void) -{ - talloc_report_full(tall_sccp_ctx, stderr); -} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index b469832fc..99ec29679 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1 +1,5 @@ -SUBDIRS = debug gsm0408 db channel sccp bsc-nat +SUBDIRS = debug gsm0408 db channel + +if BUILD_NAT +SUBDIRS += bsc-nat +endif diff --git a/openbsc/tests/bsc-nat/Makefile.am b/openbsc/tests/bsc-nat/Makefile.am index 013a465e7..f5af721b9 100644 --- a/openbsc/tests/bsc-nat/Makefile.am +++ b/openbsc/tests/bsc-nat/Makefile.am @@ -1,5 +1,5 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSCCP_CFLAGS) EXTRA_DIST = bsc_data.c @@ -12,4 +12,4 @@ bsc_nat_test_SOURCES = bsc_nat_test.c \ $(top_srcdir)/src/nat/bsc_mgcp_utils.c \ $(top_srcdir)/src/mgcp/mgcp_protocol.c \ $(top_srcdir)/src/mgcp/mgcp_network.c -bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libsccp.a $(LIBOSMOCORE_LIBS) -lrt +bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(LIBOSMOCORE_LIBS) -lrt $(LIBOSMOSCCP_LIBS) diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index 6771b314e..1b45014b5 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -29,6 +29,8 @@ #include +#include + #include /* test messages for ipa */ @@ -699,6 +701,7 @@ int main(int argc, char **argv) { struct log_target *stderr_target; + sccp_set_log_area(DSCCP); log_init(&log_info); stderr_target = log_target_create_stderr(); log_add_target(stderr_target); diff --git a/openbsc/tests/sccp/Makefile.am b/openbsc/tests/sccp/Makefile.am deleted file mode 100644 index b35693e82..000000000 --- a/openbsc/tests/sccp/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -INCLUDES = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) - -noinst_PROGRAMS = sccp_test - -sccp_test_SOURCES = sccp_test.c -sccp_test_LDADD = $(top_builddir)/src/libsccp.a $(top_builddir)/src/libbsc.a $(LIBOSMOCORE_LIBS) - diff --git a/openbsc/tests/sccp/sccp_test.c b/openbsc/tests/sccp/sccp_test.c deleted file mode 100644 index 3b9ef4ed5..000000000 --- a/openbsc/tests/sccp/sccp_test.c +++ /dev/null @@ -1,851 +0,0 @@ -/* - * SCCP testing code - * - * (C) 2009 by Holger Hans Peter Freyther - * (C) 2009 by On-Waves - * - * All Rights Reserved - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include - -#include - -#include -#include -#include - -#include - -#define MIN(x, y) ((x) < (y) ? (x) : (y)) - -/* BSC -> MSC */ -static const uint8_t bssmap_reset[] = { - 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, - 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04, - 0x01, 0x20, -}; - -/* MSC -> BSC reset ack */ -static const uint8_t bssmap_reset_ack[] = { - 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, - 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03, - 0x00, 0x01, 0x31, -}; - -/* MSC -> BSC paging, connection less */ -static const uint8_t bssmap_paging[] = { - 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, - 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10, - 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, - 0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06, -}; - -/* MSC -> BSC paging, UDT without PC */ -static const uint8_t bssmap_udt[] = { - 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, - 0x02, 0x42, 0xfe, 0x10, 0x00, 0x0e, 0x52, 0x08, - 0x08, 0x29, 0x47, 0x10, 0x02, 0x01, 0x31, 0x97, - 0x61, 0x1a, 0x01, 0x06, -}; - -/* BSC -> MSC connection open */ -static const uint8_t bssmap_cr[] = { - 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02, - 0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05, - 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3, - 0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33, - 0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01, - 0x31, 0x97, 0x61, 0x00 -}; - -/* MSC -> BSC connection confirm */ -static const uint8_t bssmap_cc[] = { - 0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, -}; - -/* MSC -> BSC DTAP - * - * we fake a bit and make it BSC -> MSC... so the - * payload does not make any sense.. - */ -static const uint8_t bssmap_dtap[] = { - 0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x0c, - 0x03, 0x05, 0x5c, 0x08, 0x11, 0x81, 0x33, 0x66, 0x02, 0x13, - 0x45, 0xf4, -}; - -/* MSC -> BSC clear command */ -static const uint8_t bssmap_clear[] = { - 0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x06, 0x00, 0x04, 0x20, - 0x04, 0x01, 0x09, -}; - -/* MSC -> BSC released */ -static const uint8_t bssmap_released[] = { - 0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f, - 0x02, 0x23, 0x42, 0x00, -}; - -/* BSC -> MSC released */ -static const uint8_t bssmap_release_complete[] = { - 0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03 -}; - -struct test_data { - int length; - const uint8_t *data; - int payload_start; - int payload_length; - uint8_t first_byte; - - /* in case it should trigger a sccp response */ - int write; - const uint8_t *response; - int response_length; -}; - -static const struct test_data test_data[] = { - { - .length = ARRAY_SIZE(bssmap_reset), - .data = &bssmap_reset[0], - .payload_start = 12, - .payload_length = ARRAY_SIZE(bssmap_reset) - 12, - .first_byte = 0x0, - }, - { - .length = ARRAY_SIZE(bssmap_reset_ack), - .data = &bssmap_reset_ack[0], - .payload_start = 16, - .payload_length = ARRAY_SIZE(bssmap_reset_ack) - 16, - .first_byte = 0x0, - }, - { - .length = ARRAY_SIZE(bssmap_paging), - .data = &bssmap_paging[0], - .payload_start = 16, - .payload_length = ARRAY_SIZE(bssmap_paging) - 16, - .first_byte = 0x0, - }, - { - .length = ARRAY_SIZE(bssmap_cr), - .data = &bssmap_cr[0], - .payload_start = 12, - /* 0x00 is end of optional data, subtract this byte */ - .payload_length = 31, - .first_byte = 0x0, - - /* the connection request should trigger a connection confirm */ - .write = 1, - .response = &bssmap_cc[0], - .response_length= ARRAY_SIZE(bssmap_cc), - }, - { - .length = ARRAY_SIZE(bssmap_dtap), - .data = &bssmap_dtap[0], - .payload_start = 7, - .payload_length = 15, - .first_byte = 0x01, - }, - { - .length = ARRAY_SIZE(bssmap_clear), - .data = &bssmap_clear[0], - .payload_start = 7, - .payload_length = 6, - .first_byte = 0x00, - }, - { - .length = ARRAY_SIZE(bssmap_released), - .data = &bssmap_released[0], - .payload_length = 2, - .payload_start = 11, - .first_byte = 0x23, - - .write = 1, - .response = &bssmap_release_complete[0], - .response_length= ARRAY_SIZE(bssmap_release_complete), - }, -}; - -/* we will send UDTs and verify they look like this */ -static const struct test_data send_data[] = { - { - .length = ARRAY_SIZE(bssmap_udt), - .data = &bssmap_udt[0], - .payload_start = 12, - .payload_length = ARRAY_SIZE(bssmap_udt) - 12, - .first_byte = 0x0, - }, - { - .length = ARRAY_SIZE(bssmap_reset), - .data = &bssmap_reset[0], - .payload_start = 12, - .payload_length = ARRAY_SIZE(bssmap_reset) - 12, - .first_byte = 0x0, - }, -}; - -struct connection_test { - /* should the connection be refused? */ - int refuse; - - int with_data; - - /* on which side to close the connection? */ - int close_side; - int close_cause; -}; - -/* sccp connection handling we want to test */ -static const struct connection_test connection_tests[] = { - { - .refuse = 1, - }, - { - .refuse = 1, - .with_data = 1, - }, - { - .refuse = 0, - .close_side = 0, - .close_cause = 5, - }, - { - .refuse = 0, - .close_side = 0, - .close_cause = 5, - .with_data = 1, - }, - { - .refuse = 0, - .close_side = 1, - .close_cause = 5, - }, - { - .refuse = 0, - .close_side = 1, - .close_cause = 5, - .with_data = 1, - }, -}; - -struct sccp_parse_header_result { - /* results */ - int msg_type; - int wanted_len; - int src_ssn; - int dst_ssn; - - int has_src_ref, has_dst_ref; - struct sccp_source_reference src_ref; - struct sccp_source_reference dst_ref; - - /* the input */ - const uint8_t *input; - int input_len; -}; - -static const uint8_t it_test[] = { -0x10, 0x01, 0x07, -0x94, 0x01, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00 }; - -static const uint8_t proto_err[] = { -0x0f, 0x0c, 0x04, 0x00, 0x00, -}; - -static const struct sccp_parse_header_result parse_result[] = { - { - .msg_type = SCCP_MSG_TYPE_IT, - .wanted_len = 0, - .src_ssn = -1, - .dst_ssn = -1, - .has_src_ref = 1, - .has_dst_ref = 1, - - .src_ref = { - .octet1 = 0x01, - .octet2 = 0x04, - .octet3 = 0x00 - }, - .dst_ref = { - .octet1 = 0x01, - .octet2 = 0x07, - .octet3 = 0x94, - }, - - .input = it_test, - .input_len = sizeof(it_test), - }, - { - .msg_type = SCCP_MSG_TYPE_ERR, - .wanted_len = 0, - .src_ssn = -1, - .dst_ssn = -1, - .has_src_ref = 0, - .has_dst_ref = 1, - .dst_ref = { - .octet1 = 0x0c, - .octet2 = 0x04, - .octet3 = 0x00, - }, - .input = proto_err, - .input_len = sizeof(proto_err), - }, -}; - - -/* testing procedure: - * - we will use sccp_write and see what will be set in the - * outgoing callback - * - we will call sccp_system_incoming and see which calls - * are made. And then compare it to the ones we expect. We - * want the payload to arrive, or callbacks to be called. - * - we will use sccp_connection_socket and sccp_connection_write - * and verify state handling of connections - */ - -static int current_test; - -/* - * test state... - */ -static int called = 0; -static int matched = 0; -static int write_called = 0; - -#define FAIL(x, args...) printf("FAILURE in %s:%d: " x, __FILE__, __LINE__, ## args) - -/* - * writing these packets and expecting a result - */ -int sccp_read_cb(struct msgb *data, unsigned len, void *context) -{ - uint16_t payload_length = test_data[current_test].payload_length; - const uint8_t *got, *wanted; - int i; - - called = 1; - - if (msgb_l3len(data) < len) { - /* this should never be reached */ - FAIL("Something horrible happened.. invalid packet..\n"); - exit(-1); - } - - if (len == 0 || len != payload_length) { - FAIL("length mismatch: got: %d wanted: %d\n", msgb_l3len(data), payload_length); - return -1; - } - - if (data->l3h[0] != test_data[current_test].first_byte) { - FAIL("The first bytes of l3 do not match: 0x%x 0x%x\n", - data->l3h[0], test_data[current_test].first_byte); - return -1; - } - - got = &data->l3h[0]; - wanted = test_data[current_test].data + test_data[current_test].payload_start; - - for (i = 0; i < len; ++i) { - if (got[i] != wanted[i]) { - FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n", - got[i], wanted[i], i); - return -1; - } - } - - matched = 1; - return 0; -} - -void sccp_write_cb(struct msgb *data, void *ctx) -{ - int i = 0; - const uint8_t *got, *wanted; - - if (test_data[current_test].response == NULL) { - FAIL("Didn't expect write callback\n"); - goto exit; - } else if (test_data[current_test].response_length != msgb_l2len(data)) { - FAIL("Size does not match. Got: %d Wanted: %d\n", - msgb_l2len(data), test_data[current_test].response_length); - } - - got = &data->l2h[0]; - wanted = test_data[current_test].response; - - for (i = 0; i < msgb_l2len(data); ++i) { - if (got[i] != wanted[i]) { - FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n", - got[i], wanted[i], i); - goto exit; - } - } - - write_called = 1; - -exit: - msgb_free(data); -} - -void sccp_c_read(struct sccp_connection *connection, struct msgb *msgb, unsigned int len) -{ - sccp_read_cb(msgb, len, connection->data_ctx); -} - -void sccp_c_state(struct sccp_connection *connection, int old_state) -{ - if (connection->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) - sccp_connection_free(connection); -} - -int sccp_accept_cb(struct sccp_connection *connection, void *user_data) -{ - called = 1; - unsigned int ref = 0; - ref |= connection->destination_local_reference.octet1 << 24; - ref |= connection->destination_local_reference.octet2 << 16; - ref |= connection->destination_local_reference.octet3 << 8; - ref = ntohl(ref); - - connection->data_cb = sccp_c_read; - connection->state_cb = sccp_c_state; - - /* accept this */ - return 0; -} - -static void sccp_udt_write_cb(struct msgb *data, void *context) -{ - const uint8_t *got, *wanted; - int i; - - write_called = 1; - - if (send_data[current_test].length != msgb_l2len(data)) { - FAIL("Size does not match. Got: %d Wanted: %d\n", - msgb_l2len(data), send_data[current_test].length); - goto exit; - } - - got = &data->l2h[0]; - wanted = send_data[current_test].data; - - for (i = 0; i < msgb_l2len(data); ++i) { - if (got[i] != wanted[i]) { - FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n", - got[i], wanted[i], i); - goto exit; - } - } - - matched = 1; - -exit: - msgb_free(data); -} - -static void test_sccp_system(void) -{ - sccp_system_init(sccp_write_cb, NULL); - sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL); - sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL); - - for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) { - unsigned int length = test_data[current_test].length; - struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__); - msg->l2h = msgb_put(msg, length); - memcpy(msg->l2h, test_data[current_test].data, length); - - called = matched = write_called = 0; - printf("Testing packet: %d\n", current_test); - sccp_system_incoming(msg); - - if (!called || !matched || (test_data[current_test].write != write_called)) - FAIL("current test: %d called: %d matched: %d write: %d\n", - current_test, called, matched, write_called); - - msgb_free(msg); - } -} - -/* test sending of udt */ -static void test_sccp_send_udt(void) -{ - sccp_system_init(sccp_udt_write_cb, NULL); - sccp_set_read(NULL, NULL, NULL); - sccp_connection_set_incoming(NULL, NULL, NULL); - - for (current_test = 0; current_test < ARRAY_SIZE(send_data); ++current_test) { - const struct test_data *test = &send_data[current_test]; - - struct msgb *msg = msgb_alloc(test->payload_length, __func__); - msg->l3h = msgb_put(msg, test->payload_length); - memcpy(msg->l3h, test->data + test->payload_start, test->payload_length); - - matched = write_called = 0; - printf("Testing packet: %d\n", current_test); - sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0); - - if (!matched || !write_called) - FAIL("current test: %d matched: %d write: %d\n", - current_test, matched, write_called); - - msgb_free(msg); - } -} - -/* send udt from one end to another */ -static unsigned int test_value = 0x2442; -static int sccp_udt_read(struct msgb *data, unsigned int len, void *context) -{ - unsigned int *val; - - if (len != 4) { - FAIL("Wrong size: %d\n", msgb_l3len(data)); - return -1; - } - - val = (unsigned int*)data->l3h; - matched = test_value == *val; - - return 0; -} - -static void sccp_write_loop(struct msgb *data, void *context) -{ - /* send it back to us */ - sccp_system_incoming(data); - msgb_free(data); -} - -static void test_sccp_udt_communication(void) -{ - struct msgb *data; - unsigned int *val; - - sccp_system_init(sccp_write_loop, NULL); - sccp_set_read(&sccp_ssn_bssap, sccp_udt_read, NULL); - sccp_connection_set_incoming(NULL, NULL, NULL); - - - data = msgb_alloc(4, "test data"); - data->l3h = &data->data[0]; - val = (unsigned int *)msgb_put(data, 4); - *val = test_value; - - matched = 0; - sccp_write(data, &sccp_ssn_bssap, &sccp_ssn_bssap, 0); - - if (!matched) - FAIL("Talking with us didn't work\n"); - - msgb_free(data); -} - - -/* connection testing... open, send, close */ -static const struct connection_test *current_con_test; -static struct sccp_connection *outgoing_con; -static struct sccp_connection *incoming_con; -static int outgoing_data, incoming_data, incoming_state, outgoing_state; - -static struct msgb *test_data1, *test_data2, *test_data3; - -static void sccp_conn_in_state(struct sccp_connection *conn, int old_state) -{ - printf("\tincome: %d -> %d\n", old_state, conn->connection_state); - if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { - if (conn == incoming_con) { - sccp_connection_free(conn); - incoming_con = NULL; - } - } -} - -static void sccp_conn_in_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len) -{ - /* compare the data */ - ++incoming_data; - printf("\tincoming data: %d\n", len); - - /* compare the data */ - if (len != 4) { - FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len); - return; - } - - if (incoming_data == 1) { - if (memcmp(msg->l3h, test_data1->l3h, len) != 0) { - FAIL("Comparing the data failed: %d\n", incoming_data); - incoming_state = 0; - printf("Got: %s\n", hexdump(msg->l3h, len)); - printf("Wanted: %s\n", hexdump(test_data1->l3h, len)); - - } - } else if (incoming_data == 2) { - if (memcmp(msg->l3h, test_data2->l3h, len) != 0) { - FAIL("Comparing the data failed: %d\n", incoming_data); - incoming_state = 0; - printf("Got: %s\n", hexdump(msg->l3h, len)); - printf("Wanted: %s\n", hexdump(test_data2->l3h, len)); - } - } - - /* sending out data */ - if (incoming_data == 2) { - printf("\tReturning data3\n"); - sccp_connection_write(conn, test_data3); - } -} - -static int sccp_conn_accept(struct sccp_connection *conn, void *ctx) -{ - printf("\taccept: %p\n", conn); - conn->state_cb = sccp_conn_in_state; - conn->data_cb = sccp_conn_in_data; - - if (current_con_test->refuse) - return -1; - - incoming_con = conn; - return 0; -} - -/* callbacks for the outgoing side */ -static void sccp_conn_out_state(struct sccp_connection *conn, int old_state) -{ - printf("\toutgoing: %p %d -> %d\n", conn, old_state, conn->connection_state); - - if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { - if (conn == outgoing_con) { - sccp_connection_free(conn); - outgoing_con = NULL; - } - } -} - -static void sccp_conn_out_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len) -{ - ++outgoing_data; - printf("\toutgoing data: %p %d\n", conn, len); - - if (len != 4) - FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len); - - if (outgoing_data == 1) { - if (memcmp(msg->l3h, test_data3->l3h, len) != 0) { - FAIL("Comparing the data failed\n"); - outgoing_state = 0; - } - } -} - -static void do_test_sccp_connection(const struct connection_test *test) -{ - int ret; - - current_con_test = test; - outgoing_con = incoming_con = 0; - - outgoing_con = sccp_connection_socket(); - if (!outgoing_con) { - FAIL("Connection is NULL\n"); - return; - } - - outgoing_con->state_cb = sccp_conn_out_state; - outgoing_con->data_cb = sccp_conn_out_data; - outgoing_data = incoming_data = 0; - incoming_state = outgoing_state = 1; - - /* start testing */ - if (test->with_data) { - if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, test_data1) != 0) - FAIL("Binding failed\n"); - } else { - ++incoming_data; - if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, NULL) != 0) - FAIL("Binding failed\n"); - } - - if (test->refuse) { - if (outgoing_con) - FAIL("Outgoing connection should have been refused.\n"); - } else { - if (!incoming_con) - FAIL("Creating incoming didn't work.\n"); - - printf("\tWriting test data2\n"); - sccp_connection_write(outgoing_con, test_data2); - sccp_connection_send_it(outgoing_con); - - /* closing connection */ - if (test->close_side == 0) - ret = sccp_connection_close(outgoing_con, 0); - else - ret = sccp_connection_close(incoming_con, 0); - - if (ret != 0) - FAIL("Closing the connection failed\n"); - } - - /* outgoing should be gone now */ - if (outgoing_con) - FAIL("Outgoing connection was not properly closed\n"); - - if (incoming_con) - FAIL("Incoming connection was not propery closed.\n"); - - if (test->refuse == 0) { - if (outgoing_data != 1 || incoming_data != 2) { - FAIL("Data sending failed: %d/%d %d/%d\n", - outgoing_data, 1, - incoming_data, 2); - } - } - - if (!incoming_state || !outgoing_state) - FAIL("Failure with the state transition. %d %d\n", - outgoing_state, incoming_state); -} - -static void test_sccp_connection(void) -{ - sccp_system_init(sccp_write_loop, NULL); - sccp_set_read(NULL, NULL, NULL); - sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_conn_accept, NULL); - - test_data1 = msgb_alloc(4, "data1"); - test_data1->l3h = msgb_put(test_data1, 4); - *((unsigned int*)test_data1->l3h) = 0x23421122; - - test_data2 = msgb_alloc(4, "data2"); - test_data2->l3h = msgb_put(test_data2, 4); - *((unsigned int*)test_data2->l3h) = 0x42232211; - - test_data3 = msgb_alloc(4, "data3"); - test_data3->l3h = msgb_put(test_data3, 4); - *((unsigned int*)test_data3->l3h) = 0x2323ff55; - - - for (current_test = 0; current_test < ARRAY_SIZE(connection_tests); ++current_test) { - printf("Testing %d refuse: %d with_data: %d\n", - current_test, connection_tests[current_test].refuse, - connection_tests[current_test].with_data); - do_test_sccp_connection(&connection_tests[current_test]); - } - - msgb_free(test_data1); - msgb_free(test_data2); - msgb_free(test_data3); -} - -/* invalid input */ -static void test_sccp_system_crash(void) -{ - printf("trying to provoke a crash with invalid input\n"); - sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL); - sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL); - - for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) { - int original_length = test_data[current_test].length; - int length = original_length + 2; - int i; - - printf("Testing packet: %d\n", current_test); - - for (i = length; i >= 0; --i) { - unsigned int length = MIN(test_data[current_test].length, i); - struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__); - msg->l2h = msgb_put(msg, length); - memcpy(msg->l2h, test_data[current_test].data, length); - sccp_system_incoming(msg); - msgb_free(msg); - } - } - - printf("survived\n"); -} - -static void test_sccp_parsing(void) -{ - for (current_test = 0; current_test < ARRAY_SIZE(parse_result); ++current_test) { - struct msgb *msg; - struct sccp_parse_result result; - - msg = msgb_alloc_headroom(1024, 128, "parse-test"); - msgb_put(msg, 1); - msg->l2h = msgb_put(msg, parse_result[current_test].input_len); - memcpy(msg->l2h, parse_result[current_test].input, msgb_l2len(msg)); - - memset(&result, 0, sizeof(result)); - if (sccp_parse_header(msg, &result) != 0) { - fprintf(stderr, "Failed to sccp parse test: %d\n", current_test); - } else { - if (parse_result[current_test].wanted_len != result.data_len) { - fprintf(stderr, "Unexpected data length.\n"); - abort(); - } - - if (parse_result[current_test].has_src_ref) { - if (memcmp(result.source_local_reference, - &parse_result[current_test].src_ref, - sizeof(struct sccp_source_reference)) != 0) { - fprintf(stderr, "SRC REF did not match\n"); - abort(); - } - } - - if (parse_result[current_test].has_dst_ref) { - if (memcmp(result.destination_local_reference, - &parse_result[current_test].dst_ref, - sizeof(struct sccp_source_reference)) != 0) { - fprintf(stderr, "DST REF did not match\n"); - abort(); - } - } - - if (parse_result[current_test].src_ssn != -1) { - fprintf(stderr, "Not implemented.\n"); - abort(); - } - - if (parse_result[current_test].dst_ssn != -1) { - fprintf(stderr, "Not implemented.\n"); - abort(); - } - } - - msgb_free(msg); - } -} - - -int main(int argc, char **argv) -{ - test_sccp_system(); - test_sccp_send_udt(); - test_sccp_udt_communication(); - test_sccp_connection(); - test_sccp_system_crash(); - test_sccp_parsing(); - return 0; -} - -void db_store_counter() {}