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
This commit is contained in:
Harald Welte 2017-04-03 22:00:45 +02:00
parent d40b9f842b
commit 996defec17
8 changed files with 392 additions and 1 deletions

1
.gitignore vendored
View File

@ -60,6 +60,7 @@ tests/package.m4
tests/testsuite
tests/testsuite.log
examples/m3ua_example
*.pc
config.*

View File

@ -1,7 +1,7 @@
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
SUBDIRS = include src tests
SUBDIRS = include src tests examples
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libosmo-sccp.pc libosmo-mtp.pc libosmo-sigtran.pc libosmo-xua.pc

View File

@ -27,6 +27,7 @@ fi
PKG_PROG_PKG_CONFIG([0.20])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.0.6)
old_LIBS=$LIBS
@ -68,5 +69,6 @@ AC_OUTPUT(
tests/m2ua/Makefile
tests/xua/Makefile
tests/ss7/Makefile
examples/Makefile
Makefile)

11
examples/Makefile.am Normal file
View File

@ -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)

12
examples/internal.h Normal file
View File

@ -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);

98
examples/m3ua_example.c Normal file
View File

@ -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);
}
}

115
examples/sccp_test_server.c Normal file
View File

@ -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;
}

152
examples/sccp_test_vty.c Normal file
View File

@ -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;
}