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:
parent
d40b9f842b
commit
996defec17
|
@ -60,6 +60,7 @@ tests/package.m4
|
|||
tests/testsuite
|
||||
tests/testsuite.log
|
||||
|
||||
examples/m3ua_example
|
||||
|
||||
*.pc
|
||||
config.*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue