summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-04-03 22:00:45 +0200
committerHarald Welte <laforge@gnumonks.org>2017-04-10 11:48:34 +0200
commit996defec1733a285f8aad9cfe426606b8dc8899f (patch)
tree9a58743adcd14da6b7dcd80ed6da2229d1ccc4d9 /examples
parentd40b9f842bb58b393c8a32142296517e328520e4 (diff)
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
Diffstat (limited to 'examples')
-rw-r--r--examples/Makefile.am11
-rw-r--r--examples/internal.h12
-rw-r--r--examples/m3ua_example.c98
-rw-r--r--examples/sccp_test_server.c115
-rw-r--r--examples/sccp_test_vty.c152
5 files changed, 388 insertions, 0 deletions
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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/fsm.h>
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/telnet_interface.h>
+
+#include <osmocom/sigtran/osmo_ss7.h>
+#include <osmocom/sigtran/sccp_sap.h>
+#include <osmocom/sigtran/sccp_helpers.h>
+#include <osmocom/sigtran/protocol/sua.h>
+#include <osmocom/sigtran/protocol/m3ua.h>
+
+#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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/logging.h>
+
+#include <osmocom/sigtran/sccp_sap.h>
+#include <osmocom/sigtran/sccp_helpers.h>
+
+#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 <string.h>
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+
+#include <osmocom/sigtran/sccp_sap.h>
+#include <osmocom/sigtran/sccp_helpers.h>
+
+#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;
+}