From 996defec1733a285f8aad9cfe426606b8dc8899f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 Apr 2017 22:00:45 +0200 Subject: Add example program how to use M3UA+SCCP client and server This is an example tool that can be run either as server (SG) or as client (ASP) with a SCCP+M3UA stacking, and communicate via connectionless and connection-oriented primitives over it Change-Id: Id698ce2da5726e304dfa1773b794671dc80d853c --- examples/Makefile.am | 11 ++++ examples/internal.h | 12 ++++ examples/m3ua_example.c | 98 ++++++++++++++++++++++++++++ examples/sccp_test_server.c | 115 +++++++++++++++++++++++++++++++++ examples/sccp_test_vty.c | 152 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 388 insertions(+) create mode 100644 examples/Makefile.am create mode 100644 examples/internal.h create mode 100644 examples/m3ua_example.c create mode 100644 examples/sccp_test_server.c create mode 100644 examples/sccp_test_vty.c (limited to 'examples') diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..6418aca --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,11 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMONETIF_CFLAGS) $(COVERAGE_FLAGS) +AM_LDFLAGS=$(COVERAGE_LDFLAGS) + +noinst_HEADERS = internal.h + +noinst_PROGRAMS = m3ua_example + +m3ua_example_SOURCES = m3ua_example.c sccp_test_server.c sccp_test_vty.c +m3ua_example_LDADD = $(top_builddir)/src/libosmo-sigtran.la \ + $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) diff --git a/examples/internal.h b/examples/internal.h new file mode 100644 index 0000000..70b9058 --- /dev/null +++ b/examples/internal.h @@ -0,0 +1,12 @@ +#pragma once + +#define SSN_TEST_UNUSED 200 +#define SSN_TEST_REFUSE 201 +#define SSN_TEST_ECHO 202 +#define SSN_TEST_CALLBACK 203 + +struct osmo_sccp_user; + +int sccp_test_user_vty_install(struct osmo_sccp_instance *inst, int ssn); + +int sccp_test_server_init(struct osmo_sccp_instance *sccp); diff --git a/examples/m3ua_example.c b/examples/m3ua_example.c new file mode 100644 index 0000000..d7b1fc2 --- /dev/null +++ b/examples/m3ua_example.c @@ -0,0 +1,98 @@ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "internal.h" + +static struct osmo_sccp_instance *sua_server_helper(void) +{ + struct osmo_sccp_instance *sccp; + + sccp = osmo_sccp_simple_server(NULL, 1, OSMO_SS7_ASP_PROT_M3UA, + -1, "127.0.0.2"); + + osmo_sccp_simple_server_add_clnt(sccp, OSMO_SS7_ASP_PROT_M3UA, + "23", 23, -1, 0, NULL); + + return sccp; +} + +/*********************************************************************** + * Initialization + ***********************************************************************/ + +static const struct log_info_cat log_info_cat[] = { +}; + +static const struct log_info log_info = { + .cat = log_info_cat, + .num_cat = ARRAY_SIZE(log_info_cat), +}; + +static void init_logging(void) +{ + const int log_cats[] = { DLSS7, DLSUA, DLM3UA, DLSCCP, DLINP }; + unsigned int i; + + osmo_init_logging(&log_info); + + for (i = 0; i < ARRAY_SIZE(log_cats); i++) + log_set_category_filter(osmo_stderr_target, log_cats[i], 1, LOGL_DEBUG); +} + +static struct vty_app_info vty_info = { + .name = "sccp-test", + .version = 0, +}; + +int main(int argc, char **argv) +{ + struct osmo_sccp_instance *sccp; + bool client; + int rc; + + init_logging(); + osmo_ss7_init(); + osmo_fsm_log_addr(false); + vty_init(&vty_info); + + if (argc <= 1) + client = true; + else + client = false; + + rc = telnet_init_dynif(NULL, NULL, vty_get_bind_addr(), 2324+client); + if (rc < 0) { + perror("Erro binding VTY port\n"); + exit(1); + } + + + if (client) { + sccp = osmo_sccp_simple_client(NULL, "client", 23, OSMO_SS7_ASP_PROT_M3UA, 0, M3UA_PORT, "127.0.0.2"); + sccp_test_user_vty_install(sccp, OSMO_SCCP_SSN_BSC_BSSAP); + } else { + sccp = sua_server_helper(); + sccp_test_server_init(sccp); + } + + while (1) { + osmo_select_main(0); + } +} diff --git a/examples/sccp_test_server.c b/examples/sccp_test_server.c new file mode 100644 index 0000000..c3c658f --- /dev/null +++ b/examples/sccp_test_server.c @@ -0,0 +1,115 @@ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "internal.h" + +unsigned int conn_id; + +/* a simple SCCP User which refuses all connections and discards all + * unitdata */ +static int refuser_prim_cb(struct osmo_prim_hdr *oph, void *_scu) +{ + struct osmo_sccp_user *scu = _scu; + struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *) oph; + + switch (OSMO_PRIM_HDR(&scu_prim->oph)) { + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): + printf("%s: refusing N-CONNECT.ind (local_ref=%u)\n", + __func__, scu_prim->u.connect.conn_id); + osmo_sccp_tx_disconn(scu, scu_prim->u.connect.conn_id, + &scu_prim->u.connect.called_addr, + 23); + break; + default: + printf("%s: Unknown primitive %u:%u\n", __func__, + oph->primitive, oph->operation); + break; + } + return 0; +} + +/* a simple SCCP User which accepts all connections and echos back all + * DATA + UNITDATA */ +static int echo_prim_cb(struct osmo_prim_hdr *oph, void *_scu) +{ + struct osmo_sccp_user *scu = _scu; + struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *) oph; + const uint8_t *data = msgb_l2(oph->msg); + unsigned int data_len = msgb_l2len(oph->msg); + + switch (OSMO_PRIM_HDR(&scu_prim->oph)) { + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): + printf("%s: Accepting N-CONNECT.ind (local_ref=%u)\n", + __func__, scu_prim->u.connect.conn_id); + osmo_sccp_tx_conn_resp(scu, scu_prim->u.connect.conn_id, + &scu_prim->u.connect.called_addr, + data, data_len); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION): + printf("%s: Echoing N-DATA.ind (local_ref=%u)\n", + __func__, scu_prim->u.data.conn_id); + osmo_sccp_tx_data(scu, scu_prim->u.data.conn_id, + data, data_len); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION): + printf("%s: Echoing N-UNITDATA.ind\n", __func__); + osmo_sccp_tx_unitdata(scu, &scu_prim->u.unitdata.called_addr, + &scu_prim->u.unitdata.calling_addr, + data, data_len); + break; + default: + printf("%s: Unknown primitive %u:%u\n", __func__, + oph->primitive, oph->operation); + break; + } + return 0; +} + +/* a simple SCCP User which receives UNITDATA messages and connects back + * to whoever sents UNITDATA and then echo's back all DATA */ +static int callback_prim_cb(struct osmo_prim_hdr *oph, void *_scu) +{ + struct osmo_sccp_user *scu = _scu; + struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *) oph; + const uint8_t *data = msgb_l2(oph->msg); + unsigned int data_len = msgb_l2len(oph->msg); + + switch (OSMO_PRIM_HDR(&scu_prim->oph)) { + case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION): + printf("%s: N-UNITDATA.ind: Connectiong back to sender\n", __func__); + osmo_sccp_tx_conn_req(scu, conn_id++, + &scu_prim->u.unitdata.called_addr, + &scu_prim->u.unitdata.calling_addr, + data, data_len); + break; + case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION): + printf("%s: Echoing N-DATA.ind (local_ref=%u)\n", + __func__, scu_prim->u.data.conn_id); + osmo_sccp_tx_data(scu, scu_prim->u.data.conn_id, + data, data_len); + break; + default: + printf("%s: Unknown primitive %u:%u\n", __func__, + oph->primitive, oph->operation); + break; + } + return 0; +} + +int sccp_test_server_init(struct osmo_sccp_instance *sccp) +{ + osmo_sccp_user_bind(sccp, "refuser", &refuser_prim_cb, SSN_TEST_REFUSE); + osmo_sccp_user_bind(sccp, "echo", &echo_prim_cb, SSN_TEST_ECHO); + osmo_sccp_user_bind(sccp, "callback", &callback_prim_cb, SSN_TEST_CALLBACK); + + return 0; +} diff --git a/examples/sccp_test_vty.c b/examples/sccp_test_vty.c new file mode 100644 index 0000000..1134d57 --- /dev/null +++ b/examples/sccp_test_vty.c @@ -0,0 +1,152 @@ + +#include + +#include +#include + +#include +#include + +#include "internal.h" + +#define SCU_NODE 23 + +static struct osmo_sccp_user *g_scu; + +static struct osmo_sccp_addr g_calling_addr = { + .presence = OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC, + .ri = OSMO_SCCP_RI_SSN_PC, + .pc = 23, +}; + +static struct osmo_sccp_addr g_called_addr = { + .presence = OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC, + .ssn = 1, + .ri = OSMO_SCCP_RI_SSN_PC, + .pc = 1, +}; + +DEFUN(scu_called_ssn, scu_called_ssn_cmd, + "called-addr-ssn <0-255>", + "Set SSN of SCCP CalledAddress\n" + "SSN of SCCP CalledAddress\n") +{ + g_called_addr.ssn = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(scu_conn_req, scu_conn_req_cmd, + "connect-req <0-16777216> [DATA]", + "N-CONNECT.req\n" + "Connection ID\n") +{ + struct osmo_sccp_user *scu = vty->index; + int conn_id = atoi(argv[0]); + const char *data = argv[1]; + + osmo_sccp_tx_conn_req(scu, conn_id, &g_calling_addr, &g_called_addr, + (const uint8_t *)data, data ? strlen(data)+1 : 0); + return CMD_SUCCESS; +} + +DEFUN(scu_conn_resp, scu_conn_resp_cmd, + "connect-resp <0-16777216> [DATA]", + "N-CONNET.resp\n" + "Connection ID\n") +{ + struct osmo_sccp_user *scu = vty->index; + int conn_id = atoi(argv[0]); + const char *data = argv[1]; + + osmo_sccp_tx_conn_resp(scu, conn_id, NULL, + (const uint8_t *)data, data ? strlen(data)+1 : 0); + return CMD_SUCCESS; +} + +DEFUN(scu_data_req, scu_data_req_cmd, + "data-req <0-16777216> DATA", + "N-DATA.req\n" + "Connection ID\n") +{ + struct osmo_sccp_user *scu = vty->index; + int conn_id = atoi(argv[0]); + const char *data = argv[1]; + + osmo_sccp_tx_data(scu, conn_id, (const uint8_t *)data, strlen(data)+1); + return CMD_SUCCESS; +} + +DEFUN(scu_unitdata_req, scu_unitdata_req_cmd, + "unitdata-req DATA", + "N-UNITDATA.req\n") +{ + struct osmo_sccp_user *scu = vty->index; + const char *data = argv[0]; + + osmo_sccp_tx_unitdata(scu, &g_calling_addr, &g_called_addr, + (const uint8_t *)data, strlen(data)+1); + return CMD_SUCCESS; +} + +DEFUN(scu_disc_req, scu_disc_req_cmd, + "disconnect-req <0-16777216>", + "N-DISCONNT.req\n" + "Connection ID\n") +{ + struct osmo_sccp_user *scu = vty->index; + int conn_id = atoi(argv[0]); + + osmo_sccp_tx_disconn(scu, conn_id, NULL, 42); + return CMD_SUCCESS; +} + +static struct cmd_node scu_node = { + SCU_NODE, + "%s(sccp-user)# ", + 1, +}; + +DEFUN(scu, scu_cmd, + "sccp-user", + "Enter SCCP User Node\n") +{ + vty->node = SCU_NODE; + vty->index = g_scu; + return CMD_SUCCESS; +} + +static int testclnt_prim_cb(struct osmo_prim_hdr *oph, void *_scu) +{ + struct osmo_sccp_user *scu = _scu; + struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *) oph; + + switch (OSMO_PRIM_HDR(&scu_prim->oph)) { + case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): + default: + break; + } + return 0; +} + + +int sccp_test_user_vty_install(struct osmo_sccp_instance *inst, int ssn) +{ + g_scu = osmo_sccp_user_bind(inst, "test_client_vty", testclnt_prim_cb, ssn); + if (!g_scu) + return -1; + + g_calling_addr.ssn = ssn; + + install_node(&scu_node, NULL); + vty_install_default(SCU_NODE); + install_element(SCU_NODE, &scu_called_ssn_cmd); + install_element(SCU_NODE, &scu_conn_req_cmd); + install_element(SCU_NODE, &scu_conn_resp_cmd); + install_element(SCU_NODE, &scu_data_req_cmd); + install_element(SCU_NODE, &scu_unitdata_req_cmd); + install_element(SCU_NODE, &scu_disc_req_cmd); + + install_element(ENABLE_NODE, &scu_cmd); + + return 0; +} -- cgit v1.2.3