gerrit-log
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
January 2022
- 3 participants
- 781 discussions
Change in osmo-ccid-firmware[master]: add simple gangupdater for multiple octsim boards
by roh 15 Mar '25
by roh 15 Mar '25
15 Mar '25
roh has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/26896 )
Change subject: add simple gangupdater for multiple octsim boards
......................................................................
add simple gangupdater for multiple octsim boards
Change-Id: Ic10572c121ac55586ec43126b63d69529757132b
---
A contrib/flash_all_octsim.sh
1 file changed, 22 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/96/26896/1
diff --git a/contrib/flash_all_octsim.sh b/contrib/flash_all_octsim.sh
new file mode 100644
index 0000000..4f4c89b
--- /dev/null
+++ b/contrib/flash_all_octsim.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# this script is to scan for octsim boards, sort them by usb path and call dfu-util on each to update the board
+# basic flow
+# - get usb path and serialno tupel from dfu-util -l
+# - reformat and sort by usbpath, drop the usbpath (grep cut tr sort cut)
+# - flash the boards
+
+# TODO:
+# - error handling
+# - filter dfu-util output and generate nice summary
+
+dfu-util -l \
+ | grep "^Found" \
+ | grep "\[1d50:6141\]" \
+ | cut -d ' ' -f 8,13 \
+ | tr -d ',' \
+ | cut -d \" -f 2,4 \
+ | tr \" ' ' \
+ | sort \
+ | cut -d ' ' -f 2
+ | xargs -n 1 dfu-util -d 1d50:6141 -D sysmoOCTSIM.bin -R -p
--
To view, visit https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/26896
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-ccid-firmware
Gerrit-Branch: master
Gerrit-Change-Id: Ic10572c121ac55586ec43126b63d69529757132b
Gerrit-Change-Number: 26896
Gerrit-PatchSet: 1
Gerrit-Owner: roh <jsteiger(a)sysmocom.de>
Gerrit-MessageType: newchange
2
2
Change in simtrace2[master]: simtrace2-tool: hack: kick the comms by sending a fake message
by James Tavares 22 Nov '22
by James Tavares 22 Nov '22
22 Nov '22
James Tavares has uploaded this change for review. ( https://gerrit.osmocom.org/c/simtrace2/+/26864 )
Change subject: simtrace2-tool: hack: kick the comms by sending a fake message
......................................................................
simtrace2-tool: hack: kick the comms by sending a fake message
This is a workaround until the root cause of the communications failure
between simtrace2-tool and simtrace2 firmware is identified. Additional
details provided on simtrace mailing list.
Change-Id: I40fa06bee5d8194516497e16597e069124ddf0fb
---
M host/include/osmocom/simtrace2/simtrace2_api.h
M host/lib/simtrace2_api.c
M host/src/simtrace2-tool.c
3 files changed, 23 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/simtrace2 refs/changes/64/26864/1
diff --git a/host/include/osmocom/simtrace2/simtrace2_api.h b/host/include/osmocom/simtrace2/simtrace2_api.h
index d658d16..3a7e5ae 100644
--- a/host/include/osmocom/simtrace2/simtrace2_api.h
+++ b/host/include/osmocom/simtrace2/simtrace2_api.h
@@ -44,6 +44,7 @@
int osmo_st2_slot_tx_msg(struct osmo_st2_slot *slot, struct msgb *msg,
uint8_t msg_class, uint8_t msg_type);
+int osmo_st2_generic_do_error_none(struct osmo_st2_cardem_inst *ci);
int osmo_st2_cardem_request_card_insert(struct osmo_st2_cardem_inst *ci, bool inserted);
int osmo_st2_cardem_request_pb_and_rx(struct osmo_st2_cardem_inst *ci, uint8_t pb, uint8_t le);
diff --git a/host/lib/simtrace2_api.c b/host/lib/simtrace2_api.c
index 4ad7eb7..beb6de4 100644
--- a/host/lib/simtrace2_api.c
+++ b/host/lib/simtrace2_api.c
@@ -155,6 +155,24 @@
}
/***********************************************************************
+ * Generic protocol
+ ***********************************************************************/
+
+/*! \brief Send an empty DO_ERROR message to the simtrace2 board */
+int osmo_st2_generic_do_error_none(struct osmo_st2_cardem_inst *ci)
+{
+ struct msgb *msg = st_msgb_alloc();
+ struct cardemu_usb_msg_error *err;
+
+ LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s\n", __func__);
+
+ err = (struct cardemu_usb_msg_error *) msgb_put(msg, sizeof(*err));
+ memset(err, 0, sizeof(*err));
+
+ return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_GENERIC, SIMTRACE_CMD_DO_ERROR);
+}
+
+/***********************************************************************
* Card Emulation protocol
***********************************************************************/
diff --git a/host/src/simtrace2-tool.c b/host/src/simtrace2-tool.c
index d92638f..407eac9 100644
--- a/host/src/simtrace2-tool.c
+++ b/host/src/simtrace2-tool.c
@@ -297,6 +297,10 @@
fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
goto close_exit;
}
+
+ // HACK: kick the board with a fake message to get subsequent messages to be accepted
+ // TODO: figure out the real problem, and remove this
+ osmo_st2_generic_do_error_none(ci);
}
if (argc - optind <= 0) {
--
To view, visit https://gerrit.osmocom.org/c/simtrace2/+/26864
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: simtrace2
Gerrit-Branch: master
Gerrit-Change-Id: I40fa06bee5d8194516497e16597e069124ddf0fb
Gerrit-Change-Number: 26864
Gerrit-PatchSet: 1
Gerrit-Owner: James Tavares <jtavares(a)kvh.com>
Gerrit-MessageType: newchange
3
5
Build failed in Jenkins: master-osmo-opencm3-projects » a1=default,a2=default,a3=default,a4=default,osmocom-master-debian9 #19
by jenkins@lists.osmocom.org 28 Mar '22
by jenkins@lists.osmocom.org 28 Mar '22
28 Mar '22
See <https://jenkins.osmocom.org/jenkins/job/master-osmo-opencm3-projects/a1=def…>
Changes:
------------------------------------------
Started by upstream project "master-osmo-opencm3-projects" build number 19
originally caused by:
Started by an SCM change
Running as SYSTEM
Building remotely on build2-deb9build-ansible (ttcn3 osmocom-gerrit-debian9 osmocom-master-debian9 repo-install-test coverity) in workspace <https://jenkins.osmocom.org/jenkins/job/master-osmo-opencm3-projects/a1=def…>
The recommended git tool is: NONE
No credentials specified
Cloning the remote Git repository
Cloning repository git://git.osmocom.org/osmo-opencm3-projects
> git init <https://jenkins.osmocom.org/jenkins/job/master-osmo-opencm3-projects/a1=def…> # timeout=10
Fetching upstream changes from git://git.osmocom.org/osmo-opencm3-projects
> git --version # timeout=10
> git --version # 'git version 2.11.0'
> git fetch --tags --progress -- git://git.osmocom.org/osmo-opencm3-projects +refs/heads/*:refs/remotes/origin/* # timeout=10
> git config remote.origin.url git://git.osmocom.org/osmo-opencm3-projects # timeout=10
> git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
Avoid second fetch
Checking out Revision 7527cab6d8364b2022bd4fa2fd03039eac2a99bb (refs/remotes/origin/master)
> git config core.sparsecheckout # timeout=10
> git checkout -f 7527cab6d8364b2022bd4fa2fd03039eac2a99bb # timeout=10
Commit message: "add missing libcommon.mk"
First time build. Skipping changelog.
> git remote # timeout=10
> git submodule init # timeout=10
> git submodule sync # timeout=10
> git config --get remote.origin.url # timeout=10
> git submodule init # timeout=10
> git config -f .gitmodules --get-regexp ^submodule\.(.+)\.url # timeout=10
> git config --get submodule.libopencm3.url # timeout=10
> git config -f .gitmodules --get submodule.libopencm3.path # timeout=10
> git config --get submodule.librfn.url # timeout=10
> git config -f .gitmodules --get submodule.librfn.path # timeout=10
> git submodule update --init --recursive libopencm3 # timeout=10
> git submodule update --init --recursive librfn # timeout=10
[osmocom-master-debian9] $ /bin/sh -xe /tmp/jenkins5762361540671398993.sh
+ ARTIFACT_STORE=/home/osmocom-build/jenkins_build_artifact_store
+ mkdir -p /home/osmocom-build/jenkins_build_artifact_store
+ docker run --rm=true --cap-add SYS_PTRACE -e ARTIFACT_STORE=/artifact_store -e ASCIIDOC_WARNINGS_CHECK=1 -e HOME=/build -e JOB_NAME=master-osmo-opencm3-projects/a1=default,a2=default,a3=default,a4=default,label=osmocom-master-debian9 -e MAKE=make -e OSMOPY_DEBUG_TCP_SOCKETS=1 -e OSMO_GSM_MANUALS_DIR=/opt/osmo-gsm-manuals -e PARALLEL_MAKE=-j 8 -e PUBLISH=1 -e WITH_MANUALS=1 -w /build -i -u build -v <https://jenkins.osmocom.org/jenkins/job/master-osmo-opencm3-projects/a1=def…>:/build -v /home/osmocom-build/jenkins_build_artifact_store:/artifact_store -v /home/osmocom-build/.ssh:/home/build/.ssh:ro osmocom-build/debian-stretch-jenkins /build/contrib/jenkins.sh --publish
=============== relay-driver START ==============
CLEAN
CC console.c
arm-none-eabi-gcc: error: /usr/lib/picolibc/arm-none-eabi/picolibc.specs: No such file or directory
../../mk/libopencm3.mk:227: recipe for target 'console.o' failed
make: *** [console.o] Error 1
Build step 'Execute shell' marked build as failure
1
29
Change in simtrace2[master]: firmware: bugfix: disable cardemu comms in local SIM mode
by James Tavares 24 Mar '22
by James Tavares 24 Mar '22
24 Mar '22
James Tavares has uploaded this change for review. ( https://gerrit.osmocom.org/c/simtrace2/+/26865 )
Change subject: firmware: bugfix: disable cardemu comms in local SIM mode
......................................................................
firmware: bugfix: disable cardemu comms in local SIM mode
This change prevents contention on the ISO7816 bus by disabling the card emulation state machine when the SIM switch is in the local mode. Without this change, the card emulation firmware can clobber ISO7816 communications and cause contention with certain (but not all) SIM cards.
Changes:
- Add 'enabled' flag to cardemu instance that is set/cleared by usb_command_sim_select() (the only place where sim switch occurs).
- Flag is initialized as false (disabled) by default, to match local SIM mode default.
- When card emulation is disabled, force SIM VCC to be "OFF", SIM RESET as "not in RESET", and drop bytes bytes received on the ISO7816 interface (but do service buffers).
Change-Id: I4010f988712eac4a6af8568ccd60062f9de62449
---
M firmware/libcommon/source/mode_cardemu.c
1 file changed, 31 insertions(+), 13 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/simtrace2 refs/changes/65/26865/1
diff --git a/firmware/libcommon/source/mode_cardemu.c b/firmware/libcommon/source/mode_cardemu.c
index 8e4acf9..00a062e 100644
--- a/firmware/libcommon/source/mode_cardemu.c
+++ b/firmware/libcommon/source/mode_cardemu.c
@@ -83,10 +83,21 @@
#ifdef DETECT_VCC_BY_ADC
uint32_t vcc_uv;
#endif
+
+ /*! real-time state of VCC I/O line, irrespective of enabled flag */
bool vcc_active;
+
+ /*! last VCC state we reported to the card emu state machine (conditioned by enabled flag) */
bool vcc_active_last;
+
+ /*! real-time state of RST I/O line, irrespective of enabled flag */
bool rst_active;
+
+ /*! last RST state we reported to the card emu state machine (conditioned by enabled flag) */
bool rst_active_last;
+
+ /*! flag indicating whether this instance should perform card emulation, or not */
+ bool enabled;
};
struct cardem_inst cardem_inst[] = {
@@ -505,19 +516,25 @@
#endif /* DETECT_VCC_BY_ADC */
-/* called from main loop; dispatches card I/O state changes to card_emu from main loop */
+/**
+ * called from main loop; dispatches card I/O state changes to card_emu from main loop.
+ * NOTE: conditions I/O state on the ci->enabled flag; if the instance is disabled, we assume VCC is
+ * disabled and the device is not in reset
+ */
static void process_io_statechg(struct cardem_inst *ci)
{
- if (ci->vcc_active != ci->vcc_active_last) {
- card_emu_io_statechg(ci->ch, CARD_IO_VCC, ci->vcc_active);
+ const bool vcc_active = ci->vcc_active && ci->enabled;
+ if (vcc_active != ci->vcc_active_last) {
+ card_emu_io_statechg(ci->ch, CARD_IO_VCC, vcc_active);
/* FIXME do this for real */
- card_emu_io_statechg(ci->ch, CARD_IO_CLK, ci->vcc_active);
- ci->vcc_active_last = ci->vcc_active;
+ card_emu_io_statechg(ci->ch, CARD_IO_CLK, vcc_active);
+ ci->vcc_active_last = vcc_active;
}
- if (ci->rst_active != ci->rst_active_last) {
- card_emu_io_statechg(ci->ch, CARD_IO_RST, ci->rst_active);
- ci->rst_active_last = ci->rst_active;
+ const bool rst_active = ci->rst_active && ci->enabled;
+ if (rst_active != ci->rst_active_last) {
+ card_emu_io_statechg(ci->ch, CARD_IO_RST, rst_active);
+ ci->rst_active_last = rst_active;
}
}
@@ -764,10 +781,8 @@
if (msgb_l2len(msg) < sizeof(*mss))
return -1;
- if (mss->remote_sim)
- sim_switch_use_physical(ci->num, 0);
- else
- sim_switch_use_physical(ci->num, 1);
+ ci->enabled = mss->remote_sim ? true : false;
+ sim_switch_use_physical(ci->num, !ci->enabled);
return 0;
}
@@ -911,7 +926,10 @@
}
uint8_t byte = rbuf_read(&ci->rb);
__enable_irq();
- card_emu_process_rx_byte(ci->ch, byte);
+
+ if (ci->enabled) {
+ card_emu_process_rx_byte(ci->ch, byte);
+ }
//TRACE_ERROR("%uRx%02x\r\n", i, byte);
}
--
To view, visit https://gerrit.osmocom.org/c/simtrace2/+/26865
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: simtrace2
Gerrit-Branch: master
Gerrit-Change-Id: I4010f988712eac4a6af8568ccd60062f9de62449
Gerrit-Change-Number: 26865
Gerrit-PatchSet: 1
Gerrit-Owner: James Tavares <jtavares(a)kvh.com>
Gerrit-MessageType: newchange
3
6
24 Feb '22
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/26797 )
Change subject: running.adoc: explain MGW configuration
......................................................................
running.adoc: explain MGW configuration
OsmoHNBGW now requires a co-located OsmoMGW instance. Lets add add some
info on how to configure it.
Change-Id: Id47f4f365cee78ce28d1534c4e3e98a59bdb0621
Related: OS#5152
---
M doc/manuals/chapters/running.adoc
1 file changed, 16 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-hnbgw refs/changes/97/26797/1
diff --git a/doc/manuals/chapters/running.adoc b/doc/manuals/chapters/running.adoc
index f40027a..5d3422e 100644
--- a/doc/manuals/chapters/running.adoc
+++ b/doc/manuals/chapters/running.adoc
@@ -117,3 +117,19 @@
local-ip 10.9.8.7
local-port 29169
----
+
+==== Configure co-located media gateway
+
+OsmoHNBGW requires a co-located OsmoMGW instace. The purpose of the co-located
+media gateway is to relay the RTP traffic between hNodeB and core network. The
+configuration is done under the hnbgw node along with iucs and iups.
+
+An example configuration for OsmoHNBGW's MGCP client:
+
+----
+hnbgw
+ mgcp
+ mgw remote-ip 127.0.0.1
+ mgw remote-port 2427
+ mgw reset-endpoint rtpbridge/*
+----
--
To view, visit https://gerrit.osmocom.org/c/osmo-hnbgw/+/26797
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: Id47f4f365cee78ce28d1534c4e3e98a59bdb0621
Gerrit-Change-Number: 26797
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newchange
3
11
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/26796 )
Change subject: overview.adoc: update network diagram
......................................................................
overview.adoc: update network diagram
The network diagram in the manual lacks the recently added co located
MGW.
Change-Id: Ica1782a407f6b944aa26748b54055168f5d250c3
Related: OS#5152
---
M doc/manuals/chapters/overview.adoc
1 file changed, 14 insertions(+), 10 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-hnbgw refs/changes/96/26796/1
diff --git a/doc/manuals/chapters/overview.adoc b/doc/manuals/chapters/overview.adoc
index 2368b4f..fa8dda0 100644
--- a/doc/manuals/chapters/overview.adoc
+++ b/doc/manuals/chapters/overview.adoc
@@ -15,16 +15,20 @@
[[fig-3g]]
.Typical 3G network architecture used with OsmoHNBGW
----
- +------------+ +--------+ +----------+ +---------+
- UE <-->| hNodeB |<--Iuh---->| HNB-GW |<--IuCS-->| OsmoMSC |<--GSUP-->| OsmoHLR |
- UE <-->| femto cell | ...-->| | ...-->| | | |
- | | | | +----------+ +---------|
- +------------+<--GTP-U | |
- \ | | +------+ +------+
- | | |<--IuPS-->| SGSN |<--GTP-C-->| GGSN |
- | +--------+ ...-->| | GTP-U-->| |
- | +------+ / +------+
- \_______________________________/
+ +------------+ +--------+ +---------+ +---------+
+ UE <-->| hNodeB |<----Iuh----->| HNB-GW |<--IuCS-->| OsmoMSC |<--GSUP-->| OsmoHLR |
+ UE <-->| femto cell | | | | | | |
+ | | | | +---------+ +---------+
+ | |<---IuPF--\ | |
+ | |<--GTP-U | | | +------+ +------+
+ +------------+ \ | | |<--IuPS-->| SGSN |<--GTP-C-->| GGSN |
+ | | +--------+ | | GTP-U-->| |
+ | | +------+ / +------+
+ | | +-----+ +-----+ |
+ | \-->| MGW |<----IuPF--->| MGW | |
+ | | | | | |
+ | +-----+ +-----+ |
+ \___________________________________/
----
The HNB-GW performs a translation interface between the IuCS/IuPS interfaces on the one hand
--
To view, visit https://gerrit.osmocom.org/c/osmo-hnbgw/+/26796
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: Ica1782a407f6b944aa26748b54055168f5d250c3
Gerrit-Change-Number: 26796
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: newchange
3
16
24 Feb '22
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/26795 )
Change subject: mgw_fsm: add MGW support to osmo-hnbgw
......................................................................
mgw_fsm: add MGW support to osmo-hnbgw
osmo-hnbgw lacks support for an co-located media gateway. This makes it
virtually impossible to isolate the HNB from the core network properly.
Lets add MGCP support to osmo-hnbgw so that it can control a co-located
media gateway to relay the RTP streams between HNB and core network.
Change-Id: Ib9b62e0145184b91c56ce5d8870760bfa49cc5a4
Related: OS#515
---
M configure.ac
M contrib/osmo-hnbgw.spec.in
M debian/control
M include/osmocom/hnbgw/context_map.h
M include/osmocom/hnbgw/hnbgw.h
A include/osmocom/hnbgw/mgw_fsm.h
A include/osmocom/hnbgw/tdefs.h
M include/osmocom/hnbgw/vty.h
M src/osmo-hnbgw/Makefile.am
M src/osmo-hnbgw/hnbgw.c
M src/osmo-hnbgw/hnbgw_cn.c
M src/osmo-hnbgw/hnbgw_rua.c
M src/osmo-hnbgw/hnbgw_vty.c
A src/osmo-hnbgw/mgw_fsm.c
A src/osmo-hnbgw/tdefs.c
15 files changed, 705 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-hnbgw refs/changes/95/26795/1
diff --git a/configure.ac b/configure.ac
index 4dc8087..f9bca78 100644
--- a/configure.ac
+++ b/configure.ac
@@ -65,7 +65,7 @@
PKG_CHECK_MODULES(LIBOSMORUA, libosmo-rua >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOHNBAP, libosmo-hnbap >= 1.1.0)
-
+PKG_CHECK_MODULES(LIBOSMOMGCPCLIENT, libosmo-mgcp-client >= 1.9.0)
dnl checks for header files
AC_HEADER_STDC
diff --git a/contrib/osmo-hnbgw.spec.in b/contrib/osmo-hnbgw.spec.in
index 5ab0f5a..04fad1f 100644
--- a/contrib/osmo-hnbgw.spec.in
+++ b/contrib/osmo-hnbgw.spec.in
@@ -33,6 +33,7 @@
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libcrypto) >= 0.9.5
+BuildRequires: pkgconfig(libosmo-mgcp-client) >= 1.9.0
BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0
BuildRequires: pkgconfig(libosmo-sigtran) >= 1.5.0
BuildRequires: pkgconfig(libosmoabis) >= 1.2.0
diff --git a/debian/control b/debian/control
index 1ea3ad2..f7b1047 100644
--- a/debian/control
+++ b/debian/control
@@ -18,6 +18,7 @@
libosmo-sigtran-dev (>= 1.5.0),
libosmo-abis-dev (>= 1.2.0),
libosmo-netif-dev (>= 1.1.0),
+ libosmo-mgcp-client-dev (>= 1.9.0),
libosmo-hnbap-dev (>= 1.1.0),
libosmo-ranap-dev (>= 1.1.0),
libosmo-rua-dev (>= 1.1.0),
diff --git a/include/osmocom/hnbgw/context_map.h b/include/osmocom/hnbgw/context_map.h
index 6279b91..6910fe8 100644
--- a/include/osmocom/hnbgw/context_map.h
+++ b/include/osmocom/hnbgw/context_map.h
@@ -35,6 +35,9 @@
uint32_t scu_conn_id;
enum hnbgw_context_map_state state;
+
+ /* FSM instance for the MGW */
+ struct osmo_fsm_inst *mgw_fi;
};
diff --git a/include/osmocom/hnbgw/hnbgw.h b/include/osmocom/hnbgw/hnbgw.h
index fc8298d..9a46301 100644
--- a/include/osmocom/hnbgw/hnbgw.h
+++ b/include/osmocom/hnbgw/hnbgw.h
@@ -16,6 +16,7 @@
DHNBAP,
DRUA,
DRANAP,
+ DMGW,
};
#define LOGHNB(x, ss, lvl, fmt, args ...) \
@@ -133,6 +134,7 @@
bool hnbap_allow_tmsi;
/*! print hnb-id (true) or MCC-MNC-LAC-RAC-SAC (false) in logs */
bool log_prefix_hnb_id;
+ struct mgcp_client_conf *mgcp_client;
} config;
/*! SCTP listen socket for incoming connections */
struct osmo_stream_srv_link *iuh;
@@ -151,6 +153,7 @@
struct osmo_sccp_addr iucs_remote_addr;
struct osmo_sccp_addr iups_remote_addr;
} sccp;
+ struct mgcp_client *mgcp_client;
};
extern void *talloc_asn1_ctx;
diff --git a/include/osmocom/hnbgw/mgw_fsm.h b/include/osmocom/hnbgw/mgw_fsm.h
new file mode 100644
index 0000000..219026d
--- /dev/null
+++ b/include/osmocom/hnbgw/mgw_fsm.h
@@ -0,0 +1,5 @@
+#pragma once
+
+int mgw_fsm_alloc_and_handle_rab_ass_req(struct hnbgw_context_map *map, struct osmo_prim_hdr *oph_rab_ass_req);
+int mgw_fsm_handle_iu_release(struct hnbgw_context_map *map);
+int mgw_fsm_handle_rab_ass_resp(struct hnbgw_context_map *map, struct osmo_prim_hdr *oph);
diff --git a/include/osmocom/hnbgw/tdefs.h b/include/osmocom/hnbgw/tdefs.h
new file mode 100644
index 0000000..4f98a36
--- /dev/null
+++ b/include/osmocom/hnbgw/tdefs.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <osmocom/core/tdef.h>
+
+extern struct osmo_tdef mgw_fsm_T_defs[];
+extern struct osmo_tdef_group hnbgw_tdef_group[];
diff --git a/include/osmocom/hnbgw/vty.h b/include/osmocom/hnbgw/vty.h
index 3d05da5..93b3c45 100644
--- a/include/osmocom/hnbgw/vty.h
+++ b/include/osmocom/hnbgw/vty.h
@@ -7,5 +7,6 @@
IUH_NODE,
IUCS_NODE,
IUPS_NODE,
+ MGCP_NODE,
};
diff --git a/src/osmo-hnbgw/Makefile.am b/src/osmo-hnbgw/Makefile.am
index 0948170..64d5ccd 100644
--- a/src/osmo-hnbgw/Makefile.am
+++ b/src/osmo-hnbgw/Makefile.am
@@ -19,6 +19,7 @@
$(LIBOSMORUA_CFLAGS) \
$(LIBOSMORANAP_CFLAGS) \
$(LIBOSMOHNBAP_CFLAGS) \
+ $(LIBOSMOMGCPCLIENT_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
@@ -38,6 +39,8 @@
context_map.c \
hnbgw_cn.c \
ranap_rab_ass.c \
+ mgw_fsm.c \
+ tdefs.c \
$(NULL)
osmo_hnbgw_LDADD = \
@@ -52,5 +55,7 @@
$(LIBOSMORUA_LIBS) \
$(LIBOSMORANAP_LIBS) \
$(LIBOSMOHNBAP_LIBS) \
+ $(LIBOSMOMGCPCLIENT_LIBS) \
$(LIBSCTP_LIBS) \
+ $(LIBOSMOMGCPCLIENT_LIBS) \
$(NULL)
diff --git a/src/osmo-hnbgw/hnbgw.c b/src/osmo-hnbgw/hnbgw.c
index da15bfc..cc6197c 100644
--- a/src/osmo-hnbgw/hnbgw.c
+++ b/src/osmo-hnbgw/hnbgw.c
@@ -52,6 +52,8 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/ports.h>
+#include <osmocom/mgcp_client/mgcp_client.h>
+
#include <osmocom/netif/stream.h>
#include <osmocom/ranap/ranap_common.h>
@@ -372,6 +374,11 @@
.color = "",
.description = "RAN Application Part",
},
+ [DMGW] = {
+ .name = "DMGW", .loglevel = LOGL_NOTICE, .enabled = 1,
+ .color = "\033[1;33m",
+ .description = "Media Gateway",
+ },
};
static const struct log_info hnbgw_log_info = {
@@ -681,6 +688,19 @@
}
g_hnb_gw->iuh = srv;
+ /* Initialize and connect MGCP client. */
+ g_hnb_gw->mgcp_client = mgcp_client_init(tall_hnb_ctx, g_hnb_gw->config.mgcp_client);
+ if (!g_hnb_gw->mgcp_client) {
+ LOGP(DMGW, LOGL_ERROR, "MGW client initalization failed\n");
+ return -EINVAL;
+ }
+ if (mgcp_client_connect(g_hnb_gw->mgcp_client)) {
+ LOGP(DMGW, LOGL_ERROR, "MGW connect failed at (%s:%u)\n",
+ g_hnb_gw->config.mgcp_client->remote_addr,
+ g_hnb_gw->config.mgcp_client->remote_port);
+ return -EINVAL;
+ }
+
if (hnbgw_cmdline_config.daemonize) {
rc = osmo_daemonize();
if (rc < 0) {
diff --git a/src/osmo-hnbgw/hnbgw_cn.c b/src/osmo-hnbgw/hnbgw_cn.c
index 7fbb691..c3deba5 100644
--- a/src/osmo-hnbgw/hnbgw_cn.c
+++ b/src/osmo-hnbgw/hnbgw_cn.c
@@ -34,6 +34,7 @@
#include <osmocom/ranap/ranap_ies_defs.h>
#include <osmocom/ranap/ranap_msg_factory.h>
#include <osmocom/hnbgw/context_map.h>
+#include <osmocom/hnbgw/mgw_fsm.h>
/***********************************************************************
* Outbound RANAP RESET to CN
@@ -356,6 +357,21 @@
return 0;
}
+ /* Intercept RAB Assignment Request, Setup MGW FSM */
+ if (!map->is_ps && msgb_l2len(oph->msg) > 2) {
+ switch (((uint8_t*)msgb_l2(oph->msg))[1]) {
+ case RANAP_ProcedureCode_id_RAB_Assignment:
+ /* Just like rua_tx_dt(), mgw_fsm_inst_alloc() will not take ownership of oph. Instead it will
+ * make its own copy of the message contents, so it is safe to free oph->msg() in sccp_sap_up()
+ * below. */
+ return mgw_fsm_alloc_and_handle_rab_ass_req(map, oph);
+ case RANAP_ProcedureCode_id_Iu_Release:
+ /* Any IU Release will terminate the MGW FSM */
+ mgw_fsm_handle_iu_release(map);
+ break;
+ }
+ }
+
return rua_tx_dt(map->hnb_ctx, map->is_ps, map->rua_ctx_id,
msgb_l2(oph->msg), msgb_l2len(oph->msg));
}
diff --git a/src/osmo-hnbgw/hnbgw_rua.c b/src/osmo-hnbgw/hnbgw_rua.c
index 24ca167..202007f 100644
--- a/src/osmo-hnbgw/hnbgw_rua.c
+++ b/src/osmo-hnbgw/hnbgw_rua.c
@@ -38,6 +38,8 @@
#include <osmocom/rua/rua_ies_defs.h>
#include <osmocom/hnbgw/context_map.h>
#include <osmocom/hnbap/HNBAP_CN-DomainIndicator.h>
+#include <osmocom/hnbgw/mgw_fsm.h>
+#include <osmocom/ranap/RANAP_ProcedureCode.h>
static const char *cn_domain_indicator_to_str(RUA_CN_DomainIndicator_t cN_DomainIndicator)
{
@@ -265,6 +267,17 @@
memcpy(msg->l2h, data, len);
}
+ /* Intercept RAB Assignment Response, inform MGW FSM. */
+ if (map && !map->is_ps && !release_context_map && msgb_l2len(prim->oph.msg) > 2)
+ {
+ switch (((uint8_t*)msgb_l2(prim->oph.msg))[1]) {
+ case RANAP_ProcedureCode_id_RAB_Assignment:
+ /* Note: Just like osmo_sccp_user_sap_down(), mgw_fsm_handle_rab_as_resp() will take ownership
+ * of oph */
+ return mgw_fsm_handle_rab_ass_resp(map, &prim->oph);
+ }
+ }
+
rc = osmo_sccp_user_sap_down(cn->sccp_user, &prim->oph);
if (map && release_context_map)
diff --git a/src/osmo-hnbgw/hnbgw_vty.c b/src/osmo-hnbgw/hnbgw_vty.c
index 4ad1ddb..0ec16fe 100644
--- a/src/osmo-hnbgw/hnbgw_vty.c
+++ b/src/osmo-hnbgw/hnbgw_vty.c
@@ -22,15 +22,19 @@
#include <osmocom/core/socket.h>
#include <osmocom/vty/command.h>
+#include <osmocom/vty/tdef_vty.h>
#include <osmocom/hnbgw/vty.h>
#include <osmocom/hnbgw/hnbgw.h>
#include <osmocom/hnbgw/context_map.h>
+#include <osmocom/hnbgw/tdefs.h>
#include <osmocom/sigtran/protocol/sua.h>
#include <osmocom/sigtran/sccp_helpers.h>
#include <osmocom/netif/stream.h>
+#include <osmocom/mgcp_client/mgcp_client.h>
+
static void *tall_hnb_ctx = NULL;
static struct hnb_gw *g_hnb_gw = NULL;
@@ -86,6 +90,19 @@
return CMD_SUCCESS;
}
+static struct cmd_node mgcp_node = {
+ MGCP_NODE,
+ "%s(config-hnbgw-mgcp)# ",
+ 1,
+};
+
+DEFUN(cfg_hnbgw_mgcp, cfg_hnbgw_mgcp_cmd,
+ "mgcp", "Configure MGCP client")
+{
+ vty->node = MGCP_NODE;
+ return CMD_SUCCESS;
+}
+
int hnbgw_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
@@ -95,6 +112,10 @@
vty->node = HNBGW_NODE;
vty->index = NULL;
break;
+ case MGCP_NODE:
+ vty->node = HNBGW_NODE;
+ vty->index = NULL;
+ break;
case HNBGW_NODE:
vty->node = CONFIG_NODE;
vty->index = NULL;
@@ -382,6 +403,14 @@
return CMD_SUCCESS;
}
+static int config_write_hnbgw_mgcp(struct vty *vty)
+{
+ vty_out(vty, " mgcp%s", VTY_NEWLINE);
+ mgcp_client_config_write(vty, " ");
+
+ return CMD_SUCCESS;
+}
+
void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx)
{
g_hnb_gw = gw;
@@ -415,4 +444,13 @@
install_element_ve(&show_one_hnb_cmd);
install_element_ve(&show_ue_cmd);
install_element_ve(&show_talloc_cmd);
+
+ install_element(HNBGW_NODE, &cfg_hnbgw_mgcp_cmd);
+ install_node(&mgcp_node, config_write_hnbgw_mgcp);
+
+ g_hnb_gw->config.mgcp_client = talloc_zero(tall_hnb_ctx, struct mgcp_client_conf);
+ mgcp_client_conf_init(g_hnb_gw->config.mgcp_client);
+ mgcp_client_vty_init(tall_hnb_ctx, MGCP_NODE, g_hnb_gw->config.mgcp_client);
+
+ osmo_tdef_vty_groups_init(HNBGW_NODE, hnbgw_tdef_group);
}
diff --git a/src/osmo-hnbgw/mgw_fsm.c b/src/osmo-hnbgw/mgw_fsm.c
new file mode 100644
index 0000000..df97c1a
--- /dev/null
+++ b/src/osmo-hnbgw/mgw_fsm.c
@@ -0,0 +1,562 @@
+/* (C) 2021 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * 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.
+ */
+
+#include <errno.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/prim.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/byteswap.h>
+#include <arpa/inet.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/sockaddr_str.h>
+
+#include <osmocom/ranap/ranap_common.h>
+#include <osmocom/ranap/ranap_ies_defs.h>
+#include <osmocom/ranap/ranap_msg_factory.h>
+
+#include <osmocom/ranap/ranap_ies_defs.h>
+#include <osmocom/ranap/iu_helpers.h>
+#include <asn1c/asn1helpers.h>
+
+#include <osmocom/hnbgw/hnbgw.h>
+#include <osmocom/hnbgw/context_map.h>
+#include <osmocom/hnbgw/ranap_rab_ass.h>
+
+#include <osmocom/hnbgw/hnbgw_rua.h>
+
+#include <osmocom/core/tdef.h>
+#include <osmocom/hnbgw/tdefs.h>
+#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
+
+#define S(x) (1 << (x))
+
+extern int asn1_xer_print;
+
+enum mgw_fsm_event {
+ MGW_EV_MGCP_OK,
+ MGW_EV_MGCP_FAIL,
+ MGW_EV_MGCP_TERM,
+ MGW_EV_RAB_ASS_RESP,
+ MGW_EV_RELEASE,
+};
+
+static const struct value_string mgw_fsm_event_names[] = {
+ OSMO_VALUE_STRING(MGW_EV_MGCP_OK),
+ OSMO_VALUE_STRING(MGW_EV_MGCP_FAIL),
+ OSMO_VALUE_STRING(MGW_EV_MGCP_TERM),
+ OSMO_VALUE_STRING(MGW_EV_RAB_ASS_RESP),
+ OSMO_VALUE_STRING(MGW_EV_RELEASE),
+ { }
+};
+
+enum mgw_fsm_state {
+ MGW_ST_CRCX_HNB,
+ MGW_ST_ASSIGN,
+ MGW_ST_MDCX_HNB,
+ MGW_ST_CRCX_MSC,
+ MGW_ST_ESTABLISHED,
+ MGW_ST_RELEASE,
+};
+
+struct mgw_fsm_priv {
+ /* Backpointer to HNBGW context */
+ struct hnbgw_context_map *map;
+
+ /* RAB-ID from RANAP RAB AssignmentRequest message */
+ uint8_t rab_id;
+
+ /* We have to store the RANAP RAB AssignmentRequest message, since we can not take ownership of the osmo prim
+ * header (oph). */
+ uint8_t rab_ass_req[IUH_MSGB_SIZE];
+ unsigned int rab_ass_req_len;
+
+ /* The RANAP RAB AssignmentResponse is handled differently. In this case we must take the ownership of the
+ * osmo prim header */
+ struct osmo_prim_hdr *oph_rab_ass_resp;
+
+ /* MGW context */
+ struct osmo_mgcpc_ep *mgcpc_ep;
+ struct osmo_mgcpc_ep_ci *mgcpc_ep_ci_hnb;
+ struct osmo_mgcpc_ep_ci *mgcpc_ep_ci_msc;
+ char msc_rtp_addr[INET6_ADDRSTRLEN];
+ uint16_t msc_rtp_port;
+};
+
+struct osmo_tdef mgw_tdefs[] = {
+ {.T = -2427,.default_val = 5,.desc = "timeout for MGCP response from MGW" },
+ { }
+};
+
+struct osmo_tdef_state_timeout mgw_fsm_timeouts[32] = {
+ [MGW_ST_CRCX_HNB] = {.T = -1001 },
+ [MGW_ST_ASSIGN] = {.T = -1002 },
+ [MGW_ST_MDCX_HNB] = {.T = -1003 },
+ [MGW_ST_CRCX_MSC] = {.T = -1004 },
+};
+
+#define mgw_fsm_state_chg(state) \
+ osmo_tdef_fsm_inst_state_chg(fi, state, \
+ mgw_fsm_timeouts, \
+ mgw_fsm_T_defs, \
+ -1)
+
+static void mgw_fsm_crcx_hnb_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ struct hnbgw_context_map *map = mgw_fsm_priv->map;
+ const char *epname;
+ struct mgcp_conn_peer mgw_info;
+
+ LOGPFSML(fi, LOGL_DEBUG, "RAB-AssignmentRequest received, creating HNB side call-leg on MGW...\n");
+
+ mgw_info = (struct mgcp_conn_peer) {
+ .call_id = (map->rua_ctx_id << 8) | mgw_fsm_priv->rab_id,
+ .ptime = 20,
+ .conn_mode = MGCP_CONN_LOOPBACK,
+ };
+ mgw_info.codecs[0] = CODEC_IUFP;
+ mgw_info.codecs_len = 1;
+
+ epname = mgcp_client_rtpbridge_wildcard(map->hnb_ctx->gw->mgcp_client);
+ mgw_fsm_priv->mgcpc_ep =
+ osmo_mgcpc_ep_alloc(fi, MGW_EV_MGCP_TERM, map->hnb_ctx->gw->mgcp_client, mgw_tdefs, fi->id, "%s", epname);
+ mgw_fsm_priv->mgcpc_ep_ci_hnb = osmo_mgcpc_ep_ci_add(mgw_fsm_priv->mgcpc_ep, "to-HNB");
+
+ osmo_mgcpc_ep_ci_request(mgw_fsm_priv->mgcpc_ep_ci_hnb, MGCP_VERB_CRCX, &mgw_info, fi, MGW_EV_MGCP_OK,
+ MGW_EV_MGCP_FAIL, NULL);
+}
+
+static void mgw_fsm_crcx_hnb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ const struct mgcp_conn_peer *mgw_info;
+ int rc;
+
+ switch (event) {
+ case MGW_EV_MGCP_OK:
+ mgw_info = osmo_mgcpc_ep_ci_get_rtp_info(mgw_fsm_priv->mgcpc_ep_ci_hnb);
+ if (!mgw_info) {
+ LOGPFSML(fi, LOGL_ERROR, "Got no response from MGW\n");
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ }
+
+ rc = ranap_rab_ass_req_replace_inet_addr(mgw_fsm_priv->rab_ass_req, sizeof(mgw_fsm_priv->rab_ass_req),
+ mgw_info->addr, mgw_info->port);
+ if (rc < 0) {
+ LOGPFSML(fi, LOGL_ERROR,
+ "Failed to replace RTP IP-address (%s) and Port (%u) in RAB-AssignmentRequest\n",
+ mgw_info->addr, mgw_info->port);
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ mgw_fsm_priv->rab_ass_req_len = 0;
+ return;
+ }
+ mgw_fsm_priv->rab_ass_req_len = rc;
+
+ mgw_fsm_state_chg(MGW_ST_ASSIGN);
+ return;
+ case MGW_EV_MGCP_FAIL:
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void mgw_fsm_assign_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ struct hnbgw_context_map *map = mgw_fsm_priv->map;
+
+ LOGPFSML(fi, LOGL_DEBUG, "forwarding modified RAB-AssignmentRequest to HNB\n");
+ rua_tx_dt(map->hnb_ctx, map->is_ps, map->rua_ctx_id, mgw_fsm_priv->rab_ass_req, mgw_fsm_priv->rab_ass_req_len);
+}
+
+static void mgw_fsm_assign(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ struct osmo_prim_hdr *oph = data;
+
+ switch (event) {
+ case MGW_EV_RAB_ASS_RESP:
+ mgw_fsm_priv->oph_rab_ass_resp = oph;
+ mgw_fsm_state_chg(MGW_ST_MDCX_HNB);
+ return;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void mgw_fsm_mdcx_hnb_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ struct hnbgw_context_map *map = mgw_fsm_priv->map;
+ struct mgcp_conn_peer mgw_info;
+ int rc;
+
+ LOGPFSML(fi, LOGL_DEBUG, "RAB-AssignmentResponse received, completing HNB side call-leg on MGW...\n");
+
+ mgw_info = (struct mgcp_conn_peer) {
+ .call_id = map->rua_ctx_id,
+ .ptime = 20,
+ .conn_mode = MGCP_CONN_RECV_SEND,
+ };
+ mgw_info.codecs[0] = CODEC_IUFP;
+ mgw_info.codecs_len = 1;
+
+ rc = ranap_rab_ass_resp_extract_inet_addr(mgw_info.addr, &mgw_info.port,
+ msgb_l2(mgw_fsm_priv->oph_rab_ass_resp->msg),
+ msgb_l2len(mgw_fsm_priv->oph_rab_ass_resp->msg));
+ if (rc < 0) {
+ LOGPFSML(fi, LOGL_ERROR, "Failed to extract RTP IP-address and Port from RAB-AssignmentResponse\n");
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ }
+
+ osmo_mgcpc_ep_ci_request(mgw_fsm_priv->mgcpc_ep_ci_hnb, MGCP_VERB_MDCX, &mgw_info, fi, MGW_EV_MGCP_OK,
+ MGW_EV_MGCP_FAIL, NULL);
+}
+
+static void mgw_fsm_mdcx_hnb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ const struct mgcp_conn_peer *mgw_info;
+
+ switch (event) {
+ case MGW_EV_MGCP_OK:
+ mgw_info = osmo_mgcpc_ep_ci_get_rtp_info(mgw_fsm_priv->mgcpc_ep_ci_hnb);
+ if (!mgw_info) {
+ LOGPFSML(fi, LOGL_ERROR, "Got no response from MGW\n");
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ }
+ mgw_fsm_state_chg(MGW_ST_CRCX_MSC);
+ return;
+ case MGW_EV_MGCP_FAIL:
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void mgw_fsm_crcx_msc_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ struct hnbgw_context_map *map = mgw_fsm_priv->map;
+ struct mgcp_conn_peer mgw_info;
+
+ LOGPFSML(fi, LOGL_DEBUG, "creating MSC side call-leg on MGW...\n");
+
+ mgw_info = (struct mgcp_conn_peer) {
+ .call_id = (map->rua_ctx_id << 8) | mgw_fsm_priv->rab_id,
+ .ptime = 20,
+ .port = mgw_fsm_priv->msc_rtp_port,
+ };
+
+ osmo_strlcpy(mgw_info.addr, mgw_fsm_priv->msc_rtp_addr, sizeof(mgw_info.addr));
+ mgw_info.codecs[0] = CODEC_IUFP;
+ mgw_info.codecs_len = 1;
+
+ mgw_fsm_priv->mgcpc_ep_ci_msc = osmo_mgcpc_ep_ci_add(mgw_fsm_priv->mgcpc_ep, "to-MSC");
+ osmo_mgcpc_ep_ci_request(mgw_fsm_priv->mgcpc_ep_ci_msc, MGCP_VERB_CRCX, &mgw_info, fi, MGW_EV_MGCP_OK,
+ MGW_EV_MGCP_FAIL, NULL);
+}
+
+static void mgw_fsm_crcx_msc(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ const struct mgcp_conn_peer *mgw_info;
+ int rc;
+ int msg_max_len;
+
+ switch (event) {
+ case MGW_EV_MGCP_OK:
+ mgw_info = osmo_mgcpc_ep_ci_get_rtp_info(mgw_fsm_priv->mgcpc_ep_ci_msc);
+ if (!mgw_info) {
+ LOGPFSML(fi, LOGL_ERROR, "Got no response from MGW\n");
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ }
+
+ /* When the RTP IP-Address/Port is replaced the message might grow. Ensure that there is enough room in
+ * l2h to grow. (The current implementation should yield a message with the same size, but there is no
+ * guarantee for that) */
+ msg_max_len =
+ msgb_l2len(mgw_fsm_priv->oph_rab_ass_resp->msg) +
+ msgb_tailroom(mgw_fsm_priv->oph_rab_ass_resp->msg);
+ rc = msgb_resize_area(mgw_fsm_priv->oph_rab_ass_resp->msg, mgw_fsm_priv->oph_rab_ass_resp->msg->l2h,
+ msgb_l2len(mgw_fsm_priv->oph_rab_ass_resp->msg), msg_max_len);
+ OSMO_ASSERT(rc == 0);
+
+ /* Replace RTP IP-Address/Port. */
+ rc = ranap_rab_ass_resp_replace_inet_addr(msgb_l2(mgw_fsm_priv->oph_rab_ass_resp->msg),
+ msgb_l2len(mgw_fsm_priv->oph_rab_ass_resp->msg),
+ mgw_info->addr, mgw_info->port);
+ if (rc < 0) {
+ LOGPFSML(fi, LOGL_ERROR,
+ "Failed to replace RTP IP-address (%s) and Port (%u) in RAB-AssignmentResponse\n",
+ mgw_info->addr, mgw_info->port);
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ }
+
+ /* Resize l2h back to the actual message length */
+ rc = msgb_resize_area(mgw_fsm_priv->oph_rab_ass_resp->msg, mgw_fsm_priv->oph_rab_ass_resp->msg->l2h,
+ msgb_l2len(mgw_fsm_priv->oph_rab_ass_resp->msg), rc);
+ OSMO_ASSERT(rc == 0);
+
+ /* When the established state is entered, the modified RAB AssignmentResponse is forwarded to the MSC.
+ * The call is then established any way may stay for an indefinate amount of time in this state until
+ * there is an IU Release happening. */
+ osmo_fsm_inst_state_chg(fi, MGW_ST_ESTABLISHED, 0, 0);
+ return;
+ case MGW_EV_MGCP_FAIL:
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void mgw_fsm_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ struct hnbgw_context_map *map = mgw_fsm_priv->map;
+ struct osmo_prim_hdr *oph = mgw_fsm_priv->oph_rab_ass_resp;
+ struct hnb_context *hnb = map->hnb_ctx;
+ struct hnbgw_cnlink *cn = hnb->gw->sccp.cnlink;
+ int rc;
+
+ rc = osmo_sccp_user_sap_down(cn->sccp_user, oph);
+ mgw_fsm_priv->oph_rab_ass_resp = NULL;
+ if (rc < 0)
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+
+ LOGPFSML(fi, LOGL_DEBUG, "HNB and MSC side call-legs completed!\n");
+}
+
+static void mgw_fsm_release_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
+}
+
+static void mgw_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+
+ switch (event) {
+ case MGW_EV_RELEASE:
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ case MGW_EV_MGCP_TERM:
+ mgw_fsm_priv->mgcpc_ep = NULL;
+ osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
+ return;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int mgw_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ return 0;
+}
+
+void mgw_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ struct osmo_scu_prim *scu_prim;
+ struct msgb *scu_msg;
+
+ /* In case we were unable to deliver the RANAP RAB AssignmentResponse we are responsible to free it since se
+ * have taken ownership of the prim header */
+ if (mgw_fsm_priv->oph_rab_ass_resp) {
+ scu_prim = (struct osmo_scu_prim *)mgw_fsm_priv->oph_rab_ass_resp;
+ scu_msg = scu_prim->oph.msg;
+ msgb_free(scu_msg);
+ mgw_fsm_priv->oph_rab_ass_resp = NULL;
+ }
+
+ talloc_free(mgw_fsm_priv);
+}
+
+static void mgw_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
+{
+ struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
+ struct hnbgw_context_map *map = mgw_fsm_priv->map;
+
+ if (mgw_fsm_priv->mgcpc_ep) {
+ osmo_mgcpc_ep_clear(mgw_fsm_priv->mgcpc_ep);
+ mgw_fsm_priv->mgcpc_ep = NULL;
+ }
+
+ /* Remove FSM from the context map. This will make this FSM unreachable for events comming from outside */
+ map->mgw_fi = NULL;
+}
+
+static const struct osmo_fsm_state mgw_fsm_states[] = {
+ [MGW_ST_CRCX_HNB] = {
+ .name = "MGW_ST_CRCX_HNB",
+ .onenter = mgw_fsm_crcx_hnb_onenter,
+ .action = mgw_fsm_crcx_hnb,
+ .in_event_mask = S(MGW_EV_MGCP_OK) | S(MGW_EV_MGCP_FAIL),
+ .out_state_mask = S(MGW_ST_ASSIGN) | S(MGW_ST_RELEASE) | S(MGW_ST_CRCX_HNB),
+ },
+ [MGW_ST_ASSIGN] = {
+ .name = "MGW_ST_ASSIGN",
+ .onenter = mgw_fsm_assign_onenter,
+ .action = mgw_fsm_assign,
+ .in_event_mask = S(MGW_EV_RAB_ASS_RESP),
+ .out_state_mask = S(MGW_ST_MDCX_HNB) | S(MGW_ST_RELEASE),
+ },
+ [MGW_ST_MDCX_HNB] = {
+ .name = "MGW_ST_MDCX_HNB",
+ .onenter = mgw_fsm_mdcx_hnb_onenter,
+ .action = mgw_fsm_mdcx_hnb,
+ .in_event_mask = S(MGW_EV_MGCP_OK) | S(MGW_EV_MGCP_FAIL),
+ .out_state_mask = S(MGW_ST_CRCX_MSC) | S(MGW_ST_RELEASE),
+ },
+ [MGW_ST_CRCX_MSC] = {
+ .name = "MGW_ST_CRCX_MSC",
+ .onenter = mgw_fsm_crcx_msc_onenter,
+ .action = mgw_fsm_crcx_msc,
+ .in_event_mask = S(MGW_EV_MGCP_OK) | S(MGW_EV_MGCP_FAIL),
+ .out_state_mask = S(MGW_ST_ESTABLISHED) | S(MGW_ST_RELEASE),
+ },
+ [MGW_ST_ESTABLISHED] = {
+ .name = "MGW_ST_ESTABLISHED",
+ .onenter = mgw_fsm_established_onenter,
+ .in_event_mask = 0,
+ .out_state_mask = S(MGW_ST_RELEASE),
+ },
+ [MGW_ST_RELEASE] = {
+ .name = "MGW_ST_RELEASE",
+ .onenter = mgw_fsm_release_onenter,
+ .in_event_mask = 0,
+ .out_state_mask = 0,
+ },
+};
+
+static struct osmo_fsm mgw_fsm = {
+ .name = "mgw",
+ .states = mgw_fsm_states,
+ .num_states = ARRAY_SIZE(mgw_fsm_states),
+ .log_subsys = DMGW,
+ .event_names = mgw_fsm_event_names,
+ .allstate_action = mgw_fsm_allstate_action,
+ .allstate_event_mask = S(MGW_EV_MGCP_TERM) | S(MGW_EV_RELEASE),
+ .timer_cb = mgw_fsm_timer_cb,
+ .cleanup = mgw_fsm_cleanup,
+ .pre_term = mgw_fsm_pre_term,
+};
+
+/*! Allocate MGW FSM and handle RANAP RAB AssignmentRequest).
+ * \ptmap[in] map hanbgw context map that is responsible for this call.
+ * \ptmap[in] oph osmo prim header with RANAP RAB AssignmentRequest (function does not take ownership).
+ * \returns 0 on success; negative on error. */
+int mgw_fsm_alloc_and_handle_rab_ass_req(struct hnbgw_context_map *map, struct osmo_prim_hdr *oph_rab_ass_req)
+{
+ static bool initialized = false;
+ struct osmo_fsm_inst *fi;
+ struct mgw_fsm_priv *mgw_fsm_priv;
+ int rc;
+ char fsm_name[255];
+
+ /* Initialize FSM if not done yet */
+ if (!initialized) {
+ OSMO_ASSERT(osmo_fsm_register(&mgw_fsm) == 0);
+ initialized = true;
+ }
+
+ /* When there is already an FSM, make sure that it is terminated. Under normal circumstances this situation
+ * should not occur. */
+ if (map->mgw_fi) {
+ LOGPFSML(map->mgw_fi, LOGL_ERROR, "another FSM instance is about to replace this FSM!\n");
+ osmo_fsm_inst_dispatch(map->mgw_fi, MGW_EV_RELEASE, NULL);
+ map->mgw_fi = NULL;
+ }
+
+ /* Create context and keep a local copy of the RAB AssignmentRequest, we will need this copy later to
+ * modify and forward it. We cannot take ownership of the prim header oph_rab_ass_req. */
+ mgw_fsm_priv = talloc_zero(map, struct mgw_fsm_priv);
+ OSMO_ASSERT(msgb_l2len(oph_rab_ass_req->msg) <= sizeof(mgw_fsm_priv->rab_ass_req));
+ memcpy(mgw_fsm_priv->rab_ass_req, msgb_l2(oph_rab_ass_req->msg), msgb_l2len(oph_rab_ass_req->msg));
+ mgw_fsm_priv->rab_ass_req_len = msgb_l2len(oph_rab_ass_req->msg);
+
+ /* Parse the RAB Assignment Request now, if it is bad for some reason we will exit early and not bother with
+ * creating an FSM etc. */
+ rc = ranap_rab_ass_req_extract_inet_addr(mgw_fsm_priv->msc_rtp_addr, &mgw_fsm_priv->msc_rtp_port,
+ &mgw_fsm_priv->rab_id, mgw_fsm_priv->rab_ass_req,
+ mgw_fsm_priv->rab_ass_req_len);
+ if (rc < 0) {
+ LOGP(DMGW, LOGL_ERROR,
+ "mgw_fsm_alloc_and_handle_rab_ass_req() rua_ctx_id=%d, invalid RAB-AssignmentRequest -- abort!\n",
+ map->rua_ctx_id);
+ talloc_free(mgw_fsm_priv);
+ return -EINVAL;
+ }
+
+ /* Allocate the FSM and start it. */
+ mgw_fsm_priv->map = map;
+ snprintf(fsm_name, sizeof(fsm_name), "mgw-fsm-%u-%u", map->rua_ctx_id, mgw_fsm_priv->rab_id);
+ fi = osmo_fsm_inst_alloc(&mgw_fsm, map, mgw_fsm_priv, LOGL_DEBUG, fsm_name);
+ map->mgw_fi = fi;
+ mgw_fsm_state_chg(MGW_ST_CRCX_HNB);
+
+ return 0;
+}
+
+/*! Handlie IU release (terminate RTP streams).
+ * \ptmap[in] map hanbgw context map that is responsible for this call.
+ * \returns 0 on success; negative on error. */
+int mgw_fsm_handle_iu_release(struct hnbgw_context_map *map)
+{
+ if (!map->mgw_fi) {
+ LOGP(DMGW, LOGL_ERROR, "mgw_fsm_handle_iu_release() rua_ctx_id=%d, no MGW fsm -- ignored!\n",
+ map->rua_ctx_id);
+ return -EINVAL;
+ }
+
+ osmo_fsm_inst_dispatch(map->mgw_fi, MGW_EV_RELEASE, NULL);
+ return 0;
+}
+
+/*! Handlie RANAP RAB AssignmentResponse (deliver message, complete RTP stream switching).
+ * \ptmap[in] map hanbgw context map that is responsible for this call.
+ * \ptmap[in] oph osmo prim header with RANAP RAB AssignmentResponse (function takes ownership).
+ * \returns 0 on success; negative on error. */
+int mgw_fsm_handle_rab_ass_resp(struct hnbgw_context_map *map, struct osmo_prim_hdr *oph)
+{
+ struct osmo_scu_prim *scu_prim;
+ struct msgb *scu_msg;
+
+ if (!map->mgw_fi) {
+ LOGP(DMGW, LOGL_ERROR, "mgw_fsm_handle_rab_ass_resp() rua_ctx_id=%d, no MGW fsm -- abort!\n",
+ map->rua_ctx_id);
+ scu_prim = (struct osmo_scu_prim *)oph;
+ scu_msg = scu_prim->oph.msg;
+ msgb_free(scu_msg);
+ return -EINVAL;
+ }
+
+ osmo_fsm_inst_dispatch(map->mgw_fi, MGW_EV_RAB_ASS_RESP, oph);
+ return 0;
+}
diff --git a/src/osmo-hnbgw/tdefs.c b/src/osmo-hnbgw/tdefs.c
new file mode 100644
index 0000000..d8198f2
--- /dev/null
+++ b/src/osmo-hnbgw/tdefs.c
@@ -0,0 +1,30 @@
+/* (C) 2021 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * 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.
+ */
+
+#include <osmocom/hnbgw/tdefs.h>
+
+struct osmo_tdef mgw_fsm_T_defs[] = {
+ {.T = -1001, .default_val = 5, .desc = "Timeout for HNB side call-leg (to-HNB) creation" },
+ {.T = -1002, .default_val = 10, .desc = "Timeout for the HNB to respond to RAB Assignment Request" },
+ {.T = -1003, .default_val = 5, .desc = "Timeout for HNB side call-leg (to-HNB) completion" },
+ {.T = -1004, .default_val = 5, .desc = "Timeout for MSC side call-leg (to-MSC) completion" },
+ { }
+};
+
+struct osmo_tdef_group hnbgw_tdef_group[] = {
+ {.name = "mgw", .tdefs = mgw_fsm_T_defs, .desc = "MGW (Media Gateway) interface" },
+ { }
+};
--
To view, visit https://gerrit.osmocom.org/c/osmo-hnbgw/+/26795
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: Ib9b62e0145184b91c56ce5d8870760bfa49cc5a4
Gerrit-Change-Number: 26795
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newchange
4
41
07 Feb '22
pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-mgw/+/26823 )
Change subject: WIP: Initial IuUP support using proper FSMs
......................................................................
WIP: Initial IuUP support using proper FSMs
Related: OS#1937
Depends: libosmocore Change-Id I63ee780b4aa162ea097410b234e73984000c0965
Change-Id: I6694a21480b25ab8f35d375295be6601ce38e31d
---
M include/osmocom/mgcp/Makefile.am
M include/osmocom/mgcp/mgcp_conn.h
A include/osmocom/mgcp/mgcp_iuup.h
M include/osmocom/mgcp/mgcp_network.h
M src/libosmo-mgcp/Makefile.am
M src/libosmo-mgcp/mgcp_conn.c
A src/libosmo-mgcp/mgcp_iuup.c
M src/libosmo-mgcp/mgcp_network.c
M src/libosmo-mgcp/mgcp_protocol.c
9 files changed, 671 insertions(+), 28 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-mgw refs/changes/23/26823/1
diff --git a/include/osmocom/mgcp/Makefile.am b/include/osmocom/mgcp/Makefile.am
index b94cdcd..60f29c6 100644
--- a/include/osmocom/mgcp/Makefile.am
+++ b/include/osmocom/mgcp/Makefile.am
@@ -13,4 +13,5 @@
mgcp_e1.h \
mgcp_network.h \
mgcp_protocol.h \
+ mgcp_iuup.h \
$(NULL)
diff --git a/include/osmocom/mgcp/mgcp_conn.h b/include/osmocom/mgcp/mgcp_conn.h
index 4f882e9..22e4d52 100644
--- a/include/osmocom/mgcp/mgcp_conn.h
+++ b/include/osmocom/mgcp/mgcp_conn.h
@@ -28,6 +28,7 @@
#include <osmocom/mgcp/osmux.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/rate_ctr.h>
+#include <osmocom/gsm/iuup.h>
#include <inttypes.h>
#define LOGPCONN(conn, cat, level, fmt, args...) \
@@ -47,6 +48,7 @@
MGCP_RTP_DEFAULT = 0,
MGCP_OSMUX_BSC,
MGCP_OSMUX_BSC_NAT,
+ MGCP_RTP_IUUP,
};
/*! Connection type, specifies which member of the union "u" in mgcp_conn
@@ -93,6 +95,14 @@
} stats;
} osmux;
+ struct {
+ struct osmo_iuup_instance *iui;
+ bool active_init; /* true: Send IuUP Init */
+ int rfci_idx_no_data; /* Index for RFCI NO_DATA (-1 if not available) */
+ bool configured;
+ struct osmo_iuup_rnl_prim *init_ind;
+ } iuup;
+
struct rate_ctr_group *rate_ctr_group;
};
@@ -176,6 +186,11 @@
return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
}
+/* Was conn configured to handle Osmux? */
+static inline bool mgcp_conn_rtp_is_iuup(const struct mgcp_conn_rtp *conn) {
+ return conn->type == MGCP_RTP_IUUP;
+}
+
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
enum mgcp_conn_type type, char *name);
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
diff --git a/include/osmocom/mgcp/mgcp_iuup.h b/include/osmocom/mgcp/mgcp_iuup.h
new file mode 100644
index 0000000..e0708f5
--- /dev/null
+++ b/include/osmocom/mgcp/mgcp_iuup.h
@@ -0,0 +1,33 @@
+/* Message connection list handling */
+
+/*
+ * (C) 2021 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Pau Espin Pedrol
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <osmocom/core/msgb.h>
+
+struct mgcp_conn_rtp;
+
+int mgcp_conn_iuup_init(struct mgcp_conn_rtp *conn_rtp);
+void mgcp_conn_iuup_cleanup(struct mgcp_conn_rtp *conn_rtp);
+int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg);
+int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg);
+int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp);
diff --git a/include/osmocom/mgcp/mgcp_network.h b/include/osmocom/mgcp/mgcp_network.h
index e3fa3b1..fa1c3e8 100644
--- a/include/osmocom/mgcp/mgcp_network.h
+++ b/include/osmocom/mgcp/mgcp_network.h
@@ -70,8 +70,6 @@
* data is just re-used) */
uint16_t alt_rtp_tx_sequence;
uint32_t alt_rtp_tx_ssrc;
-
- bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
};
struct mgcp_rtp_codec {
diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am
index 91b2bf6..de42c0e 100644
--- a/src/libosmo-mgcp/Makefile.am
+++ b/src/libosmo-mgcp/Makefile.am
@@ -48,4 +48,5 @@
mgcp_ctrl.c \
mgcp_ratectr.c \
mgcp_e1.c \
+ mgcp_iuup.c \
$(NULL)
diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c
index 9c2fb0f..6dc0199 100644
--- a/src/libosmo-mgcp/mgcp_conn.c
+++ b/src/libosmo-mgcp/mgcp_conn.c
@@ -30,6 +30,8 @@
#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_sdp.h>
#include <osmocom/mgcp/mgcp_codec.h>
+#include <osmocom/mgcp/mgcp_iuup.h>
+
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/timer.h>
@@ -129,6 +131,8 @@
{
if (mgcp_conn_rtp_is_osmux(conn_rtp))
conn_osmux_disable(conn_rtp);
+ if (mgcp_conn_rtp_is_iuup(conn_rtp))
+ mgcp_conn_iuup_cleanup(conn_rtp);
mgcp_free_rtp_port(&conn_rtp->end);
rate_ctr_group_free(conn_rtp->rate_ctr_group);
mgcp_codec_reset_all(conn_rtp);
diff --git a/src/libosmo-mgcp/mgcp_iuup.c b/src/libosmo-mgcp/mgcp_iuup.c
new file mode 100644
index 0000000..ab83f08
--- /dev/null
+++ b/src/libosmo-mgcp/mgcp_iuup.c
@@ -0,0 +1,584 @@
+/*
+ * (C) 2021 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All rights not specifically granted under this license are reserved.
+ *
+ * Author: Pau Espin Pedrol
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <stdint.h>
+
+#include <osmocom/gsm/iuup.h>
+
+#include <osmocom/netif/rtp.h>
+#include <osmocom/netif/amr.h>
+
+#include <osmocom/mgcp/mgcp_conn.h>
+#include <osmocom/mgcp/mgcp_iuup.h>
+#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_codec.h>
+#include <osmocom/mgcp/debug.h>
+
+#define MGW_IUUP_MSGB_SIZE 4096
+
+static struct osmo_iuup_rnl_config def_configure_req = {
+ .transparent = false,
+ .active = true,
+ .supported_versions_mask = 0x0003,
+ .num_rfci = 0,
+ .num_subflows = 0,
+ /* .delivery_err_sdu = All set to 0 (YES) by default, */
+ .IPTIs_present = false,
+ .t_init = { .t_ms = IUUP_TIMER_INIT_T_DEFAULT, .n_max = IUUP_TIMER_INIT_N_DEFAULT },
+ .t_ta = { .t_ms = IUUP_TIMER_TA_T_DEFAULT, .n_max = IUUP_TIMER_TA_N_DEFAULT },
+ .t_rc = { .t_ms = IUUP_TIMER_RC_T_DEFAULT, .n_max = IUUP_TIMER_RC_N_DEFAULT },
+};
+
+static struct mgcp_conn *_find_dst_conn(struct mgcp_conn *conn)
+{
+ /* Find a destination connection. */
+ /* NOTE: This code path runs every time an RTP packet is received. The
+ * function mgcp_find_dst_conn() we use to determine the detination
+ * connection will iterate the connection list inside the endpoint.
+ * Since list iterations are quite costly, we will figure out the
+ * destination only once and use the optional private data pointer of
+ * the connection to cache the destination connection pointer. */
+
+ struct mgcp_conn *conn_dst;
+ if (!conn->priv) {
+ conn_dst = mgcp_find_dst_conn(conn);
+ conn->priv = conn_dst;
+ } else {
+ conn_dst = (struct mgcp_conn *)conn->priv;
+ }
+ return conn_dst;
+}
+
+/* Find RFCI containing all 0 sizes, -1 if not found. irp is an Initialization.ind prim */
+static int _find_rfci_no_data(struct osmo_iuup_rnl_prim *irp)
+{
+ int i;
+ /* Find RFCI containing NO_DATA: */
+ for (i = 0; i < irp->u.status.u.initialization.num_rfci; i++) {
+ int j;
+ bool is_no_data = true;
+ for (j = 0; j < irp->u.status.u.initialization.num_subflows; j++) {
+ if (irp->u.status.u.initialization.subflow_sizes[i][j]) {
+ is_no_data = false;
+ break;
+ }
+ }
+ if (is_no_data) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/* -1 if none found */
+static int8_t _conn_iuup_amr_ft_2_rfci(struct mgcp_conn_rtp *conn_rtp, uint8_t ft)
+{
+ int8_t i;
+ unsigned match_bytes = (unsigned)osmo_amr_bytes(ft);
+ struct osmo_iuup_rnl_prim *irp = conn_rtp->iuup.init_ind;
+ OSMO_ASSERT(irp);
+
+ /* TODO: cache this somehow */
+ for (i = 0; i < irp->u.status.u.initialization.num_rfci; i++) {
+ int j;
+ unsigned num_bits = 0;
+ for (j = 0; j < irp->u.status.u.initialization.num_subflows; j++)
+ num_bits += irp->u.status.u.initialization.subflow_sizes[i][j];
+ if (match_bytes == (num_bits + 7)/8)
+ return i;
+ }
+
+ return -1;
+}
+
+static int _conn_iuup_configure_as_passive(struct mgcp_conn_rtp *conn_rtp, struct msgb *msg)
+{
+ struct osmo_iuup_rnl_prim *irp;
+ int rc;
+
+ conn_rtp->iuup.active_init = false;
+
+ /* Tx CONFIG.req */
+ irp = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
+ irp->u.config = def_configure_req;
+ irp->u.config.active = conn_rtp->iuup.active_init;
+ if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp)) == 0)
+ conn_rtp->iuup.configured = true;
+ else
+ LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed configuring IuUP layer\n");
+ return rc;
+}
+
+static int _conn_iuup_configure_as_active(struct mgcp_conn_rtp *conn_rtp, struct osmo_iuup_rnl_prim *init_ind)
+{
+ struct osmo_iuup_rnl_prim *irp = init_ind;
+ struct osmo_iuup_rnl_prim *irp2;
+ struct msgb *msg;
+ bool prev_output_enabled;
+ int rc;
+
+ conn_rtp->iuup.active_init = true;
+
+ /* Find RFCI containing NO_DATA: */
+ conn_rtp->iuup.rfci_idx_no_data = _find_rfci_no_data(init_ind);
+
+ /* Copy over the rfci_idx_no_data, since we reuse the same subflow set: */
+ msg = msgb_copy_c(conn_rtp->conn, irp->oph.msg, "iuup-init-copy");
+ conn_rtp->iuup.init_ind = (struct osmo_iuup_rnl_prim *)msgb_data(msg);
+ conn_rtp->iuup.init_ind->oph.msg = msg;
+
+ /* Tx CONFIG.req */
+ irp2 = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
+ irp2->u.config.transparent = false;
+ irp2->u.config.active = conn_rtp->iuup.active_init;
+ irp2->u.config.data_pdu_type = irp->u.status.u.initialization.data_pdu_type;
+ irp2->u.config.supported_versions_mask = def_configure_req.supported_versions_mask;
+ irp2->u.config.num_rfci = irp->u.status.u.initialization.num_rfci;
+ irp2->u.config.num_subflows = irp->u.status.u.initialization.num_subflows;
+ memcpy(irp2->u.config.subflow_sizes, irp->u.status.u.initialization.subflow_sizes,
+ IUUP_MAX_RFCIS * IUUP_MAX_SUBFLOWS * sizeof(irp2->u.config.subflow_sizes[0][0]));
+ irp2->u.config.IPTIs_present = irp->u.status.u.initialization.IPTIs_present;
+ if (irp->u.status.u.initialization.IPTIs_present)
+ memcpy(irp2->u.config.IPTIs, irp->u.status.u.initialization.IPTIs,
+ IUUP_MAX_RFCIS * sizeof(irp2->u.config.IPTIs[0]));
+ irp2->u.config.t_init = def_configure_req.t_init;
+ irp2->u.config.t_ta = def_configure_req.t_ta;
+ irp2->u.config.t_rc = def_configure_req.t_rc;
+
+ /* We need to force allowance of RTP containing Init-ACK back: */
+ prev_output_enabled = conn_rtp->end.output_enabled;
+ conn_rtp->end.output_enabled = true;
+
+ if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp2)) == 0)
+ conn_rtp->iuup.configured = true;
+ else
+ LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed configuring IuUP layer\n");
+
+ conn_rtp->end.output_enabled = prev_output_enabled;
+ return rc;
+}
+
+static int _conn_iuup_rtp_pl_up(struct mgcp_conn_rtp *conn_rtp, struct msgb *msg)
+{
+ /* Send RTP payload (IuUP) up the stack: */
+ struct osmo_iuup_tnl_prim *itp;
+ int rc;
+
+ msg->l2h = msgb_data(msg) + sizeof(struct rtp_hdr);
+
+ itp = osmo_iuup_tnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, MGW_IUUP_MSGB_SIZE);
+ itp->oph.msg->l2h = msgb_put(itp->oph.msg, msgb_l2len(msg));
+ memcpy(itp->oph.msg->l2h, msgb_l2(msg), msgb_l2len(msg));
+ if ((rc = osmo_iuup_tnl_prim_up(conn_rtp->iuup.iui, itp)) != 0) {
+ LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed passing IuUP-Init to IuUP layer\n");
+ }
+ return rc;
+}
+
+static int check_rtp_iuup(const struct mgcp_conn_rtp *conn_rtp, struct msgb *msg)
+{
+ size_t min_size = sizeof(struct rtp_hdr);
+ /* Check there's at least 2 bytes of RTP payload (IuUP header). This is
+ ** mainly to avoid 0-byte payload copy cases */
+ if (msgb_length(msg) < sizeof(struct rtp_hdr) + 2) {
+ LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "RTP-IuUP packet too short (%u < %zu)\n",
+ msgb_length(msg), min_size);
+ return -1;
+ }
+ return 0;
+}
+
+/* owns the irp */
+static int bridge_iuup_to_iuup_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mgcp_conn_rtp *conn_rtp_dst, struct osmo_iuup_rnl_prim *irp)
+{
+ int rc;
+
+ /* If we are not configured and we received bridged data, it means
+ * conn_rtp_src is already configured and INITed, and we can infer
+ * conn_rtp_src is Init-passive (RNC side), so conn_rtp_dst needs to be
+ * configured as INIT-active: */
+ if (!conn_rtp_dst->iuup.configured) {
+ OSMO_ASSERT(conn_rtp_src->iuup.init_ind);
+ rc = _conn_iuup_configure_as_active(conn_rtp_dst, conn_rtp_src->iuup.init_ind);
+ if (rc < 0) {
+ msgb_free(irp->oph.msg);
+ return rc;
+ }
+ }
+
+ /* We simply forward the msg, without freeing it: */
+ talloc_steal(conn_rtp_dst->conn, irp->oph.msg);
+ irp->oph.operation = PRIM_OP_REQUEST;
+ if ((rc = osmo_iuup_rnl_prim_down(conn_rtp_dst->iuup.iui, irp)) != 0)
+ LOG_CONN_RTP(conn_rtp_dst, LOGL_ERROR, "Failed Tx data down to IuUP layer\n");
+ return rc;
+}
+
+/* Owns the irp */
+static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mgcp_conn_rtp *conn_rtp_dst, struct osmo_iuup_rnl_prim *irp)
+{
+ /* FIXME: We probably need transcoding here?! Or at least look up AMR modes and translate to related RFCI */
+ uint8_t frame_nr = irp->u.data.frame_nr;
+ uint8_t fqc = irp->u.data.fqc;
+ struct msgb *msg = irp->oph.msg;
+ ssize_t amr_length = 0;
+ int ft;
+ uint8_t *amr_data;
+ struct rtp_hdr *rtp_hdr;
+ struct amr_hdr *amr_hdr;
+ int rc;
+
+ ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
+ if (ft < 0) {
+ LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
+ "Unknown AMR format for size %u\n", msgb_l3len(msg));
+ msgb_free(msg);
+ return ft;
+ }
+ msgb_pull_to_l3(msg);
+ LOGP(DLMGCP, LOGL_DEBUG, "Convert Iuup -> AMR: ft %d, len %d\n", ft, msgb_l3len(msg));
+
+ if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
+ amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
+ amr_hdr->cmr = 15; /* no change */
+ amr_hdr->f = 0;
+ amr_hdr->q = !fqc;
+ amr_hdr->ft = ft & 0xff;
+ amr_hdr->pad1 = 0;
+ amr_hdr->pad2 = 0;
+ } else {
+ OSMO_ASSERT(msgb_tailroom(msg) >= 2);
+ msgb_put(msg, 2);
+ osmo_amr_iuup_to_bwe(msgb_data(msg), msgb_length(msg) - 2, msgb_length(msg) + 2);
+ /* fill bwe header */
+ amr_data = msgb_data(msg);
+ /* CMR no change | follow bit | ft (3 of 4 bits) */
+ amr_data[0] = 15 << 4 | (0 << 3) | (ft >> 1);
+ amr_data[1] |= ((ft & 0x1) << 7) | (((!fqc) & 0x1) << 6);
+ amr_length = (osmo_amr_bits(ft) + 10 + 7) / 8;
+ msgb_trim(msg, amr_length);
+ }
+ rtp_hdr = (struct rtp_hdr *) msgb_push(msg, sizeof(*rtp_hdr));
+ *rtp_hdr = (struct rtp_hdr){
+ .csrc_count = 0,
+ .extension = 0,
+ .padding = 0,
+ .version = 0,
+ .payload_type = conn_rtp_dst->end.codec->payload_type,
+ .marker = 0,
+ .sequence = frame_nr,
+ .timestamp = 0,
+ .ssrc = 0
+ };
+
+ rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
+ msgb_free(msg);
+ return rc;
+}
+
+static int _conn_iuup_rx_rnl_data(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
+{
+ struct mgcp_conn *conn_dst;
+ struct mgcp_conn_rtp *conn_rtp_dst;
+ int rc;
+
+ conn_dst = _find_dst_conn(conn_rtp_src->conn);
+
+ /* There is no destination conn, stop here */
+ if (!conn_dst) {
+ LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_DEBUG,
+ "no connection to forward an incoming IuUP payload to\n");
+ rc= -1;
+ goto free_ret;
+ }
+
+ /* The destination conn is not an RTP/IuUP connection */
+ if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
+ LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
+ "unable to find suitable destination conn\n");
+ rc= -1;
+ goto free_ret;
+ }
+ conn_rtp_dst = &conn_dst->u.rtp;
+
+ switch (conn_rtp_dst->type) {
+ case MGCP_RTP_IUUP:
+ return bridge_iuup_to_iuup_peer(conn_rtp_src, conn_rtp_dst, irp);
+ case MGCP_RTP_DEFAULT:
+ return bridge_iuup_to_rtp_peer(conn_rtp_src, conn_rtp_dst, irp);
+ case MGCP_OSMUX_BSC:
+ case MGCP_OSMUX_BSC_NAT:
+ default:
+ LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
+ "Forward of IuUP payload to RTP connection type %u not supported!\n",
+ conn_rtp_dst->type);
+ rc = 0;
+ }
+
+free_ret:
+ msgb_free(irp->oph.msg);
+ return rc;
+}
+
+static int _conn_iuup_rx_rnl_status_init(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
+{
+ struct mgcp_conn *conn_dst;
+ struct mgcp_conn_rtp *conn_rtp_dst;
+ int rc = 0;
+ struct msgb *msg;
+
+ /* Find RFCI containing NO_DATA: */
+ conn_rtp_src->iuup.rfci_idx_no_data = _find_rfci_no_data(irp);
+
+ msg = msgb_copy_c(conn_rtp_src->conn, irp->oph.msg, "iuup-init-copy");
+ conn_rtp_src->iuup.init_ind = (struct osmo_iuup_rnl_prim *)msgb_data(msg);
+ conn_rtp_src->iuup.init_ind->oph.msg = msg;
+
+ conn_dst = _find_dst_conn(conn_rtp_src->conn);
+ if (!conn_dst)
+ return 0; /* FIXME: that probably means we potentially need to Init the peer dst later! */
+ conn_rtp_dst = &conn_dst->u.rtp;
+ if (!mgcp_conn_rtp_is_iuup(conn_rtp_dst))
+ return 0; /* Nothing to do */
+
+ /* We received IuUP parameters on the peer (RNC), Init actively this conn (against CN): */
+ if (!conn_rtp_dst->iuup.configured)
+ rc = _conn_iuup_configure_as_active(conn_rtp_dst, irp);
+
+ return rc;
+}
+
+static int _conn_iuup_rx_rnl_status(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
+{
+ int rc;
+
+ switch (irp->u.status.procedure) {
+ case IUUP_PROC_INIT:
+ rc = _conn_iuup_rx_rnl_status_init(conn_rtp_src, irp);
+ break;
+ case IUUP_PROC_RATE_CTRL:
+ case IUUP_PROC_TIME_ALIGN:
+ case IUUP_PROC_ERR_EVENT:
+ default:
+ LOG_CONN_RTP(conn_rtp_src, LOGL_ERROR,
+ "Received IuUP RNL STATUS procedure type %u not handled\n",
+ irp->u.status.procedure);
+ rc = 0;
+ }
+
+ return rc;
+}
+static int _conn_iuup_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
+{
+ struct mgcp_conn_rtp *conn_rtp_src = ctx;
+ struct osmo_iuup_rnl_prim *irp = (struct osmo_iuup_rnl_prim *)oph;
+ struct msgb *msg = oph->msg;
+ int rc;
+
+ switch (OSMO_PRIM_HDR(&irp->oph)) {
+ case OSMO_PRIM(OSMO_IUUP_RNL_DATA, PRIM_OP_INDICATION):
+ /* we pass ownsership of msg here: */
+ rc = _conn_iuup_rx_rnl_data(conn_rtp_src, irp);
+ break;
+ case OSMO_PRIM(OSMO_IUUP_RNL_STATUS, PRIM_OP_INDICATION):
+ rc = _conn_iuup_rx_rnl_status(conn_rtp_src, irp);
+ msgb_free(msg);
+ break;
+ default:
+ msgb_free(msg);
+ OSMO_ASSERT(false);
+ }
+
+ return rc;
+}
+
+static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
+{
+ struct mgcp_conn_rtp *conn_rtp_dst = ctx;
+ struct mgcp_conn *conn_dst = conn_rtp_dst->conn;
+ struct osmo_iuup_tnl_prim *itp = (struct osmo_iuup_tnl_prim *)oph;
+ struct mgcp_conn *conn_src;
+ struct msgb *msg;
+ struct rtp_hdr *rtph;
+ struct osmo_sockaddr from_addr = {0}; /* FIXME: what to do with this one? */
+
+ OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST));
+
+ msg = oph->msg;
+ talloc_steal(conn_rtp_dst->conn, msg);
+
+ msgb_pull_to_l2(msg);
+ rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
+ /* TODO: fill rtph properly: */
+ *rtph = (struct rtp_hdr){
+ .csrc_count = 0,
+ .extension = 0,
+ .padding = 0,
+ .version = 0,
+ .payload_type = conn_rtp_dst->end.codec->payload_type,
+ .marker = 0,
+ .sequence = 0,
+ .timestamp = 0,
+ .ssrc = 0
+ };
+
+ /* The destination of the destination conn is the source conn, right? */
+ conn_src = _find_dst_conn(conn_dst);
+ if (!conn_src) {
+ LOG_CONN_RTP(conn_rtp_dst, LOGL_NOTICE,
+ "Couldn't find source conn for IuUP dst conn\n");
+ //msgb_free(msg);
+ //return -ENOTCONN;
+ conn_src = conn_dst;
+ }
+
+ /* FIXME: set from_addr = NULL */
+ return mgcp_send(conn_dst->endp, 1,
+ &from_addr, msg, &conn_src->u.rtp, conn_rtp_dst);
+}
+
+int mgcp_conn_iuup_init(struct mgcp_conn_rtp *conn_rtp)
+{
+ conn_rtp->type = MGCP_RTP_IUUP;
+ conn_rtp->iuup.iui = osmo_iuup_instance_alloc(conn_rtp->conn, conn_rtp->conn->id);
+ OSMO_ASSERT(conn_rtp->iuup.iui);
+ osmo_iuup_instance_set_user_prim_cb(conn_rtp->iuup.iui, _conn_iuup_user_prim_cb, conn_rtp);
+ osmo_iuup_instance_set_transport_prim_cb(conn_rtp->iuup.iui, _conn_iuup_transport_prim_cb, conn_rtp);
+ conn_rtp->iuup.rfci_idx_no_data = -1;
+ return 0;
+}
+
+void mgcp_conn_iuup_cleanup(struct mgcp_conn_rtp *conn_rtp)
+{
+ osmo_iuup_instance_free(conn_rtp->iuup.iui);
+ conn_rtp->iuup.iui = NULL;
+}
+
+int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
+{
+ struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
+ struct mgcp_conn_rtp *conn_rtp_src = mc->conn_src;
+ int rc = 0;
+ bool force_output_enabled = false;
+ bool prev_output_enabled;
+ struct osmo_sockaddr prev_rem_addr;
+ uint16_t prev_rem_rtp_port;
+
+ OSMO_ASSERT(mgcp_conn_rtp_is_iuup(conn_rtp_src));
+
+ if ((rc = check_rtp_iuup(conn_rtp_src, msg)) < 0)
+ goto free_ret;
+
+ if (!conn_rtp_src->iuup.configured) {
+ /* We received the first message without sending any, the peer is the active side (RNC). */
+ rc = _conn_iuup_configure_as_passive(conn_rtp_src, msg);
+ if (rc < 0)
+ goto free_ret;
+ /* We need to force allowance of RTP containing Init-ACK back: */
+ prev_output_enabled = conn_rtp_src->end.output_enabled;
+ conn_rtp_src->end.output_enabled = true;
+ force_output_enabled = true;
+ /* Fill in the peer address so that we can send Init-ACK back: */
+ prev_rem_addr = conn_rtp_src->end.addr;
+ prev_rem_rtp_port = conn_rtp_src->end.rtp_port;
+ conn_rtp_src->end.addr = *mc->from_addr;
+ conn_rtp_src->end.rtp_port = htons(osmo_sockaddr_port(&mc->from_addr->u.sa));
+ }
+
+ rc = _conn_iuup_rtp_pl_up(conn_rtp_src, msg);
+
+ if (force_output_enabled) {
+ conn_rtp_src->end.output_enabled = prev_output_enabled;
+ conn_rtp_src->end.addr = prev_rem_addr;
+ conn_rtp_src->end.rtp_port = prev_rem_rtp_port;
+ }
+
+ return rc;
+free_ret:
+ msgb_free(msg);
+ return rc;
+}
+
+/* Build IuUP RNL Data primitive from msg containing an incoming RTP pkt from
+ * peer and send it down the IuUP layer towards the destination as IuUP/RTP: */
+int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg)
+{
+ struct osmo_iuup_rnl_prim *irp;
+ struct rtp_hdr *rtph;
+ struct amr_hdr *amr_hdr;
+ int rc = -1;
+ int iuup_length = 0;
+
+ /* Tx RNL-DATA.req */
+ rtph = (struct rtp_hdr *)msgb_data(msg);
+ msgb_pull(msg, sizeof(*rtph));
+
+ /* FIXME: validate amr packets */
+ irp = osmo_iuup_rnl_prim_alloc(conn_dest_rtp->conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
+ irp->u.data.frame_nr = htons(rtph->sequence) % 16;
+
+ /* FIXME: We probably need transcoding here?! Or at least look up AMR modes and translate to related RFCI */
+ if (msgb_length(msg) < (sizeof(*amr_hdr))) {
+ return -1;
+ }
+
+ amr_hdr = (struct amr_hdr *) msgb_data(msg);
+ if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
+ /* FIXME: CMR handling & multiple frames handling */
+ irp->u.data.fqc = IUUP_FQC_FRAME_GOOD;
+ irp->u.data.rfci = _conn_iuup_amr_ft_2_rfci(conn_dest_rtp, amr_hdr->ft);
+ msgb_pull(msg, 2);
+ } else {
+ irp->u.data.fqc = amr_hdr->q;
+ irp->u.data.rfci = _conn_iuup_amr_ft_2_rfci(conn_dest_rtp, amr_hdr->ft);
+ rc = iuup_length = osmo_amr_bwe_to_iuup(msgb_data(msg), msgb_length(msg));
+ if (rc < 0) {
+ LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Failed convert the RTP/AMR to IuUP payload\n");
+ return rc;
+ }
+ msgb_trim(msg, iuup_length);
+ }
+
+ irp->oph.msg->l3h = msgb_put(irp->oph.msg, msgb_length(msg));
+ memcpy(irp->oph.msg->l3h, msgb_data(msg), msgb_length(msg));
+ if ((rc = osmo_iuup_rnl_prim_down(conn_dest_rtp->iuup.iui, irp)) != 0) {
+ LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Failed Tx RTP payload down the IuUP layer\n");
+ return rc;
+ }
+
+ return rc;
+}
+
+/* Build IuUP RNL Data primitive from msg containing dummy content and send it
+ * down the IuUP layer towards the destination as IuUP/RTP: */
+int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp)
+{
+ struct osmo_iuup_rnl_prim *irp;
+ int rc;
+
+ if (conn_rtp->iuup.rfci_idx_no_data == -1) {
+ LOG_CONN_RTP(conn_rtp, LOGL_NOTICE, "No RFCI NO_DATA found, unable to send dummy packet\n");
+ return -ENOTSUP;
+ }
+
+ irp = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
+ irp->u.data.frame_nr = 0;
+ irp->u.data.fqc = IUUP_FQC_FRAME_GOOD;
+ irp->u.data.rfci = conn_rtp->iuup.rfci_idx_no_data;
+ irp->oph.msg->l3h = irp->oph.msg->tail;
+ if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp)) != 0) {
+ LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed Tx RTP dummy payload down the IuUP layer\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c
index f865dfe..ea57b26 100644
--- a/src/libosmo-mgcp/mgcp_network.c
+++ b/src/libosmo-mgcp/mgcp_network.c
@@ -48,7 +48,7 @@
#include <osmocom/mgcp/debug.h>
#include <osmocom/codec/codec.h>
#include <osmocom/mgcp/mgcp_e1.h>
-
+#include <osmocom/mgcp/mgcp_iuup.h>
#define RTP_SEQ_MOD (1 << 16)
#define RTP_MAX_DROPOUT 3000
@@ -975,7 +975,8 @@
* the length is because we currently handle IUUP packets as RTP
* packets, so they must pass this check, if we weould be more
* strict here, we would possibly break 3G. (see also FIXME note
- * below */
+ * below. */
+ /* FIXME UPDATE: we can now apply more checks based on mgcp_conn_rtp_is_iuup(conn_src) */
return 0;
}
@@ -1013,6 +1014,11 @@
"endpoint type is MGCP_OSMUX_BSC_NAT, "
"using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
return osmux_xfrm_to_osmux((char*)msgb_data(msg), msgb_length(msg), conn_dst);
+ case MGCP_RTP_IUUP:
+ LOGPENDP(endp, DRTP, LOGL_DEBUG,
+ "endpoint type is MGCP_RTP_IUUP, "
+ "using mgcp_conn_iuup_send_rtp() to forward data over IuUP\n");
+ return mgcp_conn_iuup_send_rtp(conn_src, conn_dst, msg);
}
/* If the data has not been handled/forwarded until here, it will
@@ -1073,8 +1079,11 @@
if (check_rtp_destin(conn) != 0)
goto failed;
- rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
- conn->end.rtp_port, rtp_dummy_payload, sizeof(rtp_dummy_payload));
+ if (mgcp_conn_rtp_is_iuup(conn))
+ rc = mgcp_conn_iuup_send_dummy(conn);
+ else
+ rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr, conn->end.rtp_port,
+ rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc == -1)
goto failed;
@@ -1138,7 +1147,7 @@
* course unable to patch the payload type. A situation like this
* should not occur if transcoding is consequently avoided. Until
* we have transcoding support in osmo-mgw we can not resolve this. */
- if (is_rtp) {
+ if (is_rtp && conn_dst->type != MGCP_RTP_IUUP) {
rc = mgcp_patch_pt(conn_src, conn_dst, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_DEBUG,
@@ -1185,7 +1194,9 @@
mgcp_patch_and_count(endp, rtp_state, rtp_end,
addr, msg);
- if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
+ if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
+ /* the iuup code will correctly transform to the correct AMR mode */
+ } else if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg,
conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
@@ -1214,25 +1225,6 @@
forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
- /* FIXME: HACK HACK HACK. See OS#2459.
- * The ip.access nano3G needs the first RTP payload's first two bytes to read hex
- * 'e400', or it will reject the RAB assignment. It seems to not harm other femto
- * cells (as long as we patch only the first RTP payload in each stream).
- */
- if (!rtp_state->patched_first_rtp_payload
- && conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
- uint8_t *data = msgb_data(msg) + 12;
- if (data[0] == 0xe0) {
- data[0] = 0xe4;
- data[1] = 0x00;
- data[2] = (0x09 << 2); /* Patch CRC Header to adapt to new header above */
- rtp_state->patched_first_rtp_payload = true;
- LOGPENDP(endp, DRTP, LOGL_DEBUG,
- "Patching over first two bytes"
- " to fake an IuUP Initialization Ack\n");
- }
- }
-
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
(char *)msgb_data(msg), msgb_length(msg));
@@ -1292,6 +1284,9 @@
* destination connection is known the RTP packet is sent via
* the destination connection. */
+ /* If source is IuUP, we need to handle state, forward it through specific bridge: */
+ if (mgcp_conn_rtp_is_iuup(conn_src))
+ return mgcp_conn_iuup_dispatch_rtp(msg);
/* Check if the connection is in loopback mode, if yes, just send the
* incoming data back to the origin */
diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index 5b88c7a..b5a0c58 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -46,6 +46,7 @@
#include <osmocom/mgcp/mgcp_sdp.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_conn.h>
+#include <osmocom/mgcp/mgcp_iuup.h>
/* Contains the last successfully resolved endpoint name. This variable is used
* for the unit-tests to verify that the endpoint was correctly resolved. */
@@ -147,7 +148,13 @@
struct mgcp_conn_rtp *conn_dst = conn;
struct mgcp_conn *_conn;
- if (conn->type != MGCP_RTP_DEFAULT && !mgcp_conn_rtp_is_osmux(conn)) {
+ switch (conn->type) {
+ case MGCP_RTP_DEFAULT:
+ case MGCP_OSMUX_BSC:
+ case MGCP_OSMUX_BSC_NAT:
+ case MGCP_RTP_IUUP:
+ break;
+ default:
LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
"RTP-setup: Endpoint is not configured as RTP default, stopping here!\n");
return 0;
@@ -1028,6 +1035,11 @@
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CODEC_NEGOTIATION));
goto error2;
}
+ /* Upgrade the conn type RTP_DEFAULT->RTP_IUUP if needed based on requested codec: */
+ /* TODO: "codec" probably needs to be moved from endp to conn */
+ if (conn->type == MGCP_RTP_DEFAULT && strcmp(conn->end.codec->subtype_name, "VND.3GPP.IUFP") == 0) {
+ rc = mgcp_conn_iuup_init(conn);
+ }
conn->end.fmtp_extra = talloc_strdup(trunk->endpoints,
trunk->audio_fmtp_extra);
--
To view, visit https://gerrit.osmocom.org/c/osmo-mgw/+/26823
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-mgw
Gerrit-Branch: master
Gerrit-Change-Id: I6694a21480b25ab8f35d375295be6601ce38e31d
Gerrit-Change-Number: 26823
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newchange
3
16
Change in osmo-hnbgw[master]: ranap_rab_ass: add decoder and rewrite functions for RAB-AssignmentRe...
by dexter 07 Feb '22
by dexter 07 Feb '22
07 Feb '22
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/26792 )
Change subject: ranap_rab_ass: add decoder and rewrite functions for RAB-AssignmentRequest/Response
......................................................................
ranap_rab_ass: add decoder and rewrite functions for RAB-AssignmentRequest/Response
The RANAP RAB AssignmentRequest and AssignmentResponse contains the
IP-Address and the IP-Port for the RTP voice stream. In the comming MGCP
implementation we will have to extract and replace this information.
Lets add functions that do that in a convinient way.
Change-Id: I58b542bf23ff5e1db2ccf6833fec91d9ba332837
Depends: osmo-iuh.git Id7293c1035cf6de34b7a416fa9265a5a32ed3216
Related: OS#5152
---
M configure.ac
A include/osmocom/hnbgw/ranap_rab_ass.h
M src/osmo-hnbgw/Makefile.am
A src/osmo-hnbgw/ranap_rab_ass.c
M tests/Makefile.am
A tests/test_common.c
A tests/test_common.h
M tests/testsuite.at
8 files changed, 699 insertions(+), 5 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-hnbgw refs/changes/92/26792/1
diff --git a/configure.ac b/configure.ac
index 3e02bd9..4dc8087 100644
--- a/configure.ac
+++ b/configure.ac
@@ -233,6 +233,7 @@
src/osmo-hnbgw/Makefile
tests/Makefile
tests/atlocal
+ tests/ranap_rab_ass/Makefile
doc/Makefile
doc/examples/Makefile
doc/manuals/Makefile
diff --git a/include/osmocom/hnbgw/ranap_rab_ass.h b/include/osmocom/hnbgw/ranap_rab_ass.h
new file mode 100644
index 0000000..94caa43
--- /dev/null
+++ b/include/osmocom/hnbgw/ranap_rab_ass.h
@@ -0,0 +1,18 @@
+#pragma once
+
+int ranap_rab_ass_req_decode(RANAP_RAB_AssignmentRequestIEs_t *rab_assignment_request_ies, const uint8_t *data,
+ unsigned int len);
+int ranap_rab_ass_req_encode(uint8_t *data, unsigned int len,
+ RANAP_RAB_AssignmentRequestIEs_t *rab_assignment_request_ies);
+
+int ranap_rab_ass_resp_decode(RANAP_RAB_AssignmentResponseIEs_t *rab_assignment_response_ies, const uint8_t *data,
+ unsigned int len);
+int ranap_rab_ass_resp_encode(uint8_t *data, unsigned int len,
+ RANAP_RAB_AssignmentResponseIEs_t *rab_assignment_response_ies);
+
+int ranap_rab_ass_req_extract_inet_addr(char *addr, uint16_t *port, uint8_t *rab_id, const uint8_t *data,
+ unsigned int data_len);
+int ranap_rab_ass_resp_extract_inet_addr(char *addr, uint16_t *port, const uint8_t *data, unsigned int data_len);
+
+int ranap_rab_ass_req_replace_inet_addr(uint8_t *data, unsigned int data_len, const char *addr, uint32_t port);
+int ranap_rab_ass_resp_replace_inet_addr(uint8_t *data, unsigned int data_len, const char *addr, uint32_t port);
diff --git a/src/osmo-hnbgw/Makefile.am b/src/osmo-hnbgw/Makefile.am
index bda8633..0948170 100644
--- a/src/osmo-hnbgw/Makefile.am
+++ b/src/osmo-hnbgw/Makefile.am
@@ -37,6 +37,7 @@
hnbgw_vty.c \
context_map.c \
hnbgw_cn.c \
+ ranap_rab_ass.c \
$(NULL)
osmo_hnbgw_LDADD = \
diff --git a/src/osmo-hnbgw/ranap_rab_ass.c b/src/osmo-hnbgw/ranap_rab_ass.c
new file mode 100644
index 0000000..c8fd3fe
--- /dev/null
+++ b/src/osmo-hnbgw/ranap_rab_ass.c
@@ -0,0 +1,557 @@
+/* (C) 2021 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* Note: This files contains tools to decode and re-encode the RAB-AssignmentRequest. This set of tools is used by
+ * mgcp_fsm.c to extract and manipulate the transportLayerAddress. */
+
+#include <errno.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/sockaddr_str.h>
+#include <osmocom/hnbgw/hnbgw.h>
+#include <osmocom/ranap/ranap_common.h>
+#include <osmocom/ranap/iu_helpers.h>
+#include <asn1c/asn1helpers.h>
+
+/* Decode a RAB-AssignmentRequest message down to request IEs. */
+int ranap_rab_ass_req_decode(RANAP_RAB_AssignmentRequestIEs_t *rab_assignment_request_ies, const uint8_t *data,
+ unsigned int len)
+{
+ int rc;
+ asn_dec_rval_t dec_ret;
+ RANAP_RANAP_PDU_t _ranap_pdu;
+ RANAP_RANAP_PDU_t *ranap_pdu = &_ranap_pdu;
+
+ /* NOTE: The caller must take care of freeing the raB_SetupOrModifyList that is contained in the result using:
+ * ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyList, decoded.raB_SetupOrModifyList); */
+
+ memset(ranap_pdu, 0, sizeof(*ranap_pdu));
+ memset(rab_assignment_request_ies, 0, sizeof(*rab_assignment_request_ies));
+
+ /* Decode the RANAP PDU (outer shell) */
+ dec_ret = aper_decode(NULL, &asn_DEF_RANAP_RANAP_PDU, (void **)&ranap_pdu, data, len, 0, 0);
+ if (dec_ret.code != RC_OK) {
+ RANAP_DEBUG("Error in RANAP ASN.1 decode\n");
+ return -EINVAL;
+ }
+
+ /* We expect this to be an initiating message */
+ if (ranap_pdu->present != RANAP_RANAP_PDU_PR_initiatingMessage) {
+ RANAP_DEBUG("RAB Assignment request does not contain an initiating message\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* We expect the procedure code to match, this should always be the case since the procedure code is already
+ * matched by the code pathes before and we won't even attempt to enter this code path with a procedure code
+ * other then RANAP_ProcedureCode_id_RAB_Assignment */
+ if (ranap_pdu->choice.initiatingMessage.procedureCode != RANAP_ProcedureCode_id_RAB_Assignment) {
+ RANAP_DEBUG("Procedure code indicates that this message is not a RAB Assignment!\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Decode RAB assignment request IEs (inner shell) */
+ rc = ranap_decode_rab_assignmentrequesties(rab_assignment_request_ies,
+ &ranap_pdu->choice.initiatingMessage.value);
+ if (rc != 0) {
+ RANAP_DEBUG("Unable to decode RAB Assignment Request IEs!\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = 0;
+error:
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RANAP_PDU, ranap_pdu);
+ return rc;
+}
+
+/* Encode a RAB-AssignmentRequest message from given request IEs. */
+int ranap_rab_ass_req_encode(uint8_t *data, unsigned int len,
+ RANAP_RAB_AssignmentRequestIEs_t *rab_assignment_request_ies)
+{
+ int rc;
+ struct msgb *msg;
+
+ RANAP_RAB_AssignmentRequest_t _rab_assignment_request;
+ RANAP_RAB_AssignmentRequest_t *rab_assignment_request = &_rab_assignment_request;
+ memset(rab_assignment_request, 0, sizeof(*rab_assignment_request));
+
+ rc = ranap_encode_rab_assignmentrequesties(rab_assignment_request, rab_assignment_request_ies);
+ if (rc < 0)
+ return -EINVAL;
+
+ /* generate an Initiating Mesasage: out -> msg */
+ msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_RAB_Assignment,
+ RANAP_Criticality_reject,
+ &asn_DEF_RANAP_RAB_AssignmentRequest, rab_assignment_request);
+
+ /* 'msg' has been generated, we cann now release the input 'out' */
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_AssignmentRequest, rab_assignment_request);
+
+ if (!msg)
+ return -EINVAL;
+ if (msg->len > len)
+ return -EINVAL;
+
+ memcpy(data, msg->data, msg->len);
+ rc = msg->len;
+ msgb_free(msg);
+ return rc;
+}
+
+/* Decode a RAB-AssignmentResponse message down to request IEs. */
+int ranap_rab_ass_resp_decode(RANAP_RAB_AssignmentResponseIEs_t *rab_assignment_response_ies, const uint8_t *data,
+ unsigned int len)
+{
+ int rc;
+ asn_dec_rval_t dec_ret;
+ RANAP_RANAP_PDU_t _ranap_pdu;
+ RANAP_RANAP_PDU_t *ranap_pdu = &_ranap_pdu;
+
+ /* NOTE: The caller must take care of freeing the raB_SetupOrModifyList that is contained in the result using:
+ * ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedList, decoded.raB_SetupOrModifiedList); */
+
+ memset(ranap_pdu, 0, sizeof(*ranap_pdu));
+ memset(rab_assignment_response_ies, 0, sizeof(*rab_assignment_response_ies));
+
+ /* Decode the RANAP PDU (outer shell) */
+ dec_ret = aper_decode(NULL, &asn_DEF_RANAP_RANAP_PDU, (void **)&ranap_pdu, data, len, 0, 0);
+ if (dec_ret.code != RC_OK) {
+ RANAP_DEBUG("Error in RANAP ASN.1 decode\n");
+ return -EINVAL;
+ }
+
+ /* We expect this to be an outcome message */
+ if (ranap_pdu->present != RANAP_RANAP_PDU_PR_outcome) {
+ RANAP_DEBUG("RAB AssignmentResponse does not contain an outcome message\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* We expect the procedure code to match, this should always be the case since the procedure code is already
+ * matched by the code pathes before and we won't even attempt to enter this code path with a procedure code
+ * other then RANAP_ProcedureCode_id_RAB_Assignment */
+ if (ranap_pdu->choice.initiatingMessage.procedureCode != RANAP_ProcedureCode_id_RAB_Assignment) {
+ RANAP_DEBUG("Procedure code indicates that this message is not a RAB Assignment!\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Decode RAB assignment response IEs (inner shell) */
+ rc = ranap_decode_rab_assignmentresponseies(rab_assignment_response_ies, &ranap_pdu->choice.outcome.value);
+ if (rc != 0) {
+ RANAP_DEBUG("Unable to decode RAB AssignmentResponse IEs!\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = 0;
+error:
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RANAP_PDU, ranap_pdu);
+ return rc;
+}
+
+/* Encode a RAB-AssignmentResponse message from given request IEs. */
+int ranap_rab_ass_resp_encode(uint8_t *data, unsigned int len,
+ RANAP_RAB_AssignmentResponseIEs_t *rab_assignment_response_ies)
+{
+ int rc;
+ struct msgb *msg;
+
+ RANAP_RAB_AssignmentResponse_t _rab_assignment_response;
+ RANAP_RAB_AssignmentResponse_t *rab_assignment_response = &_rab_assignment_response;
+ memset(rab_assignment_response, 0, sizeof(*rab_assignment_response));
+
+ rc = ranap_encode_rab_assignmentresponseies(rab_assignment_response, rab_assignment_response_ies);
+ if (rc < 0)
+ return -EINVAL;
+
+ /* generate an outcome mesasage: out -> msg */
+ msg = ranap_generate_outcome(RANAP_ProcedureCode_id_RAB_Assignment,
+ RANAP_Criticality_reject,
+ &asn_DEF_RANAP_RAB_AssignmentResponse, rab_assignment_response);
+
+ /* 'msg' has been generated, we cann now release the input 'out' */
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_AssignmentResponse, rab_assignment_response);
+
+ if (!msg)
+ return -EINVAL;
+ if (msg->len > len)
+ return -EINVAL;
+
+ memcpy(data, msg->data, msg->len);
+ rc = msg->len;
+ msgb_free(msg);
+ return rc;
+}
+
+/* Pick the first item from the RAB setup-or-modify list and return the first protocol-ie-field-pair. This is based on
+ * the assumption that a PS call will only assign a signle RAB. This could be different for video calls and IMS but
+ * those are in practice a corner case, so we go for this simplified assumption for now. */
+static RANAP_ProtocolIE_FieldPair_t *prot_ie_field_pair_from_ass_req_ies(const RANAP_RAB_AssignmentRequestIEs_t *ies)
+{
+ RANAP_ProtocolIE_ContainerPair_t *protocol_ie_container_pair;
+ RANAP_ProtocolIE_FieldPair_t *protocol_ie_field_pair;
+
+ /* Make sure we indeed deal with a setup-or-modify list */
+ if (!(ies->presenceMask & RAB_ASSIGNMENTREQUESTIES_RANAP_RAB_SETUPORMODIFYLIST_PRESENT)) {
+ RANAP_DEBUG
+ ("Decoding failed, the RANAP RAB AssignmentRequest did not contain a setup-or-modify list!\n");
+ return NULL;
+ }
+
+ protocol_ie_container_pair = ies->raB_SetupOrModifyList.list.array[0];
+ protocol_ie_field_pair = protocol_ie_container_pair->list.array[0];
+
+ return protocol_ie_field_pair;
+}
+
+/* See also comment above prot_ie_field_pair_from_ass_req_ies */
+static RANAP_IE_t *setup_or_modif_item_from_rab_ass_resp(const RANAP_RAB_AssignmentResponseIEs_t *ies)
+{
+ /* Make sure we indeed deal with a setup-or-modified list */
+ if (!(ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT)) {
+ RANAP_DEBUG
+ ("Decoding failed, the RANAP RAB AssignmentResponse did not contain a setup-or-modified list!\n");
+ return NULL;
+ }
+
+ return ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0];
+}
+
+/*! Extract IP address and port from the transport-layer-address that is contained inside RAB AssignmentRequest.
+ * \ptmap[out] addr buffer to store extracted RTP stream IP address (length at least INET6_ADDRSTRLEN).
+ * \ptmap[out] port pointer to store extracted RTP stream IP port number (host byte order).
+ * \ptmap[out] rab_id pointer to store RAB-ID (optional, can be NULL).
+ * \ptmap[in] data buffer with ASN.1 encoded message.
+ * \ptmap[in] data_len length of buffer with ASN.1 encoded message.
+ * \returns 0 on success; negative on error. */
+int ranap_rab_ass_req_extract_inet_addr(char *addr, uint16_t *port, uint8_t *rab_id, const uint8_t *data,
+ unsigned int data_len)
+{
+ RANAP_RAB_AssignmentRequestIEs_t _rab_assignment_request_ies;
+ RANAP_RAB_AssignmentRequestIEs_t *rab_assignment_request_ies = &_rab_assignment_request_ies;
+ RANAP_ProtocolIE_FieldPair_t *protocol_ie_field_pair;
+ RANAP_RAB_SetupOrModifyItemFirst_t _rab_setup_or_modify_item_first;
+ RANAP_RAB_SetupOrModifyItemFirst_t *rab_setup_or_modify_item_first = &_rab_setup_or_modify_item_first;
+ int rc;
+
+ rc = ranap_rab_ass_req_decode(rab_assignment_request_ies, data, data_len);
+ if (rc < 0)
+ return -EINVAL;
+
+ protocol_ie_field_pair = prot_ie_field_pair_from_ass_req_ies(rab_assignment_request_ies);
+ if (!protocol_ie_field_pair) {
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ if (protocol_ie_field_pair->id != RANAP_ProtocolIE_ID_id_RAB_SetupOrModifyItem) {
+ RANAP_DEBUG
+ ("Decoding failed, the protocol IE field-pair is not of type RANAP RAB setup-or-modify-item!\n");
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ rc = ranap_decode_rab_setupormodifyitemfirst(rab_setup_or_modify_item_first,
+ &protocol_ie_field_pair->firstValue);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ if (rab_id) {
+ /* The RAB-ID is defined as a bitstring with a size of 8 (1 byte),
+ * See also RANAP-IEs.asn, RAB-ID ::= BIT STRING (SIZE (8)) */
+ *rab_id = rab_setup_or_modify_item_first->rAB_ID.buf[0];
+ }
+
+ rc = ranap_transp_layer_addr_decode(addr, INET6_ADDRSTRLEN,
+ &rab_setup_or_modify_item_first->transportLayerInformation->
+ transportLayerAddress);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = ranap_transp_assoc_decode(port,
+ &rab_setup_or_modify_item_first->transportLayerInformation->
+ iuTransportAssociation);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = 0;
+error:
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, rab_setup_or_modify_item_first);
+early_error:
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyList,
+ &rab_assignment_request_ies->raB_SetupOrModifyList);
+ return rc;
+}
+
+/*! Extract IP address and port from the transport-layer-address that is contained inside RAB AssignmentResponse.
+ * \ptmap[out] addr buffer to store extracted RTP stream IP address (length at least INET6_ADDRSTRLEN).
+ * \ptmap[out] port pointer to store extracted RTP stream IP port number (host byte order).
+ * \ptmap[in] data buffer with ASN.1 encoded message.
+ * \ptmap[in] data_len length of buffer with ASN.1 encoded message.
+ * \returns 0 on success; negative on error. */
+int ranap_rab_ass_resp_extract_inet_addr(char *addr, uint16_t *port, const uint8_t *data, unsigned int data_len)
+{
+ RANAP_RAB_AssignmentResponseIEs_t _rab_assignment_response_ies;
+ RANAP_RAB_AssignmentResponseIEs_t *rab_assignment_response_ies = &_rab_assignment_response_ies;
+ RANAP_IE_t *setup_or_modified_list_ie;
+ RANAP_RAB_SetupOrModifiedItemIEs_t _rab_setup_or_modified_items_ies;
+ RANAP_RAB_SetupOrModifiedItemIEs_t *rab_setup_or_modified_items_ies = &_rab_setup_or_modified_items_ies;
+ RANAP_RAB_SetupOrModifiedItem_t *rab_setup_or_modified_item;
+ int rc;
+
+ rc = ranap_rab_ass_resp_decode(rab_assignment_response_ies, data, data_len);
+ if (rc < 0)
+ return -EINVAL;
+
+ setup_or_modified_list_ie = setup_or_modif_item_from_rab_ass_resp(rab_assignment_response_ies);
+ if (!setup_or_modified_list_ie) {
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ rc = ranap_decode_rab_setupormodifieditemies_fromlist(rab_setup_or_modified_items_ies,
+ &setup_or_modified_list_ie->value);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ rab_setup_or_modified_item = &rab_setup_or_modified_items_ies->raB_SetupOrModifiedItem;
+
+ rc = ranap_transp_layer_addr_decode(addr, INET6_ADDRSTRLEN, rab_setup_or_modified_item->transportLayerAddress);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = ranap_transp_assoc_decode(port, rab_setup_or_modified_item->iuTransportAssociation);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = 0;
+error:
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedItem, rab_setup_or_modified_items_ies);
+early_error:
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedList,
+ &rab_assignment_response_ies->raB_SetupOrModifiedList);
+ return rc;
+}
+
+/*! Replace IP address and port in the transport-layer-address that is contained inside RAB AssignmentRequest.
+ * \ptmap[inout] data buffer with ASN.1 encoded message.
+ * \ptmap[in] data_len length of buffer with ASN.1 encoded message.
+ * \ptmap[in] addr buffer that contains the new RTP stream IP address.
+ * \ptmap[in] port new RTP stream IP port number (host byte order).
+ * \returns resulting message length on success; negative on error. */
+int ranap_rab_ass_req_replace_inet_addr(uint8_t *data, unsigned int data_len, const char *addr, uint32_t port)
+{
+
+ /* FIXME: WHAT IF THE RESULTING LENGTH OF THE MESSAGE IS DIFFERENT!? */
+ RANAP_RAB_AssignmentRequestIEs_t _rab_assignment_request_ies;
+ RANAP_RAB_AssignmentRequestIEs_t *rab_assignment_request_ies = &_rab_assignment_request_ies;
+ RANAP_ProtocolIE_FieldPair_t *protocol_ie_field_pair;
+ RANAP_RAB_SetupOrModifyItemFirst_t _rab_setup_or_modify_item_first;
+ RANAP_RAB_SetupOrModifyItemFirst_t *rab_setup_or_modify_item_first = &_rab_setup_or_modify_item_first;
+ struct osmo_sockaddr ip_addr;
+ struct osmo_sockaddr_str sockaddr_str;
+ RANAP_TransportLayerInformation_t *old_transport_layer_information = NULL;
+ RANAP_TransportLayerInformation_t *new_transport_layer_information = NULL;
+ int rc;
+
+ rc = ranap_rab_ass_req_decode(rab_assignment_request_ies, data, data_len);
+ if (rc < 0)
+ return -EINVAL;
+
+ protocol_ie_field_pair = prot_ie_field_pair_from_ass_req_ies(rab_assignment_request_ies);
+ if (!protocol_ie_field_pair) {
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ if (protocol_ie_field_pair->id != RANAP_ProtocolIE_ID_id_RAB_SetupOrModifyItem) {
+ RANAP_DEBUG("Rewriting transport layer information failed, unexpected IE field-pair type!\n");
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ /* Decode setup-or-modifiy item (first) */
+ rc = ranap_decode_rab_setupormodifyitemfirst(rab_setup_or_modify_item_first,
+ &protocol_ie_field_pair->firstValue);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ /* Replace transport-layer-information */
+ if (rab_setup_or_modify_item_first->transportLayerInformation->iuTransportAssociation.present ==
+ RANAP_IuTransportAssociation_PR_bindingID) {
+ sockaddr_str = (struct osmo_sockaddr_str) {
+ .af = AF_INET,
+ .port = port,
+ };
+ osmo_strlcpy(sockaddr_str.ip, addr, INET6_ADDRSTRLEN);
+
+ rc = osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &ip_addr.u.sas);
+ if (rc < 0) {
+ RANAP_DEBUG("Rewriting transport layer information failed, invalid address!\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ old_transport_layer_information = rab_setup_or_modify_item_first->transportLayerInformation;
+ new_transport_layer_information = ranap_new_transp_info_rtp(&ip_addr, true); //<============= FIXME!
+ OSMO_ASSERT(new_transport_layer_information);
+ rab_setup_or_modify_item_first->transportLayerInformation = new_transport_layer_information;
+ } else {
+ RANAP_DEBUG("Rewriting transport layer information failed, no bindingID (port)!\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Reencode transport-layer-information */
+ rc = ANY_fromType_aper(&protocol_ie_field_pair->firstValue, &asn_DEF_RANAP_RAB_SetupOrModifyItemFirst,
+ rab_setup_or_modify_item_first);
+ if (rc < 0) {
+ RANAP_DEBUG("Rewriting transport layer information failed, could not reencode\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Do the final encoding */
+ rc = ranap_rab_ass_req_encode(data, data_len, rab_assignment_request_ies);
+ if (rc < 0)
+ rc = -EINVAL;
+
+error:
+ /* Restore original state of the modified ASN.1 struct so that the asn1c free mechanisms can work properly */
+ if (old_transport_layer_information)
+ rab_setup_or_modify_item_first->transportLayerInformation = old_transport_layer_information;
+
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, rab_setup_or_modify_item_first);
+ if (new_transport_layer_information)
+ ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, new_transport_layer_information);
+early_error:
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyList,
+ &rab_assignment_request_ies->raB_SetupOrModifyList);
+ return rc;
+}
+
+/*! Replace IP address and port in the transport-layer-address that is contained inside RAB AssignmentResponse.
+ * \ptmap[inout] data buffer with ASN.1 encoded message.
+ * \ptmap[in] data_len length of buffer with ASN.1 encoded message.
+ * \ptmap[in] addr buffer that contains the new RTP stream IP address.
+ * \ptmap[in] port new RTP stream IP port number (host byte order).
+ * \returns resulting message length on success; negative on error. */
+int ranap_rab_ass_resp_replace_inet_addr(uint8_t *data, unsigned int data_len, const char *addr, uint32_t port)
+{
+ RANAP_RAB_AssignmentResponseIEs_t _rab_assignment_response_ies;
+ RANAP_RAB_AssignmentResponseIEs_t *rab_assignment_response_ies = &_rab_assignment_response_ies;
+ RANAP_IE_t *setup_or_modified_list_ie;
+ RANAP_RAB_SetupOrModifiedItemIEs_t _rab_setup_or_modified_items_ies;
+ RANAP_RAB_SetupOrModifiedItemIEs_t *rab_setup_or_modified_items_ies = &_rab_setup_or_modified_items_ies;
+ RANAP_RAB_SetupOrModifiedItem_t *rab_setup_or_modified_item;
+ RANAP_TransportLayerInformation_t *temp_transport_layer_information = NULL;
+ RANAP_TransportLayerAddress_t *old_transport_layer_address = NULL;
+ RANAP_IuTransportAssociation_t *old_iu_transport_association = NULL;
+ struct osmo_sockaddr ip_addr;
+ struct osmo_sockaddr_str sockaddr_str;
+ int rc;
+
+ rc = ranap_rab_ass_resp_decode(rab_assignment_response_ies, data, data_len);
+ if (rc < 0)
+ return -EINVAL;
+
+ setup_or_modified_list_ie = setup_or_modif_item_from_rab_ass_resp(rab_assignment_response_ies);
+ if (!setup_or_modified_list_ie) {
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ rc = ranap_decode_rab_setupormodifieditemies_fromlist(rab_setup_or_modified_items_ies,
+ &setup_or_modified_list_ie->value);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto early_error;
+ }
+
+ rab_setup_or_modified_item = &rab_setup_or_modified_items_ies->raB_SetupOrModifiedItem;
+
+ /* Generate a temporary transport layer information, from which we can use the transport layer address and
+ * the iu transport association to update the setup or modified item */
+ sockaddr_str = (struct osmo_sockaddr_str) {
+ .af = AF_INET,
+ .port = port,
+ };
+ osmo_strlcpy(sockaddr_str.ip, addr, INET6_ADDRSTRLEN);
+ rc = osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &ip_addr.u.sas);
+ if (rc < 0) {
+ RANAP_DEBUG("Rewriting transport layer address failed, invalid address!\n");
+ rc = -EINVAL;
+ goto error;
+ }
+ temp_transport_layer_information = ranap_new_transp_info_rtp(&ip_addr, true); //<============= FIXME!
+ OSMO_ASSERT(temp_transport_layer_information);
+
+ /* Replace transport layer address and iu transport association */
+ old_transport_layer_address = rab_setup_or_modified_item->transportLayerAddress;
+ old_iu_transport_association = rab_setup_or_modified_item->iuTransportAssociation;
+ rab_setup_or_modified_item->transportLayerAddress = &temp_transport_layer_information->transportLayerAddress;
+ rab_setup_or_modified_item->iuTransportAssociation = &temp_transport_layer_information->iuTransportAssociation;
+
+ /* Reencode modified setup or modified list */
+ rc = ANY_fromType_aper(&setup_or_modified_list_ie->value, &asn_DEF_RANAP_RAB_SetupOrModifiedItem,
+ rab_setup_or_modified_items_ies);
+ if (rc < 0) {
+ RANAP_DEBUG("Rewriting transport layer address failed, could not reencode\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Do the final encoding */
+ rc = ranap_rab_ass_resp_encode(data, data_len, rab_assignment_response_ies);
+ if (rc < 0)
+ rc = -EINVAL;
+
+error:
+ /* Restore original state of the modified ASN.1 struct so that the asn1c free mechanisms can work properly */
+ if (old_transport_layer_address)
+ rab_setup_or_modified_item->transportLayerAddress = old_transport_layer_address;
+ if (old_iu_transport_association)
+ rab_setup_or_modified_item->iuTransportAssociation = old_iu_transport_association;
+
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedItem, rab_setup_or_modified_items_ies);
+ if (temp_transport_layer_information)
+ ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, temp_transport_layer_information);
+early_error:
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedList,
+ &rab_assignment_response_ies->raB_SetupOrModifiedList);
+ return rc;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 899e436..f9da51f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,4 +1,5 @@
SUBDIRS = \
+ ranap_rab_ass \
$(NULL)
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
diff --git a/tests/test_common.c b/tests/test_common.c
new file mode 100644
index 0000000..b9527c1
--- /dev/null
+++ b/tests/test_common.c
@@ -0,0 +1,111 @@
+/* Common osmo-iuh test stub code */
+
+/* (C) 2015 by Sysmocom s.f.m.c. GmbH
+ * Author: Daniel Willmann <dwillmann(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/sctp.h>
+#include <arpa/inet.h>
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/logging.h>
+
+#include <osmocom/ranap/ranap_common.h>
+
+#include <osmocom/hnbgw/hnbgw.h>
+
+static const struct log_info_cat log_cat[] = {
+ [DMAIN] = {
+ .name = "DMAIN", .loglevel = LOGL_INFO, .enabled = 1,
+ .color = "",
+ .description = "Main program",
+ },
+ [DHNBAP] = {
+ .name = "DHNBAP", .loglevel = LOGL_DEBUG, .enabled = 1,
+ .color = "",
+ .description = "Home Node B Application Part",
+ },
+ [DRANAP] = {
+ .name = "RANAP", .loglevel = LOGL_DEBUG, .enabled = 1,
+ .color = "",
+ .description = "RAN Application Part",
+ },
+ [DRUA] = {
+ .name = "RUA", .loglevel = LOGL_DEBUG, .enabled = 1,
+ .color = "",
+ .description = "RANAP User Adaptation",
+ },
+};
+
+static const struct log_info test_log_info = {
+ .cat = log_cat,
+ .num_cat = ARRAY_SIZE(log_cat),
+};
+
+static void *msgb_ctx;
+
+int test_common_init(void)
+{
+ int rc;
+
+ msgb_ctx = msgb_talloc_ctx_init(NULL, 0);
+ talloc_asn1_ctx = talloc_named_const(NULL, 0, "asn1_context");
+
+ rc = osmo_init_logging(&test_log_info);
+ if (rc < 0)
+ exit(1);
+
+ ranap_set_log_area(DRANAP);
+
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+ return rc;
+}
+
+void test_common_cleanup(void)
+{
+ if (talloc_total_blocks(msgb_ctx) != 1
+ || talloc_total_size(msgb_ctx) != 0)
+ talloc_report_full(msgb_ctx, stderr);
+
+ OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
+ OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
+ talloc_free(msgb_ctx);
+
+ if (talloc_total_blocks(talloc_asn1_ctx) != 1
+ || talloc_total_size(talloc_asn1_ctx) != 0)
+ talloc_report_full(talloc_asn1_ctx, stderr);
+
+ OSMO_ASSERT(talloc_total_blocks(talloc_asn1_ctx) == 1);
+ OSMO_ASSERT(talloc_total_size(talloc_asn1_ctx) == 0);
+ talloc_free(talloc_asn1_ctx);
+}
diff --git a/tests/test_common.h b/tests/test_common.h
new file mode 100644
index 0000000..836d999
--- /dev/null
+++ b/tests/test_common.h
@@ -0,0 +1,4 @@
+#pragma once
+
+int test_common_init(void);
+void test_common_cleanup(void);
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 65d1ca0..41d0449 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -1,8 +1,9 @@
AT_INIT
AT_BANNER([Regression tests.])
-#AT_SETUP([foobar])
-#AT_KEYWORDS([foobar])
-#cat $abs_srcdir/foobar/foobar_test.ok > expout
-#AT_CHECK([$abs_top_builddir/tests/foobar/foobar_test], [], [expout], [ignore])
-#AT_CLEANUP
+AT_SETUP([ranap-rab-ass])
+AT_KEYWORDS([ranap-rab-ass])
+cat $abs_srcdir/ranap_rab_ass/ranap_rab_ass_test.ok > expout
+cat $abs_srcdir/ranap_rab_ass/ranap_rab_ass_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/ranap_rab_ass/ranap_rab_ass_test], [0], [expout], [experr])
+AT_CLEANUP
\ No newline at end of file
--
To view, visit https://gerrit.osmocom.org/c/osmo-hnbgw/+/26792
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: I58b542bf23ff5e1db2ccf6833fec91d9ba332837
Gerrit-Change-Number: 26792
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newchange
3
32
31 Jan '22
Attention is currently required from: laforge.
pespin has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-e1d/+/27016 )
Change subject: Allow configuration of interfaces/lines via VTY
......................................................................
Patch Set 6: Code-Review+1
(1 comment)
File src/usb.c:
https://gerrit.osmocom.org/c/osmo-e1d/+/27016/comment/112a59ae_5803b92c
PS6, Line 565: /* try to find the matching interface config create by the vty */
created by
--
To view, visit https://gerrit.osmocom.org/c/osmo-e1d/+/27016
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-e1d
Gerrit-Branch: master
Gerrit-Change-Id: I89b57b688b68901f87d9683ab9294772ee747d77
Gerrit-Change-Number: 27016
Gerrit-PatchSet: 6
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: tnt <tnt(a)246tNt.com>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Comment-Date: Mon, 31 Jan 2022 19:13:14 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Gerrit-MessageType: comment
1
0