Compare commits

...

28 Commits
1.2.0 ... 1.3.0

Author SHA1 Message Date
Pau Espin Pedrol
44dfe698fa Bump version: 1.2.1.25-7893-dirty → 1.3.0
Change-Id: I5283bfcdcee218d2db25cd10b9a17ffe2129efb6
2022-06-29 12:42:35 +02:00
Harald Welte
7893028ef6 update URLs (git -> https; gitea)
Change-Id: Ic9da2fbbc473b1ac5bc4e29c8dd77533455930d4
2022-06-18 14:02:41 +02:00
Pau Espin Pedrol
62fb1dea61 mgw_fsm: Simplify cleanup paths
Let's have a unified way of freeing the FSM instance once it was
allocated, otherwise it's far more difficult to understand and maintain.

Change-Id: I8883e737fa112cff57834abae7ef272388a54edb
2022-06-15 11:55:21 +02:00
Pau Espin Pedrol
304f7646c9 mgw_fsm: Fix error path accessing uninitialized fsm ptr
The error handling of the error path was wrong. Let's remove the "fi"
variable to avoid more of such errors. Furthermore, add an assert to
clarify for the reader that the map->mgw_fi will be freed before
allocating a new FSM instance below.

Change-Id: I9d3bca552bfa77f5e18f75bedad8d422f74df1f8
2022-06-14 18:41:48 +02:00
Pau Espin Pedrol
87e03208af mgw_fsm: Change macro to not use local variables implicitly
This is misleading for readers since it may access variables which may
be uninitialized or in a wrong state. Furthermore, we want to pass some
other variable name in a follow up patch.

This effectively allows the compiler to warn about uninitialized used of
a fi var in line 661.

Change-Id: Id694f51bb2918fd27da87b3f4a905727cd7f5de6
2022-06-14 18:40:11 +02:00
Pau Espin Pedrol
de8b170d1a cosmetic: mgw_fsm: Fix typo in log
Change-Id: I80aa61a288ab37c51510af67c784498f5949fc50
2022-06-14 18:07:52 +02:00
Pau Espin Pedrol
1d1839a34b mgw_fsm: Improve logging
Change-Id: I14785b6bc798c3bae8c552bccb55ca4fa9f2f416
2022-06-14 18:07:32 +02:00
Pau Espin Pedrol
8c7aae87b0 mgw_fsm: Mark structs as static const
Change-Id: Ie62f28587c08296429c0dabda7b6add67ffa010c
2022-06-14 17:46:56 +02:00
Neels Hofmeyr
ff2fbdf998 fix segfault in error handling for mgw_fi == NULL
In mgw_fsm_handle_rab_ass_resp(), a NULL mgw_fi is handled as error,
but the error handling fails to return. The function continues to
dereference mgw_fi. Add missing return.

Related: SYS#5995
Change-Id: I3e98dc3a00145ec1f71c678bbf45debfd4276237
2022-06-10 11:40:33 +02:00
Neels Hofmeyr
2c91bd66a1 add option to send SCCP CR without payload
It is reported that a third-party SGSN is rejecting SCCP CR when the
SCCP message part exceeds a certain length. The solution is to first
send an SCCP CR without payload, and send the payload in a DT later.

Add config option

  hnbgw
   sccp cr max-payload-len <0-999999>

If the RANAP payload surpasses the given length, osmo-hnbgw will first
send an SCCP CR without payload, cache the RANAP payload, and put that
in an SCCP DT once the SCCP CC is received.

The original idea was to limit the size of the entire SCCP part of the
message, but I'm currently not sure how to determine that without
copying much of the osmo_sccp code. I figured using a limit on the RANAP
payload is sufficient. To avoid the error with above third-party SGSN,
the easy solution is to set max-payload-len to 0, so that we always get
a separate SCCP CR without payload.

Related: SYS#5968
Related: I827e081eaacfb8e76684ed1560603e6c8f896c38 (osmo-ttcn3-hacks)
Change-Id: If0c5c0a76e5230bf22871f527dcb2dbdf34d7328
2022-06-07 22:51:26 +02:00
Neels Hofmeyr
afbcae6366 tweak comments in rua_to_scu()
Change-Id: I227a5e6b869da453fa72ff0eebaa1e95aa9625e6
2022-06-07 22:51:25 +02:00
Neels Hofmeyr
da9d08c94e allow calling rua_to_scu() without data
There can be SCCP primitives without payload data, e.g. an "empty" SCCP
Connection Request.

Patch 'mgw_fsm: add MGW support to osmo-hnbgw' added RANAP message
decoding that lacks a guard against NULL data. Fix that: do not try to
decode NULL data.

Related: SYS#5968
Change-Id: Id755e769e82ace7203460ea1b3c847c2c90d41bf
2022-06-07 22:50:37 +02:00
Neels Hofmeyr
0ca9567fb2 use osmo_select_main_ctx(), tweak log in handle_cn_conn_conf()
Upcoming patch adds to this function. Let me first combine those four
LOGP() to a single one, use proper osmo_sccp_addr_to_str_c(OTC_SELECT).

To be able to use OTC_SELECT, switch hnbgw.c to osmo_select_main_ctx().

Related: SYS#5968
Change-Id: I1e0ea0a883e8cf65e6cfb45ed9b6f3d8fb7c59eb
2022-06-07 18:09:19 +02:00
Philipp Maier
be9ed71631 ranap_rab_ass: check for more than one RAB assignment req
The spec permits RAB AssignmentRequests with multiple RABs at a time.
Even though one voice call is assigned only one RAB in practice. Since
the current FSM implementation only supports a 1:1 scenario, lets check
if the MSC really assigns only one RAB and block RAB Assignments that do
not fit in this scheme.

Change-Id: I0f1d868fd0b4dc413533d6fcc5482862825181be
Related: OS#5152
2022-02-28 10:22:16 +01:00
Philipp Maier
d1f4b9b9a1 mgw_fsm: release call when FSM is not created
While the FSM is created the RAB Assignment Requests is checked and
parsed. In case of failure the context is freed, but the CN is not
informed about the problem. The RAB AssignmentRequest will then most
likely time out. However, lets make sure the call is released by re
requesting an IU Release.

Change-Id: I1904f7e95d86bbcecee14f8721bd4075d0e33ab4
Related: OS#5152
2022-02-25 15:12:18 +01:00
Philipp Maier
b5508f98ef osmo-hnbgw.cfg: use local port 2729 as default for MGCP client
There are several osmo processes that talk to osmo-mgw via
osmo-mgcp-client. The sample config for osmo-bsc suggest 2727 and the
sample config for osmo-msc suggests 2728 as local port default. To make
it less likely for users to get port collisions whlie setting up their
networks we should use a different port for osmo-hnbgw. Lets use 2729.

Change-Id: I55179c2bff3e6ef0e54fee6b1b90fc76f541e58e
2022-02-25 15:12:18 +01:00
Philipp Maier
9e46544486 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
2022-02-24 11:29:09 +01:00
Philipp Maier
7dd3a61b57 overview.adoc: update network diagram
The network diagram in the manual lacks the recently added
co located MGW.

Change-Id: Ica1782a407f6b944aa26748b54055168f5d250c3
Related: OS#5152
2022-02-24 11:28:50 +01:00
Philipp Maier
81f1751896 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#5152
2022-02-24 10:51:30 +01:00
Philipp Maier
e7c66defc2 ranap_rab_ass_test: cosmetic: correct test function names
The test function naming follows an older scheme, lets use the current
scheme.

Change-Id: Ib9db9d86e01551c8d9d8f8c4933025ca20ce5624
Related: OS#5152
2022-02-23 15:50:43 +01:00
Philipp Maier
f5742a3bed ranap_rab_ass: add function to check if RAB is in ReleaseList
A RANAP RAB-AssignmentRelease may contain a ReleaseList. In order to
detect that a RAB is about to be released we need to be able to check if
the RAB we are dealing with is contained in such a ReleaseList.

Change-Id: I5b67cc2d35d11de7a09e66c181a1fdd5a58c75bb
Related: OS#5152
2022-02-23 15:50:43 +01:00
Philipp Maier
efe4850e75 ranap_rab_ass: add function to check if RAB is in FailureList
A RANAP RAB-AssignmentResponse may contain a FailedList. In order to
detect that a RAB Assignment failed at the HNB we need to be able to
check if the RAB we are dealing with is contained an such a FailedList.

Change-Id: I4319f7caa45ea758ccd792cc8570521df075cf45
Related: OS#5152
2022-02-23 15:38:17 +01:00
Philipp Maier
0c465b0f68 ranap_rab_ass: ensure specific rab_id
The parser functions currently ignore the rab_id. An exception is
ranap_rab_ass_req_ies_extract_inet_addr, which extracts the rab_id
of the first RAB. To make the handling of the RAB assignment parsing
more robust lets add a rab_id parameter to the other functions. This
parameter can then be used to ensure thet the correct RAB is handled.

Change-Id: I2259ffce9f4b508c555d60618c5983ac6294e0ae
Related: OS#5152
2022-02-11 11:00:35 +01:00
Philipp Maier
7daa502a2d 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
Related: OS#5152
2022-02-02 10:51:38 +01:00
Philipp Maier
dddafa60ea hbgw_hnbap: use osmo_plmn_from_bcd instead of gsm48_mcc_mnc_from_bcd
The function gsm48_mcc_mnc_from_bcd is deprecated. Lets use
osmo_plmn_from_bcd instead.

Change-Id: I01406a4cf86d4f3ed162c9df55880941e54d654e
2022-01-14 17:31:25 +01:00
Philipp Maier
60008b1457 hnbgw_cn.c: fix sourcecode formatting
Change-Id: I50ec3a4a5c2f65c85adc177f83123991f949e9cf
2022-01-12 16:59:45 +01:00
Pau Espin Pedrol
dd29038a8f Bump version: 1.2.0.1-6d8e → 1.2.1
Change-Id: I99981bf8c9a340accc80623b56be5de58626648a
2022-01-11 18:55:50 +01:00
Pau Espin Pedrol
6d8e37f610 Do not turn some compiler warnings into errors by default
We build with --enable-werror during development and in CI. If the code
is built with a different compiler that throws additional warnings, it
should not stop the build.

This patch also effectively removes dependency on autoconf-archive.

Related: OS#5289
Related: SYS#5789
Change-Id: I7512a4230a5bbba6c67172c2572c98b9ab20c923
2022-01-11 18:30:13 +01:00
33 changed files with 2369 additions and 97 deletions

View File

@@ -19,9 +19,9 @@ GIT Repository
You can clone from the official osmo-hnbgw.git repository using
git clone git://git.osmocom.org/osmo-hnbgw.git
git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-hnbgw
There is a cgit interface at https://git.osmocom.org/osmo-hnbgw/
There is a web interface at https://gitea.osmocom.org/cellular-infrastructure/osmo-hnbgw
Documentation
-------------

View File

@@ -36,11 +36,6 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
fi
PKG_PROG_PKG_CONFIG([0.20])
dnl check for AX_CHECK_COMPILE_FLAG
m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [
AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
])
dnl checks for libraries
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
@@ -56,16 +51,16 @@ AC_SEARCH_LIBS([sctp_recvmsg], [sctp], [
LIBS=$old_LIBS
PKG_CHECK_MODULES(LIBASN1C, libasn1c >= 0.9.30)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.5.0)
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(LIBOSMOCORE, libosmocore >= 1.7.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.7.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.7.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.7.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMORUA, libosmo-rua >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOHNBAP, libosmo-hnbap >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOMGCPCLIENT, libosmo-mgcp-client >= 1.10.0)
dnl checks for header files
AC_HEADER_STDC
@@ -113,13 +108,6 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],
CFLAGS="$saved_CFLAGS"
AC_SUBST(SYMBOL_VISIBILITY)
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CFLAGS="$CFLAGS -Wnull-dereference"])
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
# Coverage build taken from WebKit's configure.in
AC_MSG_CHECKING([whether to enable code coverage support])
AC_ARG_ENABLE(coverage,
@@ -154,7 +142,7 @@ if test "x$enable_ext_tests" = "xyes" ; then
fi
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
AC_MSG_ERROR([Please install git://osmocom.org/python/osmo-python-tests to run the VTY/CTRL tests.])
AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.])
fi
fi
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
@@ -233,6 +221,7 @@ AC_OUTPUT(
src/osmo-hnbgw/Makefile
tests/Makefile
tests/atlocal
tests/ranap_rab_ass/Makefile
doc/Makefile
doc/examples/Makefile
doc/manuals/Makefile

View File

@@ -35,6 +35,7 @@ osmo-build-dep.sh libosmo-netif
osmo-build-dep.sh libosmo-sccp
osmo-build-dep.sh libasn1c
osmo-build-dep.sh osmo-iuh
osmo-build-dep.sh osmo-mgw
# Additional configure options and depends
CONFIG=""

View File

@@ -24,7 +24,6 @@ License: AGPL-3.0-or-later AND GPL-2.0-or-later
Group: Hardware/Mobile
URL: https://osmocom.org/projects/osmohnbgw
Source: %{name}-%{version}.tar.xz
BuildRequires: autoconf-archive
BuildRequires: automake >= 1.9
BuildRequires: libtool >= 2
BuildRequires: lksctp-tools-devel
@@ -33,18 +32,19 @@ BuildRequires: pkgconfig >= 0.20
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libcrypto) >= 0.9.5
BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0
BuildRequires: pkgconfig(libosmo-sigtran) >= 1.5.0
BuildRequires: pkgconfig(libosmoabis) >= 1.2.0
BuildRequires: pkgconfig(libosmotrau) >= 1.2.0
BuildRequires: pkgconfig(libosmocore) >= 1.6.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.6.0
BuildRequires: pkgconfig(libosmogb) >= 1.6.0
BuildRequires: pkgconfig(libosmogsm) >= 1.6.0
BuildRequires: pkgconfig(libosmovty) >= 1.6.0
BuildRequires: pkgconfig(libosmo-hnbap) >= 1.1.0
BuildRequires: pkgconfig(libosmo-ranap) >= 1.1.0
BuildRequires: pkgconfig(libosmo-rua) >= 1.1.0
BuildRequires: pkgconfig(libosmo-mgcp-client) >= 1.10.0
BuildRequires: pkgconfig(libosmo-netif) >= 1.2.0
BuildRequires: pkgconfig(libosmo-sigtran) >= 1.6.0
BuildRequires: pkgconfig(libosmoabis) >= 1.3.0
BuildRequires: pkgconfig(libosmotrau) >= 1.3.0
BuildRequires: pkgconfig(libosmocore) >= 1.7.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.7.0
BuildRequires: pkgconfig(libosmogb) >= 1.7.0
BuildRequires: pkgconfig(libosmogsm) >= 1.7.0
BuildRequires: pkgconfig(libosmovty) >= 1.7.0
BuildRequires: pkgconfig(libosmo-hnbap) >= 1.3.0
BuildRequires: pkgconfig(libosmo-ranap) >= 1.3.0
BuildRequires: pkgconfig(libosmo-rua) >= 1.3.0
BuildRequires: pkgconfig(talloc)
BuildRequires: pkgconfig(libasn1c) >= 0.9.30
%{?systemd_requires}

43
debian/changelog vendored
View File

@@ -1,3 +1,46 @@
osmo-hnbgw (1.3.0) unstable; urgency=medium
[ Philipp Maier ]
* hnbgw_cn.c: fix sourcecode formatting
* hbgw_hnbap: use osmo_plmn_from_bcd instead of gsm48_mcc_mnc_from_bcd
* ranap_rab_ass: add decoder and rewrite functions for RAB-AssignmentRequest/Response
* ranap_rab_ass: ensure specific rab_id
* ranap_rab_ass: add function to check if RAB is in FailureList
* ranap_rab_ass: add function to check if RAB is in ReleaseList
* ranap_rab_ass_test: cosmetic: correct test function names
* mgw_fsm: add MGW support to osmo-hnbgw
* overview.adoc: update network diagram
* running.adoc: explain MGW configuration
* osmo-hnbgw.cfg: use local port 2729 as default for MGCP client
* mgw_fsm: release call when FSM is not created
* ranap_rab_ass: check for more than one RAB assignment req
[ Neels Hofmeyr ]
* use osmo_select_main_ctx(), tweak log in handle_cn_conn_conf()
* allow calling rua_to_scu() without data
* tweak comments in rua_to_scu()
* add option to send SCCP CR without payload
* fix segfault in error handling for mgw_fi == NULL
[ Pau Espin Pedrol ]
* mgw_fsm: Mark structs as static const
* mgw_fsm: Improve logging
* cosmetic: mgw_fsm: Fix typo in log
* mgw_fsm: Change macro to not use local variables implicitly
* mgw_fsm: Fix error path accessing uninitialized fsm ptr
* mgw_fsm: Simplify cleanup paths
[ Harald Welte ]
* update URLs (git -> https; gitea)
-- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 29 Jun 2022 12:42:35 +0200
osmo-hnbgw (1.2.1) unstable; urgency=medium
* Do not turn some compiler warnings into errors by default
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 11 Jan 2022 18:55:50 +0100
osmo-hnbgw (1.2.0) unstable; urgency=medium
* Initial structure + import code from osmo-iuh.git

22
debian/control vendored
View File

@@ -6,7 +6,6 @@ Build-Depends: debhelper (>=9),
dh-autoreconf,
autotools-dev,
autoconf,
autoconf-archive,
automake,
libtool,
pkg-config,
@@ -14,17 +13,18 @@ Build-Depends: debhelper (>=9),
libtalloc-dev,
libasn1c-dev (>= 0.9.30),
libsctp-dev,
libosmocore-dev (>= 1.6.0),
libosmo-sigtran-dev (>= 1.5.0),
libosmo-abis-dev (>= 1.2.0),
libosmo-netif-dev (>= 1.1.0),
libosmo-hnbap-dev (>= 1.1.0),
libosmo-ranap-dev (>= 1.1.0),
libosmo-rua-dev (>= 1.1.0),
osmo-gsm-manuals-dev (>= 1.2.0)
libosmocore-dev (>= 1.7.0),
libosmo-sigtran-dev (>= 1.6.0),
libosmo-abis-dev (>= 1.3.0),
libosmo-netif-dev (>= 1.2.0),
libosmo-mgcp-client-dev (>= 1.10.0),
libosmo-hnbap-dev (>= 1.3.0),
libosmo-ranap-dev (>= 1.3.0),
libosmo-rua-dev (>= 1.3.0),
osmo-gsm-manuals-dev (>= 1.3.0)
Standards-Version: 3.9.8
Vcs-Git: git://git.osmocom.org/osmo-hnbgw.git
Vcs-Browser: https://git.osmocom.org/osmo-hnbgw/
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-hnbgw
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-hnbgw
Homepage: https://projects.osmocom.org/projects/osmo-hnbgw
Package: osmo-hnbgw

2
debian/copyright vendored
View File

@@ -1,6 +1,6 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: osmo-hnbgw
Source: git://git.osmocom.org/osmo-hnbgw
Source: https://gitea.osmocom.org/cellular-infrastructure/osmo-hnbgw
Files: *
Copyright: 2021 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>

View File

@@ -23,3 +23,9 @@ hnbgw
iuh
local-ip 0.0.0.0
hnbap-allow-tmsi 1
mgcp
mgw remote-ip 127.0.0.1
mgw local-port 2729
mgw remote-port 2427
mgw reset-endpoint rtpbridge/*

View File

@@ -15,16 +15,20 @@ diagram:
[[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 | | | | | | |
| | | | +---------+ +---------+
| |<---IuUP--\ | |
| |<-------. | | | +---------+ +------+
+------------+ | | | |<--IuPS-->| SGSN |<--GTP-C-->| GGSN |
| | +----------+ | | .------>| |
| | +---------+ | +------+
| | +----------+ +---------+ |
| \-->| MGW |<--IuUP-->| MGW | |
| | (HNB-GW) | | (MSC) | |
| +----------+ +---------+ |
`--------------------GTP-U----------------'
----
The HNB-GW performs a translation interface between the IuCS/IuPS interfaces on the one hand

View File

@@ -117,3 +117,25 @@ hnbgw
local-ip 10.9.8.7
local-port 29169
----
==== Configure co-located media gateway
OsmoHNBGW requires a co-located OsmoMGW instance. The purpose of the co-located
media gateway is to relay the RTP traffic between hNodeB and the core network.
For security reasons the RAN network is kept separate and isolated from the
core network. Both networks will usually have no transparent routing in between
them. The co-located media gateway provides an interface between hNodeB and core
network across this boundary.
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/*
----

View File

@@ -1,4 +1,5 @@
noinst_HEADERS = \
vty.h \
context_map.h hnbgw.h hnbgw_cn.h \
hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h
hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h \
ranap_rab_ass.h mgw_fsm.h tdefs.h

View File

@@ -2,6 +2,9 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/rua/RUA_CN-DomainIndicator.h>
struct msgb;
enum hnbgw_context_map_state {
MAP_S_NULL,
@@ -33,8 +36,14 @@ struct hnbgw_context_map {
bool is_ps;
/* SCCP User SAP connection ID */
uint32_t scu_conn_id;
/* Pending data to be sent: when we send an "empty" SCCP CR first, the initial RANAP message will be sent in a
* separate DT once the CR is confirmed. This caches the initial RANAP message. */
struct msgb *cached_msg;
enum hnbgw_context_map_state state;
/* FSM instance for the MGW */
struct osmo_fsm_inst *mgw_fi;
};
@@ -46,6 +55,8 @@ context_map_alloc_by_hnb(struct hnb_context *hnb, uint32_t rua_ctx_id,
struct hnbgw_context_map *
context_map_by_cn(struct hnbgw_cnlink *cn, uint32_t scu_conn_id);
int context_map_send_cached_msg(struct hnbgw_context_map *map);
void context_map_deactivate(struct hnbgw_context_map *map);
int context_map_init(struct hnb_gw *gw);

View File

@@ -16,6 +16,7 @@ enum {
DHNBAP,
DRUA,
DRANAP,
DMGW,
};
#define LOGHNB(x, ss, lvl, fmt, args ...) \
@@ -133,6 +134,8 @@ struct hnb_gw {
bool hnbap_allow_tmsi;
/*! print hnb-id (true) or MCC-MNC-LAC-RAC-SAC (false) in logs */
bool log_prefix_hnb_id;
unsigned int max_sccp_cr_payload_len;
struct mgcp_client_conf *mgcp_client;
} config;
/*! SCTP listen socket for incoming connections */
struct osmo_stream_srv_link *iuh;
@@ -151,6 +154,7 @@ struct hnb_gw {
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;
@@ -172,3 +176,5 @@ void hnb_context_release(struct hnb_context *ctx);
void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx);
int hnbgw_vty_go_parent(struct vty *vty);
bool hnbgw_requires_empty_sccp_cr(struct hnb_gw *gw, unsigned int ranap_msg_len);

View File

@@ -2,6 +2,7 @@
#include <osmocom/hnbgw/hnbgw.h>
#include <osmocom/rua/RUA_Cause.h>
#include <osmocom/rua/RUA_CN-DomainIndicator.h>
int hnbgw_rua_rx(struct hnb_context *hnb, struct msgb *msg);
int hnbgw_rua_init(void);
@@ -11,3 +12,9 @@ int rua_tx_dt(struct hnb_context *hnb, int is_ps, uint32_t context_id,
const uint8_t *data, unsigned int len);
int rua_tx_disc(struct hnb_context *hnb, int is_ps, uint32_t context_id,
const RUA_Cause_t *cause, const uint8_t *data, unsigned int len);
int rua_to_scu(struct hnb_context *hnb,
RUA_CN_DomainIndicator_t cN_DomainIndicator,
enum osmo_scu_prim_type type,
uint32_t context_id, uint32_t cause,
const uint8_t *data, unsigned int len);

View File

@@ -0,0 +1,7 @@
#pragma once
#include <osmocom/ranap/ranap_ies_defs.h>
int handle_rab_ass_req(struct hnbgw_context_map *map, struct osmo_prim_hdr *oph, ranap_message *message);
int mgw_fsm_handle_rab_ass_resp(struct hnbgw_context_map *map, struct osmo_prim_hdr *oph, ranap_message *message);
int mgw_fsm_release(struct hnbgw_context_map *map);

View File

@@ -0,0 +1,21 @@
#pragma once
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_encode(uint8_t *data, unsigned int len,
RANAP_RAB_AssignmentResponseIEs_t *rab_assignment_response_ies);
int ranap_rab_ass_req_ies_extract_inet_addr(struct osmo_sockaddr *addr, uint8_t *rab_id,
RANAP_RAB_AssignmentRequestIEs_t *ies, unsigned int index);
int ranap_rab_ass_resp_ies_extract_inet_addr(struct osmo_sockaddr *addr, RANAP_RAB_AssignmentResponseIEs_t *ies,
uint8_t rab_id);
int ranap_rab_ass_req_ies_replace_inet_addr(RANAP_RAB_AssignmentRequestIEs_t *ies, struct osmo_sockaddr *addr,
uint8_t rab_id);
int ranap_rab_ass_resp_ies_replace_inet_addr(RANAP_RAB_AssignmentResponseIEs_t *ies, struct osmo_sockaddr *addr,
uint8_t rab_id);
bool ranap_rab_ass_req_ies_check_release(RANAP_RAB_AssignmentRequestIEs_t *ies, uint8_t rab_id);
bool ranap_rab_ass_resp_ies_check_failure(RANAP_RAB_AssignmentResponseIEs_t *ies, uint8_t rab_id);
int ranap_rab_ass_req_ies_get_count(RANAP_RAB_AssignmentRequestIEs_t *ies);

View File

@@ -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[];

View File

@@ -7,5 +7,6 @@ enum osmo_iuh_vty_node {
IUH_NODE,
IUCS_NODE,
IUPS_NODE,
MGCP_NODE,
};

View File

@@ -19,6 +19,7 @@ AM_CFLAGS = \
$(LIBOSMORUA_CFLAGS) \
$(LIBOSMORANAP_CFLAGS) \
$(LIBOSMOHNBAP_CFLAGS) \
$(LIBOSMOMGCPCLIENT_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
@@ -37,6 +38,9 @@ osmo_hnbgw_SOURCES = \
hnbgw_vty.c \
context_map.c \
hnbgw_cn.c \
ranap_rab_ass.c \
mgw_fsm.c \
tdefs.c \
$(NULL)
osmo_hnbgw_LDADD = \
@@ -51,5 +55,7 @@ osmo_hnbgw_LDADD = \
$(LIBOSMORUA_LIBS) \
$(LIBOSMORANAP_LIBS) \
$(LIBOSMOHNBAP_LIBS) \
$(LIBOSMOMGCPCLIENT_LIBS) \
$(LIBSCTP_LIBS) \
$(LIBOSMOMGCPCLIENT_LIBS) \
$(NULL)

View File

@@ -25,7 +25,9 @@
#include <osmocom/core/timer.h>
#include <osmocom/hnbgw/hnbgw.h>
#include <osmocom/hnbgw/hnbgw_rua.h>
#include <osmocom/hnbgw/context_map.h>
#include <osmocom/hnbgw/mgw_fsm.h>
const struct value_string hnbgw_context_map_state_names[] = {
{MAP_S_NULL , "not-initialized"},
@@ -129,6 +131,20 @@ context_map_by_cn(struct hnbgw_cnlink *cn, uint32_t scu_conn_id)
return NULL;
}
int context_map_send_cached_msg(struct hnbgw_context_map *map)
{
int rc;
if (!map || !map->cached_msg)
return 0;
rc = rua_to_scu(map->hnb_ctx,
map->is_ps ? RUA_CN_DomainIndicator_ps_domain : RUA_CN_DomainIndicator_cs_domain,
OSMO_SCU_PRIM_N_DATA, map->rua_ctx_id, 0,
msgb_data(map->cached_msg), msgb_length(map->cached_msg));
msgb_free(map->cached_msg);
map->cached_msg = NULL;
return rc;
}
void context_map_deactivate(struct hnbgw_context_map *map)
{
/* set the state to reserved. We still show up in the list and
@@ -137,6 +153,13 @@ void context_map_deactivate(struct hnbgw_context_map *map)
if (map->state != MAP_S_RESERVED2)
map->state = MAP_S_RESERVED1;
/* a possibly still existing MGW FSM must be terminated when the context
* map is deactivated. (this is a cornercase) */
if (map->mgw_fi) {
mgw_fsm_release(map);
OSMO_ASSERT(map->mgw_fi == NULL);
}
}
static struct osmo_timer_list context_map_tmr;

View File

@@ -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>
@@ -86,12 +88,19 @@ static struct hnb_gw *hnb_gw_create(void *ctx)
gw->config.iuh_local_port = IUH_DEFAULT_SCTP_PORT;
gw->config.log_prefix_hnb_id = true;
/* No limit by default, always include the initial RANAP message in the SCCP CR towards the CN.
* 999999 is the maximum value in hnbgw_vty.c */
gw->config.max_sccp_cr_payload_len = 999999;
gw->next_ue_ctx_id = 23;
INIT_LLIST_HEAD(&gw->hnb_list);
INIT_LLIST_HEAD(&gw->ue_list);
context_map_init(gw);
gw->config.mgcp_client = talloc_zero(tall_hnb_ctx, struct mgcp_client_conf);
mgcp_client_conf_init(gw->config.mgcp_client);
return gw;
}
@@ -338,6 +347,11 @@ void hnb_context_release(struct hnb_context *ctx)
talloc_free(ctx);
}
bool hnbgw_requires_empty_sccp_cr(struct hnb_gw *gw, unsigned int ranap_msg_len)
{
return ranap_msg_len > gw->config.max_sccp_cr_payload_len;
}
/*! call-back when the listen FD has something to read */
static int accept_cb(struct osmo_stream_srv_link *srv, int fd)
{
@@ -372,6 +386,11 @@ static const struct log_info_cat log_cat[] = {
.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 +700,19 @@ int main(int argc, char **argv)
}
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) {
@@ -690,7 +722,7 @@ int main(int argc, char **argv)
}
while (1) {
rc = osmo_select_main(0);
rc = osmo_select_main_ctx(0);
if (rc < 0)
exit(3);
}

View File

@@ -34,6 +34,11 @@
#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>
#include <osmocom/ranap/RANAP_ProcedureCode.h>
#include <osmocom/ranap/ranap_common.h>
#include <osmocom/ranap/ranap_common_ran.h>
#include <osmocom/ranap/RANAP_RANAP-PDU.h>
/***********************************************************************
* Outbound RANAP RESET to CN
@@ -266,7 +271,7 @@ static int handle_cn_ranap(struct hnbgw_cnlink *cnlink, const struct osmo_scu_un
int rc;
memset(pdu, 0, sizeof(*pdu));
dec_ret = aper_decode(NULL,&asn_DEF_RANAP_RANAP_PDU, (void **) &pdu,
dec_ret = aper_decode(NULL, &asn_DEF_RANAP_RANAP_PDU, (void **) &pdu,
data, len, 0, 0);
if (dec_ret.code != RC_OK) {
LOGP(DRANAP, LOGL_ERROR, "Error in RANAP ASN.1 decode\n");
@@ -324,18 +329,19 @@ static int handle_cn_conn_conf(struct hnbgw_cnlink *cnlink,
const struct osmo_scu_connect_param *param,
struct osmo_prim_hdr *oph)
{
/* we don't actually need to do anything, as RUA towards the HNB
* doesn't seem to know any confirmations to its CONNECT
* operation */
struct osmo_ss7_instance *ss7 = osmo_sccp_get_ss7(cnlink->gw->sccp.client);
LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() conn_id=%d, addrs: called=%s calling=%s responding=%s\n",
param->conn_id,
osmo_sccp_addr_to_str_c(OTC_SELECT, ss7, &param->called_addr),
osmo_sccp_addr_to_str_c(OTC_SELECT, ss7, &param->calling_addr),
osmo_sccp_addr_to_str_c(OTC_SELECT, ss7, &param->responding_addr));
LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() conn_id=%d\n",
param->conn_id);
LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() called_addr=%s\n",
inet_ntoa(param->called_addr.ip.v4));
LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() calling_addr=%s\n",
inet_ntoa(param->calling_addr.ip.v4));
LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() responding_addr=%s\n",
inet_ntoa(param->responding_addr.ip.v4));
/* Nothing needs to happen for RUA, RUA towards the HNB doesn't seem to know any confirmations to its CONNECT
* operation. */
/* If our initial SCCP CR was sent without data payload, then the initial RANAP message is cached and waiting to
* be sent as soon as the SCCP connection is confirmed. See if that is the case, send cached data. */
context_map_send_cached_msg(context_map_by_cn(cnlink, param->conn_id));
return 0;
}
@@ -345,10 +351,13 @@ static int handle_cn_data_ind(struct hnbgw_cnlink *cnlink,
struct osmo_prim_hdr *oph)
{
struct hnbgw_context_map *map;
ranap_message *message;
int rc;
/* connection-oriented data is always passed transparently
* towards the specific HNB, via a RUA connection identified by
* conn_id */
/* Usually connection-oriented data is always passed transparently towards the specific HNB, via a RUA
* connection identified by conn_id. An exception is made for RANAP RAB AssignmentRequest and
* RANAP RAB AssignmentResponse, since those messages contain transport layer information (RTP stream IP/Port),
* which is rewritten by the FSM that controls the co-located media gateway. */
map = context_map_by_cn(cnlink, param->conn_id);
if (!map) {
@@ -356,6 +365,28 @@ static int handle_cn_data_ind(struct hnbgw_cnlink *cnlink,
return 0;
}
/* Intercept RAB Assignment Request, Setup MGW FSM */
if (!map->is_ps) {
message = talloc_zero(map, ranap_message);
rc = ranap_ran_rx_co_decode(map, message, msgb_l2(oph->msg), msgb_l2len(oph->msg));
if (rc == 0) {
switch (message->procedureCode) {
case RANAP_ProcedureCode_id_RAB_Assignment:
/* mgw_fsm_alloc_and_handle_rab_ass_req() takes ownership of (ranap) message */
return handle_rab_ass_req(map, oph, message);
case RANAP_ProcedureCode_id_Iu_Release:
/* Any IU Release will terminate the MGW FSM, the message itsself is not passed to the
* FSM code. It is just forwarded normally by the rua_tx_dt() call below. */
mgw_fsm_release(map);
break;
}
ranap_ran_rx_co_free(message);
}
talloc_free(message);
}
return rua_tx_dt(map->hnb_ctx, map->is_ps, map->rua_ctx_id,
msgb_l2(oph->msg), msgb_l2len(oph->msg));
}

View File

@@ -398,6 +398,7 @@ static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in)
struct hnb_context *hnb;
HNBAP_HNBRegisterRequestIEs_t ies;
int rc;
struct osmo_plmn_id plmn;
rc = hnbap_decode_hnbregisterrequesties(&ies, in);
if (rc < 0) {
@@ -413,7 +414,9 @@ static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in)
ctx->id.sac = asn1str_to_u16(&ies.sac);
ctx->id.rac = asn1str_to_u8(&ies.rac);
ctx->id.cid = asn1bitstr_to_u28(&ies.cellIdentity);
gsm48_mcc_mnc_from_bcd(ies.plmNidentity.buf, &ctx->id.mcc, &ctx->id.mnc);
osmo_plmn_from_bcd(ies.plmNidentity.buf, &plmn);
ctx->id.mcc = plmn.mcc;
ctx->id.mnc = plmn.mnc;
llist_for_each_entry(hnb, &ctx->gw->hnb_list, list) {
if (hnb->hnb_registered && ctx != hnb && memcmp(&ctx->id, &hnb->id, sizeof(ctx->id)) == 0) {

View File

@@ -38,6 +38,10 @@
#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>
#include <osmocom/ranap/ranap_common.h>
#include <osmocom/ranap/ranap_common_cn.h>
static const char *cn_domain_indicator_to_str(RUA_CN_DomainIndicator_t cN_DomainIndicator)
{
@@ -173,11 +177,11 @@ int rua_tx_disc(struct hnb_context *hnb, int is_ps, uint32_t context_id,
/* forward a RUA message to the SCCP User API to SCCP */
static int rua_to_scu(struct hnb_context *hnb,
RUA_CN_DomainIndicator_t cN_DomainIndicator,
enum osmo_scu_prim_type type,
uint32_t context_id, uint32_t cause,
const uint8_t *data, unsigned int len)
int rua_to_scu(struct hnb_context *hnb,
RUA_CN_DomainIndicator_t cN_DomainIndicator,
enum osmo_scu_prim_type type,
uint32_t context_id, uint32_t cause,
const uint8_t *data, unsigned int len)
{
struct msgb *msg;
struct osmo_scu_prim *prim;
@@ -186,6 +190,7 @@ static int rua_to_scu(struct hnb_context *hnb,
struct osmo_sccp_addr *remote_addr;
bool is_ps;
bool release_context_map = false;
ranap_message *message;
int rc;
switch (cN_DomainIndicator) {
@@ -220,9 +225,9 @@ static int rua_to_scu(struct hnb_context *hnb,
default:
map = context_map_alloc_by_hnb(hnb, context_id, is_ps, cn);
OSMO_ASSERT(map);
LOGHNB(hnb, DRUA, LOGL_DEBUG, "rua_to_scu() %s to %s, rua_ctx_id %u scu_conn_id %u\n",
LOGHNB(hnb, DRUA, LOGL_DEBUG, "rua_to_scu() %s to %s, rua_ctx_id %u scu_conn_id %u data-len %u\n",
cn_domain_indicator_to_str(cN_DomainIndicator), osmo_sccp_addr_dump(remote_addr),
map->rua_ctx_id, map->scu_conn_id);
map->rua_ctx_id, map->scu_conn_id, len);
}
/* add primitive header */
@@ -259,12 +264,31 @@ static int rua_to_scu(struct hnb_context *hnb,
return -EINVAL;
}
/* add optional data section, if needed */
/* If there is RANAP data, include it in the msgb. Usually there is data, but this could also be an SCCP CR
* a.k.a. OSMO_SCU_PRIM_N_CONNECT without RANAP payload. */
if (data && len) {
msg->l2h = msgb_put(msg, len);
memcpy(msg->l2h, data, len);
}
/* If there is data, see if it is a RAB Assignment message where we need to change the user plane information,
* for RTP mapping via MGW (soon also GTP mapping via UPF). */
if (data && len && map && !map->is_ps && !release_context_map) {
message = talloc_zero(map, ranap_message);
rc = ranap_cn_rx_co_decode(map, message, msgb_l2(prim->oph.msg), msgb_l2len(prim->oph.msg));
if (rc == 0) {
switch (message->procedureCode) {
case RANAP_ProcedureCode_id_RAB_Assignment:
/* mgw_fsm_handle_rab_ass_resp() takes ownership of prim->oph and (ranap) message */
return mgw_fsm_handle_rab_ass_resp(map, &prim->oph, message);
}
ranap_cn_rx_co_free(message);
}
talloc_free(message);
}
rc = osmo_sccp_user_sap_down(cn->sccp_user, &prim->oph);
if (map && release_context_map)
@@ -341,21 +365,69 @@ static int rua_rx_init_connect(struct msgb *msg, ANY_t *in)
struct hnb_context *hnb = msg->dst;
uint32_t context_id;
int rc;
const uint8_t *data;
unsigned int data_len;
rc = rua_decode_connecties(&ies, in);
if (rc < 0)
return rc;
context_id = asn1bitstr_to_u24(&ies.context_ID);
data = ies.ranaP_Message.buf;
data_len = ies.ranaP_Message.size;
LOGHNB(hnb, DRUA, LOGL_DEBUG, "RUA %s Connect.req(ctx=0x%x, %s)\n",
cn_domain_indicator_to_str(ies.cN_DomainIndicator), context_id,
ies.establishment_Cause == RUA_Establishment_Cause_emergency_call ? "emergency" : "normal");
LOGHNB(hnb, DRUA, LOGL_DEBUG, "RUA %s Connect.req(ctx=0x%x, %s, RANAP.size=%u)\n",
cn_domain_indicator_to_str(ies.cN_DomainIndicator), context_id,
ies.establishment_Cause == RUA_Establishment_Cause_emergency_call ? "emergency" : "normal",
data_len);
if (hnbgw_requires_empty_sccp_cr(hnb->gw, data_len)) {
/* Do not include data in the SCCP CR, to avoid hitting a message size limit at the remote end that may
* lead to rejection. */
bool is_ps;
struct osmo_sccp_addr *remote_addr;
struct hnbgw_context_map *map;
switch (ies.cN_DomainIndicator) {
case RUA_CN_DomainIndicator_cs_domain:
remote_addr = &hnb->gw->sccp.iucs_remote_addr;
is_ps = false;
break;
case RUA_CN_DomainIndicator_ps_domain:
remote_addr = &hnb->gw->sccp.iups_remote_addr;
is_ps = true;
break;
default:
LOGHNB(hnb, DRUA, LOGL_ERROR, "Unsupported Domain %ld\n", ies.cN_DomainIndicator);
rua_free_connecties(&ies);
return -1;
}
if (!hnb->gw->sccp.cnlink) {
LOGHNB(hnb, DRUA, LOGL_NOTICE, "CN=NULL, discarding message\n");
rua_free_connecties(&ies);
return 0;
}
map = context_map_alloc_by_hnb(hnb, context_id, is_ps, hnb->gw->sccp.cnlink);
OSMO_ASSERT(map);
OSMO_ASSERT(map->is_ps == is_ps);
LOGHNB(hnb, DRUA, LOGL_DEBUG, "rua_rx_init_connect() %s to %s, rua_ctx_id %u scu_conn_id %u;"
" Sending SCCP CR without payload, caching %u octets\n",
cn_domain_indicator_to_str(ies.cN_DomainIndicator), osmo_sccp_addr_dump(remote_addr),
map->rua_ctx_id, map->scu_conn_id, data_len);
map->cached_msg = msgb_alloc_c(map, data_len, "map.cached_msg");
OSMO_ASSERT(map->cached_msg);
memcpy(msgb_put(map->cached_msg, data_len), data, data_len);
/* Data is cached for after CR is confirmed, send SCCP CR but omit payload. */
data = NULL;
data_len = 0;
}
rc = rua_to_scu(hnb, ies.cN_DomainIndicator, OSMO_SCU_PRIM_N_CONNECT,
context_id, 0, ies.ranaP_Message.buf,
ies.ranaP_Message.size);
context_id, 0, data, data_len);
rua_free_connecties(&ies);
return rc;

View File

@@ -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 @@ DEFUN(cfg_hnbgw_iups, cfg_hnbgw_iups_cmd,
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 @@ int hnbgw_vty_go_parent(struct vty *vty)
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;
@@ -309,6 +330,18 @@ DEFUN(cfg_hnbgw_log_prefix, cfg_hnbgw_log_prefix_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_hnbgw_max_sccp_cr_payload_len, cfg_hnbgw_max_sccp_cr_payload_len_cmd,
"sccp cr max-payload-len <0-999999>",
"Configure SCCP behavior\n"
"Configure SCCP Connection Request\n"
"Set an upper bound for payload data length included directly in the CR. If an initial RUA message has a"
" RANAP payload larger than this value (octets), send an SCCP CR without data, followed by an SCCP DT."
" This may be necessary if the remote component has a size limit on valid SCCP CR messages.\n")
{
g_hnb_gw->config.max_sccp_cr_payload_len = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_hnbgw_iucs_remote_addr,
cfg_hnbgw_iucs_remote_addr_cmd,
"remote-addr NAME",
@@ -334,6 +367,8 @@ static int config_write_hnbgw(struct vty *vty)
vty_out(vty, "hnbgw%s", VTY_NEWLINE);
vty_out(vty, " log-prefix %s%s", g_hnb_gw->config.log_prefix_hnb_id ? "hnb-id" : "umts-cell-id",
VTY_NEWLINE);
if (g_hnb_gw->config.max_sccp_cr_payload_len != 999999)
vty_out(vty, " sccp cr max-payload-len %u%s", g_hnb_gw->config.max_sccp_cr_payload_len, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -382,6 +417,14 @@ static int config_write_hnbgw_iups(struct vty *vty)
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;
@@ -392,6 +435,7 @@ void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx)
install_element(HNBGW_NODE, &cfg_hnbgw_rnc_id_cmd);
install_element(HNBGW_NODE, &cfg_hnbgw_log_prefix_cmd);
install_element(HNBGW_NODE, &cfg_hnbgw_max_sccp_cr_payload_len_cmd);
install_element(HNBGW_NODE, &cfg_hnbgw_iuh_cmd);
install_node(&iuh_node, config_write_hnbgw_iuh);
@@ -415,4 +459,10 @@ void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx)
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);
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);
}

782
src/osmo-hnbgw/mgw_fsm.c Normal file
View File

@@ -0,0 +1,782 @@
/* (C) 2021 by sysmocom s.f.m.c. GmbH <info@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_common_cn.h>
#include <osmocom/ranap/ranap_common_ran.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>
/* NOTE: This implementation can only handle one RAB per hnbgw context. This simplification was made because usually
* a voice call will require only one RAB at a time. An exception may be corner cases like video calls, which we
* do not support at the moment. */
/* Send Iu Release Request, this is done in erroneous cases from which we cannot recover */
static void tx_release_req(struct hnbgw_context_map *map)
{
struct hnb_context *hnb = map->hnb_ctx;
struct hnbgw_cnlink *cn = hnb->gw->sccp.cnlink;
struct msgb *msg;
struct osmo_scu_prim *prim;
static const struct RANAP_Cause cause = {
.present = RANAP_Cause_PR_transmissionNetwork,
.choice.transmissionNetwork =
RANAP_CauseTransmissionNetwork_iu_transport_connection_failed_to_establish,
};
msg = ranap_new_msg_iu_rel_req(&cause);
msg->l2h = msg->data;
prim = (struct osmo_scu_prim *)msgb_push(msg, sizeof(*prim));
prim->u.data.conn_id = map->scu_conn_id;
osmo_prim_init(&prim->oph, SCCP_SAP_USER, OSMO_SCU_PRIM_N_DATA, PRIM_OP_REQUEST, msg);
osmo_sccp_user_sap_down(cn->sccp_user, &prim->oph);
}
#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,
MGW_ST_FAILURE,
};
struct mgw_fsm_priv {
/* Backpointer to HNBGW context */
struct hnbgw_context_map *map;
/* RAB-ID from RANAP RAB AssignmentRequest message */
uint8_t rab_id;
/* Pointers to messages and prim header we take ownership of */
ranap_message *ranap_rab_ass_req_message;
ranap_message *ranap_rab_ass_resp_message;
struct osmo_prim_hdr *ranap_rab_ass_resp_oph;
/* 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;
};
static const struct osmo_tdef mgw_tdefs[] = {
{.T = -2427, .default_val = 5, .desc = "timeout for MGCP response from MGW" },
{ }
};
static const 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(fi, 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;
struct osmo_sockaddr addr;
struct osmo_sockaddr_str addr_str;
RANAP_RAB_AssignmentRequestIEs_t *ies;
const char *epname;
struct mgcp_conn_peer mgw_info;
int rc;
LOGPFSML(fi, LOGL_DEBUG, "RAB-AssignmentRequest received, creating HNB side call-leg on MGW...\n");
/* Parse the RAB Assignment Request now */
ies = &mgw_fsm_priv->ranap_rab_ass_req_message->msg.raB_AssignmentRequestIEs;
rc = ranap_rab_ass_req_ies_extract_inet_addr(&addr, &mgw_fsm_priv->rab_id, ies, 0);
if (rc < 0) {
LOGPFSML(fi, LOGL_ERROR, "Invalid RAB-AssignmentRequest -- abort\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
rc = osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas);
if (rc < 0) {
LOGPFSML(fi, LOGL_ERROR,
"Invalid RTP IP-address or port in RAB-AssignmentRequest -- abort\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
osmo_strlcpy(mgw_fsm_priv->msc_rtp_addr, addr_str.ip, sizeof(mgw_fsm_priv->msc_rtp_addr));
mgw_fsm_priv->msc_rtp_port = addr_str.port;
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;
struct osmo_sockaddr addr;
struct osmo_sockaddr_str addr_str;
RANAP_RAB_AssignmentRequestIEs_t *ies;
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 RTP info response from MGW\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
if (strchr(mgw_info->addr, '.'))
addr_str.af = AF_INET;
else
addr_str.af = AF_INET6;
addr_str.port = mgw_info->port;
osmo_strlcpy(addr_str.ip, mgw_info->addr, sizeof(addr_str.ip));
rc = osmo_sockaddr_str_to_sockaddr(&addr_str, &addr.u.sas);
if (rc < 0) {
LOGPFSML(fi, LOGL_ERROR,
"Failed to convert RTP IP-address (%s) and Port (%u) to its binary representation\n",
mgw_info->addr, mgw_info->port);
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
ies = &mgw_fsm_priv->ranap_rab_ass_req_message->msg.raB_AssignmentRequestIEs;
rc = ranap_rab_ass_req_ies_replace_inet_addr(ies, &addr, mgw_fsm_priv->rab_id);
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_FAILURE, 0, 0);
return;
}
mgw_fsm_state_chg(fi, MGW_ST_ASSIGN);
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;
uint8_t encoded[IUH_MSGB_SIZE];
RANAP_RAB_AssignmentRequestIEs_t *ies;
int rc;
ies = &mgw_fsm_priv->ranap_rab_ass_req_message->msg.raB_AssignmentRequestIEs;
rc = ranap_rab_ass_req_encode(encoded, sizeof(encoded), ies);
if (rc < 0) {
LOGPFSML(fi, LOGL_ERROR, "failed to re-encode RAB-AssignmentRequest message\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
LOGPFSML(fi, LOGL_DEBUG, "forwarding modified RAB-AssignmentRequest to HNB\n");
rua_tx_dt(map->hnb_ctx, map->is_ps, map->rua_ctx_id, encoded, rc);
}
static void mgw_fsm_assign(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case MGW_EV_RAB_ASS_RESP:
mgw_fsm_state_chg(fi, 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 hnb_context *hnb = map->hnb_ctx;
struct hnbgw_cnlink *cn = hnb->gw->sccp.cnlink;
struct mgcp_conn_peer mgw_info;
struct osmo_sockaddr addr;
struct osmo_sockaddr_str addr_str;
RANAP_RAB_AssignmentResponseIEs_t *ies;
int rc;
bool rab_failed_at_hnb;
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;
ies = &mgw_fsm_priv->ranap_rab_ass_resp_message->msg.raB_AssignmentResponseIEs;
rc = ranap_rab_ass_resp_ies_extract_inet_addr(&addr, ies, mgw_fsm_priv->rab_id);
if (rc < 0) {
rab_failed_at_hnb = ranap_rab_ass_resp_ies_check_failure(ies, mgw_fsm_priv->rab_id);
if (rab_failed_at_hnb) {
LOGPFSML(fi, LOGL_ERROR,
"The RAB-AssignmentResponse contains a RAB-FailedList, RAB-Assignment (%u) failed.\n",
mgw_fsm_priv->rab_id);
/* Forward the RAB-AssignmentResponse transparently. This will ensure that the MSC is informed
* about the problem. */
LOGPFSML(fi, LOGL_DEBUG, "forwarding unmodified RAB-AssignmentResponse to MSC\n");
rc = osmo_sccp_user_sap_down(cn->sccp_user, mgw_fsm_priv->ranap_rab_ass_resp_oph);
mgw_fsm_priv->ranap_rab_ass_resp_oph = NULL;
if (rc < 0) {
LOGPFSML(fi, LOGL_DEBUG, "failed to forward RAB-AssignmentResponse message\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
}
/* Even though this is a failure situation, we still release normally as the error is located
* at the HNB. */
osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
return;
}
/* The RAB-ID we are dealing with is not on an FailedList and we were unable to parse the response
* normally. This is a situation we cannot recover from. */
LOGPFSML(fi, LOGL_ERROR, "Failed to extract RTP IP-address and Port from RAB-AssignmentResponse\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
rc = osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas);
if (rc < 0) {
LOGPFSML(fi, LOGL_ERROR, "Invalid RTP IP-address or Port in RAB-AssignmentResponse\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
osmo_strlcpy(mgw_info.addr, addr_str.ip, sizeof(mgw_info.addr));
mgw_info.port = addr_str.port;
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 RTP info response from MGW\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
mgw_fsm_state_chg(fi, MGW_ST_CRCX_MSC);
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;
struct osmo_sockaddr addr;
struct osmo_sockaddr_str addr_str;
int rc;
int msg_max_len;
RANAP_RAB_AssignmentResponseIEs_t *ies;
switch (event) {
case MGW_EV_MGCP_OK:
ies = &mgw_fsm_priv->ranap_rab_ass_resp_message->msg.raB_AssignmentResponseIEs;
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_FAILURE, 0, 0);
return;
}
/* Replace RTP IP-Address/Port in ranap message container */
if (strchr(mgw_info->addr, '.'))
addr_str.af = AF_INET;
else
addr_str.af = AF_INET6;
addr_str.port = mgw_info->port;
osmo_strlcpy(addr_str.ip, mgw_info->addr, sizeof(addr_str.ip));
rc = osmo_sockaddr_str_to_sockaddr(&addr_str, &addr.u.sas);
if (rc < 0) {
LOGPFSML(fi, LOGL_ERROR,
"Failed to convert RTP IP-address (%s) and Port (%u) to its binary representation\n",
mgw_info->addr, mgw_info->port);
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
rc = ranap_rab_ass_resp_ies_replace_inet_addr(ies, &addr, mgw_fsm_priv->rab_id);
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_FAILURE, 0, 0);
return;
}
/* When the modified ranap message container is re-encoded, the resulting message might be larger then
* the original message. 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->ranap_rab_ass_resp_oph->msg) +
msgb_tailroom(mgw_fsm_priv->ranap_rab_ass_resp_oph->msg);
rc = msgb_resize_area(mgw_fsm_priv->ranap_rab_ass_resp_oph->msg,
mgw_fsm_priv->ranap_rab_ass_resp_oph->msg->l2h,
msgb_l2len(mgw_fsm_priv->ranap_rab_ass_resp_oph->msg), msg_max_len);
OSMO_ASSERT(rc == 0);
rc = ranap_rab_ass_resp_encode(msgb_l2(mgw_fsm_priv->ranap_rab_ass_resp_oph->msg),
msgb_l2len(mgw_fsm_priv->ranap_rab_ass_resp_oph->msg), ies);
if (rc < 0) {
LOGPFSML(fi, LOGL_ERROR, "failed to re-encode RAB-AssignmentResponse message\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
}
/* Resize l2h back to the actual message length */
rc = msgb_resize_area(mgw_fsm_priv->ranap_rab_ass_resp_oph->msg,
mgw_fsm_priv->ranap_rab_ass_resp_oph->msg->l2h,
msgb_l2len(mgw_fsm_priv->ranap_rab_ass_resp_oph->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;
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->ranap_rab_ass_resp_oph;
struct hnb_context *hnb = map->hnb_ctx;
struct hnbgw_cnlink *cn = hnb->gw->sccp.cnlink;
int rc;
LOGPFSML(fi, LOGL_DEBUG, "forwarding modified RAB-AssignmentResponse to MSC\n");
rc = osmo_sccp_user_sap_down(cn->sccp_user, oph);
mgw_fsm_priv->ranap_rab_ass_resp_oph = NULL;
if (rc < 0) {
LOGPFSML(fi, LOGL_DEBUG, "failed to forward RAB-AssignmentResponse message\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 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_failure_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
tx_release_req(mgw_fsm_priv->map);
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, 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_MGCP_TERM:
mgw_fsm_priv->mgcpc_ep = NULL;
LOGPFSML(fi, LOGL_ERROR, "Media gateway failed\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
case MGW_EV_MGCP_FAIL:
LOGPFSML(fi, LOGL_ERROR, "Media gateway failed to switch RTP streams\n");
osmo_fsm_inst_state_chg(fi, MGW_ST_FAILURE, 0, 0);
return;
case MGW_EV_RELEASE:
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;
}
static 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;
if (mgw_fsm_priv->ranap_rab_ass_req_message) {
ranap_ran_rx_co_free(mgw_fsm_priv->ranap_rab_ass_req_message);
talloc_free(mgw_fsm_priv->ranap_rab_ass_req_message);
mgw_fsm_priv->ranap_rab_ass_req_message = NULL;
}
if (mgw_fsm_priv->ranap_rab_ass_resp_message) {
ranap_cn_rx_co_free(mgw_fsm_priv->ranap_rab_ass_resp_message);
talloc_free(mgw_fsm_priv->ranap_rab_ass_resp_message);
mgw_fsm_priv->ranap_rab_ass_resp_message = NULL;
}
if (mgw_fsm_priv->ranap_rab_ass_resp_oph) {
scu_prim = (struct osmo_scu_prim *)mgw_fsm_priv->ranap_rab_ass_resp_oph;
scu_msg = scu_prim->oph.msg;
msgb_free(scu_msg);
mgw_fsm_priv->ranap_rab_ass_resp_oph = 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 coming 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),
.out_state_mask =
S(MGW_ST_ASSIGN) |
S(MGW_ST_FAILURE) |
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_FAILURE) |
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),
.out_state_mask =
S(MGW_ST_CRCX_MSC) |
S(MGW_ST_FAILURE) |
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),
.out_state_mask =
S(MGW_ST_ESTABLISHED) |
S(MGW_ST_FAILURE) |
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_FAILURE) |
S(MGW_ST_RELEASE),
},
[MGW_ST_RELEASE] = {
.name = "MGW_ST_RELEASE",
.onenter = mgw_fsm_release_onenter,
.in_event_mask = 0,
.out_state_mask = 0,
},
[MGW_ST_FAILURE] = {
.name = "MGW_ST_FAILURE",
.onenter = mgw_fsm_failure_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) | S(MGW_EV_MGCP_FAIL),
.timer_cb = mgw_fsm_timer_cb,
.cleanup = mgw_fsm_cleanup,
.pre_term = mgw_fsm_pre_term,
};
/* The MSC may ask to release a specific RAB within a RAB-AssignmentRequest */
static int handle_rab_release(struct hnbgw_context_map *map, struct osmo_prim_hdr *oph, ranap_message *message)
{
bool rab_release_req;
struct osmo_fsm_inst *fi = map->mgw_fi;
struct mgw_fsm_priv *mgw_fsm_priv = fi->priv;
int rc;
/* Check if the RAB that is handled by this FSM is addressed by the release request */
rab_release_req = ranap_rab_ass_req_ies_check_release(&message->msg.raB_AssignmentRequestIEs,
mgw_fsm_priv->rab_id);
if (!rab_release_req)
return -EINVAL;
LOGPFSML(map->mgw_fi, LOGL_NOTICE, "MSC asked to release RAB-ID %u\n", mgw_fsm_priv->rab_id);
/* Forward the unmodifed RAB-AssignmentRequest to HNB, so that the HNB is informed about the RAB release as
* well */
LOGPFSML(fi, LOGL_DEBUG, "forwarding unmodified RAB-AssignmentRequest to HNB\n");
rc = rua_tx_dt(map->hnb_ctx, map->is_ps, map->rua_ctx_id, msgb_l2(oph->msg), msgb_l2len(oph->msg));
/* Release the FSM normally */
osmo_fsm_inst_state_chg(fi, MGW_ST_RELEASE, 0, 0);
return rc;
}
/*! 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 AssignmentResponse (function takes no ownership).
* \ptmap[in] message ranap message container (function takes ownership).
* \returns 0 on success; negative on error. */
int handle_rab_ass_req(struct hnbgw_context_map *map, struct osmo_prim_hdr *oph, ranap_message *message)
{
static bool initialized = false;
struct mgw_fsm_priv *mgw_fsm_priv;
char fsm_name[255];
int rc;
/* Initialize FSM if not done yet */
if (!initialized) {
OSMO_ASSERT(osmo_fsm_register(&mgw_fsm) == 0);
initialized = true;
}
/* The RTP stream negotiation usually begins with a RAB-AssignmentRequest and ends with an IU-Release, however
* it may also be thet the MSC decides to release the RAB with a dedicated RAB-AssignmentRequest that contains
* a ReleaseList. In this case an FSM will already be present. */
if (map->mgw_fi) {
/* A RAB Release might be in progress, handle it */
rc = handle_rab_release(map, oph, message);
if (rc >= 0)
return rc;
LOGPFSML(map->mgw_fi, LOGL_ERROR,
"mgw_fsm_alloc_and_handle_rab_ass_req() unable to handle RAB-AssignmentRequest!\n");
osmo_fsm_inst_state_chg(map->mgw_fi, MGW_ST_FAILURE, 0, 0);
OSMO_ASSERT(map->mgw_fi == NULL);
}
/* This FSM only supports RAB assignments with a single RAB assignment only. This limitation has been taken
* into account under the assumption that voice calls typically require a single RAB only. Nevertheless, we
* will block all incoming RAB assignments that try to assign more (or less) than one RAB. */
if (ranap_rab_ass_req_ies_get_count(&message->msg.raB_AssignmentRequestIEs) != 1) {
LOGP(DMGW, LOGL_ERROR,
"mgw_fsm_alloc_and_handle_rab_ass_req() rua_ctx_id=%d, RAB-AssignmentRequest with more than one RAB assignment -- abort!\n",
map->rua_ctx_id);
tx_release_req(map);
return -1;
}
mgw_fsm_priv = talloc_zero(map, struct mgw_fsm_priv);
mgw_fsm_priv->map = map;
mgw_fsm_priv->ranap_rab_ass_req_message = message;
/* Allocate FSM */
snprintf(fsm_name, sizeof(fsm_name), "mgw-fsm-%u-%u", map->rua_ctx_id, mgw_fsm_priv->rab_id);
map->mgw_fi = osmo_fsm_inst_alloc(&mgw_fsm, map, mgw_fsm_priv, LOGL_DEBUG, fsm_name);
/* Start the FSM */
mgw_fsm_state_chg(map->mgw_fi, MGW_ST_CRCX_HNB);
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).
* \ptmap[in] message ranap message container with decoded ranap message (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, ranap_message *message)
{
struct mgw_fsm_priv *mgw_fsm_priv;
struct osmo_scu_prim *prim;
struct msgb *msg;
OSMO_ASSERT(oph);
if (!map->mgw_fi) {
/* NOTE: This situation is a corner-case. We may end up here when the co-located MGW caused a problem
* on the way between RANAP RAB Assignment Request and RANAP RAB Assignment Response. */
LOGP(DMGW, LOGL_ERROR,
"mgw_fsm_handle_rab_ass_resp() rua_ctx_id=%d, no MGW fsm -- sending Iu-Release-Request!\n",
map->rua_ctx_id);
/* Cleanup ranap message */
ranap_cn_rx_co_free(message);
talloc_free(message);
/* Toss RAB-AssignmentResponse */
prim = (struct osmo_scu_prim *)oph;
msg = prim->oph.msg;
msgb_free(msg);
/* Send a release request, to make sure that the MSC is aware of the problem. */
tx_release_req(map);
return -1;
}
mgw_fsm_priv = map->mgw_fi->priv;
mgw_fsm_priv->ranap_rab_ass_resp_oph = oph;
mgw_fsm_priv->ranap_rab_ass_resp_message = message;
osmo_fsm_inst_dispatch(map->mgw_fi, MGW_EV_RAB_ASS_RESP, NULL);
return 0;
}
/*! Release the FSM and clear its associated RTP streams.
* \ptmap[in] map hanbgw context map that is responsible for this call.
* \returns 0 on success; negative on error. */
int mgw_fsm_release(struct hnbgw_context_map *map)
{
if (!map->mgw_fi) {
LOGP(DMGW, LOGL_ERROR, "mgw_fsm_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;
}

View File

@@ -0,0 +1,637 @@
/* (C) 2021 by sysmocom s.f.m.c. GmbH <info@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/ranap_common_cn.h>
#include <osmocom/ranap/ranap_common_ran.h>
#include <osmocom/ranap/iu_helpers.h>
#include <asn1c/asn1helpers.h>
/*! Encode RABAP RAB AssignmentRequest from RANAP_RAB_AssignmentRequestIEs.
* \ptmap[out] data user provided memory to store resulting ASN.1 encoded message.
* \ptmap[in] len length of user provided memory to store resulting ASN.1 encoded message.
* \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentRequestIEs.
* \returns resulting message length on success; negative on error. */
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(data, 0, len);
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 */
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;
}
/*! Encode RABAP RAB AssignmentRequest from RANAP_RAB_AssignmentResponseIEs.
* \ptmap[out] data user provided memory to store resulting ASN.1 encoded message.
* \ptmap[in] len length of user provided memory to store resulting ASN.1 encoded message.
* \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentResponseIEs.
* \returns resulting message length on success; negative on error. */
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(data, 0, len);
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 */
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 indexed item from the RAB setup-or-modify list and return the first protocol-ie-field-pair. */
static RANAP_ProtocolIE_FieldPair_t *prot_ie_field_pair_from_ass_req_ies(const RANAP_RAB_AssignmentRequestIEs_t *ies,
unsigned int index)
{
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;
}
/* Detect the end of the list */
if (index >= ies->raB_SetupOrModifyList.list.count)
return NULL;
protocol_ie_container_pair = ies->raB_SetupOrModifyList.list.array[index];
protocol_ie_field_pair = protocol_ie_container_pair->list.array[0];
return protocol_ie_field_pair;
}
/* Pick the indexed item from the RAB release-list list and return a pointer to it */
static RANAP_IE_t *release_item_from_ass_req_ies(const RANAP_RAB_AssignmentRequestIEs_t *ies, unsigned int index)
{
/* Make sure we indeed deal with a setup-or-modify list */
if (!(ies->presenceMask & RAB_ASSIGNMENTREQUESTIES_RANAP_RAB_RELEASELIST_PRESENT)) {
RANAP_DEBUG
("Decoding failed, the RANAP RAB AssignmentRequest did not contain a release list!\n");
return NULL;
}
/* Detect the end of the list */
if (index >= ies->raB_ReleaseList.raB_ReleaseList_ies.list.count)
return NULL;
return ies->raB_ReleaseList.raB_ReleaseList_ies.list.array[index];
}
/* Pick the indexed item from the RAB setup-or-modified list and return a pointer to it */
static RANAP_IE_t *setup_or_modif_item_from_rab_ass_resp(const RANAP_RAB_AssignmentResponseIEs_t *ies,
unsigned int index)
{
/* Make sure we indeed deal with a setup-or-modified list */
if (!(ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT)) {
RANAP_DEBUG("RANAP RAB AssignmentResponse did not contain a setup-or-modified list!\n");
return NULL;
}
/* Detect the end of the list */
if (index >= ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.count)
return NULL;
return ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[index];
}
/* Pick the indexed item from the RAB failed list and return a pointer to it */
static RANAP_IE_t *failed_list_item_from_rab_ass_resp(const RANAP_RAB_AssignmentResponseIEs_t *ies,
unsigned int index)
{
/* Make sure we indeed deal with a failed list */
if (!(ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_FAILEDLIST_PRESENT)) {
RANAP_DEBUG("RANAP RAB AssignmentResponse did not contain a failed list!\n");
return NULL;
}
/* Detect the end of the list */
if (index >= ies->raB_FailedList.raB_FailedList_ies.list.count)
return NULL;
return ies->raB_FailedList.raB_FailedList_ies.list.array[index];
}
/* find the RAB specified by rab_id in ies and when found, decode the result into items_ies */
static int decode_rab_smditms_from_resp_ies(RANAP_RAB_SetupOrModifiedItemIEs_t *items_ies,
RANAP_RAB_AssignmentResponseIEs_t *ies, uint8_t rab_id)
{
RANAP_IE_t *setup_or_modified_list_ie;
RANAP_RAB_SetupOrModifiedItem_t *rab_setup_or_modified_item;
int rc;
uint8_t rab_id_decoded;
unsigned int index = 0;
while (1) {
setup_or_modified_list_ie = setup_or_modif_item_from_rab_ass_resp(ies, index);
if (!setup_or_modified_list_ie)
return -EINVAL;
rc = ranap_decode_rab_setupormodifieditemies_fromlist(items_ies, &setup_or_modified_list_ie->value);
if (rc < 0)
return -EINVAL;
rab_setup_or_modified_item = &items_ies->raB_SetupOrModifiedItem;
/* 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_decoded = rab_setup_or_modified_item->rAB_ID.buf[0];
if (rab_id_decoded == rab_id)
return index;
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedItem, items_ies);
index++;
}
}
/* See comment above decode_rab_smditms_from_resp_ies() */
static int decode_rab_flitms_from_resp_ies(RANAP_RAB_FailedItemIEs_t *items_ies,
RANAP_RAB_AssignmentResponseIEs_t *ies, uint8_t rab_id)
{
RANAP_IE_t *failed_list_ie;
RANAP_RAB_FailedItem_t *rab_failed_item;
int rc;
uint8_t rab_id_decoded;
unsigned int index = 0;
while (1) {
failed_list_ie = failed_list_item_from_rab_ass_resp(ies, index);
if (!failed_list_ie)
return -EINVAL;
rc = ranap_decode_rab_faileditemies_fromlist(items_ies, &failed_list_ie->value);
if (rc < 0)
return -EINVAL;
rab_failed_item = &items_ies->raB_FailedItem;
/* 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_decoded = rab_failed_item->rAB_ID.buf[0];
if (rab_id_decoded == rab_id)
return index;
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_FailedItem, items_ies);
index++;
}
}
/* find the RAB specified by rab_id in ies and when found, decode the result into item */
static int decode_rab_smditms_from_req_ies(RANAP_RAB_SetupOrModifyItemFirst_t *item,
RANAP_RAB_AssignmentRequestIEs_t *ies, uint8_t rab_id)
{
RANAP_ProtocolIE_FieldPair_t *protocol_ie_field_pair;
int rc;
uint8_t rab_id_decoded;
unsigned int index = 0;
while (1) {
protocol_ie_field_pair = prot_ie_field_pair_from_ass_req_ies(ies, index);
if (!protocol_ie_field_pair)
return -EINVAL;
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");
return -EINVAL;
}
rc = ranap_decode_rab_setupormodifyitemfirst(item, &protocol_ie_field_pair->firstValue);
if (rc < 0)
return -EINVAL;
rab_id_decoded = item->rAB_ID.buf[0];
if (rab_id_decoded == rab_id)
return index;
}
}
static int decode_rab_relitms_from_req_ies(RANAP_RAB_ReleaseItemIEs_t *items_ies,
RANAP_RAB_AssignmentRequestIEs_t *ies, uint8_t rab_id)
{
RANAP_IE_t *release_list_ie;
RANAP_RAB_ReleaseItem_t *rab_release_item;
int rc;
uint8_t rab_id_decoded;
unsigned int index = 0;
while (1) {
release_list_ie = release_item_from_ass_req_ies(ies, index);
if (!release_list_ie)
return -EINVAL;
if (release_list_ie->id != RANAP_ProtocolIE_ID_id_RAB_ReleaseItem) {
RANAP_DEBUG("Decoding failed, the protocol IE is not of type RANAP RAB ReleaseItem!\n");
return -EINVAL;
}
rc = ranap_decode_rab_releaseitemies_fromlist(items_ies, &release_list_ie->value);
if (rc < 0)
return -EINVAL;
rab_release_item = &items_ies->raB_ReleaseItem;
/* 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_decoded = rab_release_item->rAB_ID.buf[0];
if (rab_id_decoded == rab_id)
return index;
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_ReleaseItem, items_ies);
index++;
}
}
/*! Extract IP address and port from RANAP_RAB_AssignmentRequestIEs.
* \ptmap[out] addr user provided memory to store extracted RTP stream IP-Address and port number.
* \ptmap[out] rab_id pointer to store RAB-ID (optional, can be NULL).
* \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentRequestIEs.
* \ptmap[in] index index of the SetupOrModifyItem (e.g. 0 for the first list item).
* \returns 0 on success; negative on error. */
int ranap_rab_ass_req_ies_extract_inet_addr(struct osmo_sockaddr *addr, uint8_t *rab_id,
RANAP_RAB_AssignmentRequestIEs_t *ies, unsigned int index)
{
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;
RANAP_TransportLayerAddress_t *trasp_layer_addr;
RANAP_IuTransportAssociation_t *transp_assoc;
uint16_t port;
int rc;
protocol_ie_field_pair = prot_ie_field_pair_from_ass_req_ies(ies, index);
if (!protocol_ie_field_pair)
return -EINVAL;
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");
return -EINVAL;
}
rc = ranap_decode_rab_setupormodifyitemfirst(rab_setup_or_modify_item_first,
&protocol_ie_field_pair->firstValue);
if (rc < 0)
return -EINVAL;
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];
}
/* Decode IP-Address */
trasp_layer_addr = &rab_setup_or_modify_item_first->transportLayerInformation->transportLayerAddress;
rc = ranap_transp_layer_addr_decode2(addr, NULL, trasp_layer_addr);
if (rc < 0) {
rc = -EINVAL;
goto error;
}
/* Decode port number */
transp_assoc = &rab_setup_or_modify_item_first->transportLayerInformation->iuTransportAssociation;
rc = ranap_transp_assoc_decode(&port, transp_assoc);
if (rc < 0) {
rc = -EINVAL;
goto error;
}
switch (addr->u.sin.sin_family) {
case AF_INET:
addr->u.sin.sin_port = htons(port);
break;
case AF_INET6:
addr->u.sin6.sin6_port = htons(port);
break;
default:
rc = -EINVAL;
goto error;
}
rc = 0;
error:
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, rab_setup_or_modify_item_first);
return rc;
}
/*! Extract IP address and port from RANAP_RAB_AssignmentResponseIEs.
* \ptmap[out] addr user provided memory to store extracted RTP stream IP-Address and port number.
* \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentResponseIEs.
* \ptmap[in] rab_id expected rab id to look for.
* \returns 0 on success; negative on error. */
int ranap_rab_ass_resp_ies_extract_inet_addr(struct osmo_sockaddr *addr, RANAP_RAB_AssignmentResponseIEs_t *ies, uint8_t rab_id)
{
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;
uint16_t port;
int rc;
rc = decode_rab_smditms_from_resp_ies(rab_setup_or_modified_items_ies, ies, rab_id);
if (rc < 0)
return -EINVAL;
rab_setup_or_modified_item = &rab_setup_or_modified_items_ies->raB_SetupOrModifiedItem;
/* Decode IP-Address */
rc = ranap_transp_layer_addr_decode2(addr, NULL, rab_setup_or_modified_item->transportLayerAddress);
if (rc < 0) {
rc = -EINVAL;
goto error;
}
/* Decode port number */
rc = ranap_transp_assoc_decode(&port, rab_setup_or_modified_item->iuTransportAssociation);
if (rc < 0) {
rc = -EINVAL;
goto error;
}
switch (addr->u.sin.sin_family) {
case AF_INET:
addr->u.sin.sin_port = htons(port);
break;
case AF_INET6:
addr->u.sin6.sin6_port = htons(port);
break;
default:
rc = -EINVAL;
goto error;
}
rc = 0;
error:
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedItem, rab_setup_or_modified_items_ies);
return rc;
}
/*! Replace IP address and port in RANAP_RAB_AssignmentRequestIEs.
* \ptmap[inout] ies user provided memory with RANAP_RAB_AssignmentRequestIEs.
* \ptmap[in] addr user provided memory that contains the new RTP stream IP-Address and port number.
* \ptmap[in] rab_id expected rab id to look for.
* \returns 0 on success; negative on error. */
int ranap_rab_ass_req_ies_replace_inet_addr(RANAP_RAB_AssignmentRequestIEs_t *ies, struct osmo_sockaddr *addr, uint8_t rab_id)
{
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;
RANAP_TransportLayerInformation_t *old_transport_layer_information = NULL;
RANAP_TransportLayerInformation_t *new_transport_layer_information = NULL;
struct osmo_sockaddr addr_old;
bool uses_x213_nsap;
int rc;
int index;
index = decode_rab_smditms_from_req_ies(rab_setup_or_modify_item_first, ies, rab_id);
if (index < 0)
return -EINVAL;
/* Replace transport-layer-information */
if (rab_setup_or_modify_item_first->transportLayerInformation->iuTransportAssociation.present ==
RANAP_IuTransportAssociation_PR_bindingID) {
old_transport_layer_information = rab_setup_or_modify_item_first->transportLayerInformation;
/* Before we can re-encode the transport layer information, we need to know the format it was
* encoded in. */
rc = ranap_transp_layer_addr_decode2(&addr_old, &uses_x213_nsap,
&old_transport_layer_information->transportLayerAddress);
if (rc < 0) {
rc = -EINVAL;
goto error;
}
/* Encode a new transport layer information field */
new_transport_layer_information = ranap_new_transp_info_rtp(addr, uses_x213_nsap);
if (!new_transport_layer_information) {
rc = -EINVAL;
goto error;
}
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 */
protocol_ie_field_pair = prot_ie_field_pair_from_ass_req_ies(ies, index);
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;
}
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);
return rc;
}
/*! Replace IP address and port in RANAP_RAB_AssignmentResponseIEs.
* \ptmap[inout] ies user provided memory with RANAP_RAB_AssignmentResponseIEs.
* \ptmap[in] addr user provided memory that contains the new RTP stream IP-Address and port number.
* \ptmap[in] rab_id expected rab id to look for.
* \returns 0 on success; negative on error. */
int ranap_rab_ass_resp_ies_replace_inet_addr(RANAP_RAB_AssignmentResponseIEs_t *ies, struct osmo_sockaddr *addr, uint8_t rab_id)
{
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 addr_old;
bool uses_x213_nsap;
int rc;
int index;
index = decode_rab_smditms_from_resp_ies(rab_setup_or_modified_items_ies, ies, rab_id);
if (index < 0)
return -EINVAL;
rab_setup_or_modified_item = &rab_setup_or_modified_items_ies->raB_SetupOrModifiedItem;
/* Before we can re-encode the transport layer address, we need to know the format it was encoded in. */
rc = ranap_transp_layer_addr_decode2(&addr_old, &uses_x213_nsap,
rab_setup_or_modified_item->transportLayerAddress);
if (rc < 0) {
rc = -EINVAL;
goto error;
}
/* 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 */
temp_transport_layer_information = ranap_new_transp_info_rtp(addr, uses_x213_nsap);
if (!temp_transport_layer_information) {
rc = -EINVAL;
goto error;
}
/* 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 */
setup_or_modified_list_ie = setup_or_modif_item_from_rab_ass_resp(ies, index);
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;
}
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;
if (temp_transport_layer_information)
ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, temp_transport_layer_information);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedItem, rab_setup_or_modified_items_ies);
return rc;
}
/*! Check if a specific RAB is present in an RAB-Failed-Item-List inside RANAP_RAB_AssignmentResponseIEs.
* \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentResponseIEs.
* \ptmap[in] rab_id expected rab id to look for.
* \returns true when RAB could be identified as failed; false otherwise */
bool ranap_rab_ass_resp_ies_check_failure(RANAP_RAB_AssignmentResponseIEs_t *ies, uint8_t rab_id)
{
RANAP_RAB_FailedItemIEs_t _rab_failed_items_ies;
RANAP_RAB_FailedItemIEs_t *rab_failed_items_ies = &_rab_failed_items_ies;
int rc;
bool result = true;
/* If we can get a failed item for the specified RAB ID, then we know that the
* HNB reported the RAB Assignment as failed */
rc = decode_rab_flitms_from_resp_ies(rab_failed_items_ies, ies, rab_id);
if (rc < 0)
result = false;
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_FailedItem, rab_failed_items_ies);
return result;
}
/*! Check if a specific RAB is present in an RAB-ReleaseList inside RANAP_RAB_AssignmentRequestIEs.
* \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentRequestIEs.
* \ptmap[in] rab_id expected rab id to look for.
* \returns true when RAB is intended for release; false otherwise */
bool ranap_rab_ass_req_ies_check_release(RANAP_RAB_AssignmentRequestIEs_t *ies, uint8_t rab_id)
{
RANAP_RAB_ReleaseItemIEs_t _rab_release_items_ies;
RANAP_RAB_ReleaseItemIEs_t *rab_release_items_ies = &_rab_release_items_ies;
int rc;
bool result = true;
/* If we can get a rlease list item for the specified RAB ID, then we know that the
* MSC intends to release the specified RAB */
rc = decode_rab_relitms_from_req_ies(rab_release_items_ies, ies, rab_id);
if (rc < 0)
result = false;
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_ReleaseItem, rab_release_items_ies);
return result;
}
/*! Find out how many RAB items are present in a RAB-SetupOrModifyList inside RANAP_RAB_AssignmentRequestIEs.
* \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentRequestIEs.
* \returns number of RAB items, -1 on failure. */
int ranap_rab_ass_req_ies_get_count(RANAP_RAB_AssignmentRequestIEs_t *ies)
{
/* 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 -1;
}
return ies->raB_SetupOrModifyList.list.count;
}

30
src/osmo-hnbgw/tdefs.c Normal file
View File

@@ -0,0 +1,30 @@
/* (C) 2021 by sysmocom s.f.m.c. GmbH <info@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" },
{ }
};

View File

@@ -1,4 +1,5 @@
SUBDIRS = \
ranap_rab_ass \
$(NULL)
# The `:;' works around a Bash 3.2 bug when the output is not writeable.

View File

@@ -0,0 +1,37 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
$(NULL)
AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBASN1C_CFLAGS) \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMORANAP_CFLAGS) \
$(LIBOSMOSIGTRAN_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
EXTRA_DIST = \
ranap_rab_ass_test.ok \
$(NULL)
noinst_PROGRAMS = \
ranap_rab_ass_test \
$(NULL)
ranap_rab_ass_test_SOURCES = \
ranap_rab_ass_test.c \
$(NULL)
ranap_rab_ass_test_LDADD = \
$(LIBASN1C_LIBS) \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMORANAP_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \
$(COVERAGE_LDFLAGS) \
$(top_builddir)/src/osmo-hnbgw/ranap_rab_ass.o \
$(NULL)

View File

@@ -0,0 +1,422 @@
/* (C) 2021 by sysmocom s.f.m.c. GmbH <info@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/>.
*
*/
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/sockaddr_str.h>
#include <osmocom/hnbgw/hnbgw.h>
#include <osmocom/ranap/ranap_ies_defs.h>
#include <osmocom/ranap/iu_helpers.h>
#include <osmocom/hnbgw/ranap_rab_ass.h>
#include <osmocom/ranap/ranap_common.h>
#include <osmocom/ranap/ranap_common_cn.h>
#include <osmocom/ranap/ranap_common_ran.h>
static void *tall_hnb_ctx;
static void *msgb_ctx;
extern void *talloc_asn1_ctx;
void test_ranap_rab_ass_req_decode_encode(void)
{
int rc;
ranap_message message;
uint8_t testvec[] = {
0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x01, 0x00,
0x36, 0x40, 0x52, 0x00, 0x00, 0x01, 0x00, 0x35,
0x00, 0x48, 0x78, 0x22, 0xcd, 0x80, 0x10, 0x2f,
0xa7, 0x20, 0x1a, 0x2c, 0x00, 0x00, 0xf4, 0x4c,
0x08, 0x0a, 0x02, 0x80, 0x00, 0x51, 0x40, 0x00,
0x27, 0x20, 0x28, 0x14, 0x00, 0x67, 0x40, 0x00,
0x00, 0x22, 0x28, 0x14, 0x00, 0x3c, 0x40, 0x00,
0x00, 0x00, 0x50, 0x3d, 0x02, 0x00, 0x02, 0x27,
0xc0, 0x35, 0x00, 0x01, 0x0a, 0x09, 0x01, 0xa2,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0x76,
0x00, 0x00, 0x40, 0x01, 0x00, 0x00
};
uint8_t encoded[sizeof(testvec)];
rc = ranap_ran_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec));
OSMO_ASSERT(rc == 0);
rc = ranap_rab_ass_req_encode(encoded, sizeof(encoded), &message.msg.raB_AssignmentRequestIEs);
printf("ranap_rab_ass_req_encode rc=%d\n", rc);
printf("INPUT: %s\n", osmo_hexdump_nospc(testvec, sizeof(testvec)));
printf("RESULT: %s\n", osmo_hexdump_nospc(encoded, sizeof(encoded)));
OSMO_ASSERT(memcmp(testvec, encoded, sizeof(testvec)) == 0);
ranap_ran_rx_co_free(&message);
}
void test_ranap_rab_ass_resp_decode_encode(void)
{
int rc;
ranap_message message;
uint8_t testvec[] = {
0x60, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x01, 0x00,
0x34, 0x40, 0x23, 0x00, 0x00, 0x01, 0x00, 0x33,
0x40, 0x1c, 0x60, 0x3a, 0x7c, 0x35, 0x00, 0x01,
0x0a, 0x09, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x04, 0x0a, 0x00, 0x00
};
uint8_t encoded[sizeof(testvec)];
rc = ranap_cn_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec));
OSMO_ASSERT(rc == 0);
rc = ranap_rab_ass_resp_encode(encoded, sizeof(encoded), &message.msg.raB_AssignmentResponseIEs);
printf("ranap_rab_ass_resp_encode rc=%d\n", rc);
printf("INPUT: %s\n", osmo_hexdump_nospc(testvec, sizeof(testvec)));
printf("RESULT: %s\n", osmo_hexdump_nospc(encoded, sizeof(encoded)));
OSMO_ASSERT(memcmp(testvec, encoded, sizeof(testvec)) == 0);
ranap_cn_rx_co_free(&message);
}
void test_ranap_rab_ass_req_ies_extract_inet_addr(void)
{
int rc;
struct osmo_sockaddr addr;
struct osmo_sockaddr_str addr_str;
uint8_t rab_id;
ranap_message message;
uint8_t testvec[] = {
0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x01, 0x00,
0x36, 0x40, 0x52, 0x00, 0x00, 0x01, 0x00, 0x35,
0x00, 0x48, 0x78, 0x22, 0xcd, 0x80, 0x10, 0x2f,
0xa7, 0x20, 0x1a, 0x2c, 0x00, 0x00, 0xf4, 0x4c,
0x08, 0x0a, 0x02, 0x80, 0x00, 0x51, 0x40, 0x00,
0x27, 0x20, 0x28, 0x14, 0x00, 0x67, 0x40, 0x00,
0x00, 0x22, 0x28, 0x14, 0x00, 0x3c, 0x40, 0x00,
0x00, 0x00, 0x50, 0x3d, 0x02, 0x00, 0x02, 0x27,
0xc0, 0x35, 0x00, 0x01, 0x0a, 0x09, 0x01, 0xa2,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0x76,
0x00, 0x00, 0x40, 0x01, 0x00, 0x00
};
rc = ranap_ran_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec));
OSMO_ASSERT(rc == 0);
rc = ranap_rab_ass_req_ies_extract_inet_addr(&addr, &rab_id, &message.msg.raB_AssignmentRequestIEs, 0);
osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas);
printf("ranap_rab_ass_req_extract_inet_addr rc=%d\n", rc);
printf("RESULT: addr=%s, port=%u, rab-id=%02x\n", addr_str.ip, addr_str.port, rab_id);
ranap_ran_rx_co_free(&message);
}
void test_ranap_rab_ass_resp_ies_extract_inet_addr(void)
{
int rc;
struct osmo_sockaddr addr;
struct osmo_sockaddr_str addr_str;
ranap_message message;
uint8_t testvec[] = {
0x60, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x01, 0x00,
0x34, 0x40, 0x23, 0x00, 0x00, 0x01, 0x00, 0x33,
0x40, 0x1c, 0x60, 0x3a, 0x7c, 0x35, 0x00, 0x01,
0x0a, 0x09, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x04, 0x0a, 0x00, 0x00
};
rc = ranap_cn_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec));
OSMO_ASSERT(rc == 0);
rc = ranap_rab_ass_resp_ies_extract_inet_addr(&addr, &message.msg.raB_AssignmentResponseIEs, 7);
osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas);
printf("ranap_rab_ass_resp_extract_inet_addr rc=%d\n", rc);
printf("RESULT: addr=%s, port=%u\n", addr_str.ip, addr_str.port);
ranap_cn_rx_co_free(&message);
}
void test_ranap_rab_ass_req_ies_replace_inet_addr(void)
{
int rc;
struct osmo_sockaddr addr;
struct osmo_sockaddr_str addr_str;
ranap_message message;
uint8_t rab_id;
uint8_t testvec_in[] = {
0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x01, 0x00,
0x36, 0x40, 0x52, 0x00, 0x00, 0x01, 0x00, 0x35,
0x00, 0x48, 0x78, 0x4e, 0xcd, 0x80, 0x10, 0x2f,
0xa7, 0x20, 0x1a, 0x2c, 0x00, 0x00, 0xf4, 0x4c,
0x08, 0x0a, 0x02, 0x80, 0x00, 0x51, 0x40, 0x00,
0x27, 0x20, 0x28, 0x14, 0x00, 0x67, 0x40, 0x00,
0x00, 0x22, 0x28, 0x14, 0x00, 0x3c, 0x40, 0x00,
0x00, 0x00, 0x50, 0x3d, 0x02, 0x00, 0x02, 0x27,
0xc0, 0x35, 0x00, 0x01, 0x0a, 0x09, 0x01, 0xa2,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0xba,
0x00, 0x00, 0x40, 0x01, 0x00
};
uint8_t testvec_expected_out[] = {
0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x01, 0x00,
0x36, 0x40, 0x52, 0x00, 0x00, 0x01, 0x00, 0x35,
0x00, 0x48, 0x78, 0x4e, 0xcd, 0x80, 0x10, 0x2f,
0xa7, 0x20, 0x1a, 0x2c, 0x00, 0x00, 0xf4, 0x4c,
0x08, 0x0a, 0x02, 0x80, 0x00, 0x51, 0x40, 0x00,
0x27, 0x20, 0x28, 0x14, 0x00, 0x67, 0x40, 0x00,
0x00, 0x22, 0x28, 0x14, 0x00, 0x3c, 0x40, 0x00,
0x00, 0x00, 0x50, 0x3d, 0x02, 0x00, 0x02, 0x27,
0xc0, 0x35, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0xd2,
0x00, 0x00, 0x40, 0x01, 0x00
};
rc = ranap_ran_rx_co_decode(talloc_asn1_ctx, &message, testvec_in, sizeof(testvec_in));
OSMO_ASSERT(rc == 0);
rc = ranap_rab_ass_req_ies_extract_inet_addr(&addr, &rab_id, &message.msg.raB_AssignmentRequestIEs, 0);
OSMO_ASSERT(rc == 0);
osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas);
printf("before: addr=%s, port=%u, rab_id=%u\n", addr_str.ip, addr_str.port, rab_id);
memset(&addr_str, 0, sizeof(addr_str));
addr_str.af = AF_INET;
addr_str.port = 1234;
osmo_strlcpy(addr_str.ip, "1.2.3.4", sizeof(addr_str.ip));
osmo_sockaddr_str_to_sockaddr(&addr_str, &addr.u.sas);
rc = ranap_rab_ass_req_ies_replace_inet_addr(&message.msg.raB_AssignmentRequestIEs, &addr, rab_id);
printf("ranap_rab_ass_req_replace_inet_addr rc=%d\n", rc);
rc = ranap_rab_ass_req_ies_extract_inet_addr(&addr, &rab_id, &message.msg.raB_AssignmentRequestIEs, 0);
OSMO_ASSERT(rc == 0);
osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas);
printf("after: addr=%s, port=%u, rab_id=%u\n", addr_str.ip, addr_str.port, rab_id);
rc = ranap_rab_ass_req_encode(testvec_in, sizeof(testvec_in), &message.msg.raB_AssignmentRequestIEs);
OSMO_ASSERT(rc == sizeof(testvec_in));
OSMO_ASSERT(memcmp(testvec_in, testvec_expected_out, sizeof(testvec_in)) == 0);
ranap_ran_rx_co_free(&message);
}
void test_ranap_rab_ass_resp_ies_replace_inet_addr(void)
{
int rc;
struct osmo_sockaddr addr;
struct osmo_sockaddr_str addr_str;
ranap_message message;
uint8_t testvec_in[] = {
0x60, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x01, 0x00,
0x34, 0x40, 0x23, 0x00, 0x00, 0x01, 0x00, 0x33,
0x40, 0x1c, 0x60, 0x32, 0x7c, 0x35, 0x00, 0x01,
0x0a, 0x09, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x04, 0x0a, 0x00, 0x00
};
uint8_t testvec_expected_out[] = {
0x60, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x01, 0x00,
0x34, 0x40, 0x23, 0x00, 0x00, 0x01, 0x00, 0x33,
0x40, 0x1c, 0x60, 0x32, 0x7c, 0x35, 0x00, 0x01,
0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x04, 0xd2, 0x00, 0x00
};
rc = ranap_cn_rx_co_decode(talloc_asn1_ctx, &message, testvec_in, sizeof(testvec_in));
OSMO_ASSERT(rc == 0);
rc = ranap_rab_ass_resp_ies_extract_inet_addr(&addr, &message.msg.raB_AssignmentResponseIEs, 6);
OSMO_ASSERT(rc == 0);
osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas);
printf("before: addr=%s, port=%u\n", addr_str.ip, addr_str.port);
memset(&addr_str, 0, sizeof(addr_str));
addr_str.af = AF_INET;
addr_str.port = 1234;
osmo_strlcpy(addr_str.ip, "1.2.3.4", sizeof(addr_str.ip));
osmo_sockaddr_str_to_sockaddr(&addr_str, &addr.u.sas);
rc = ranap_rab_ass_resp_ies_replace_inet_addr(&message.msg.raB_AssignmentResponseIEs, &addr, 6);
printf("ranap_rab_ass_resp_replace_inet_addr rc=%d\n", rc);
rc = ranap_rab_ass_resp_ies_extract_inet_addr(&addr, &message.msg.raB_AssignmentResponseIEs, 6);
OSMO_ASSERT(rc == 0);
osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas);
printf("after: addr=%s, port=%u\n", addr_str.ip, addr_str.port);
rc = ranap_rab_ass_resp_encode(testvec_in, sizeof(testvec_in), &message.msg.raB_AssignmentResponseIEs);
OSMO_ASSERT(rc == sizeof(testvec_in));
OSMO_ASSERT(memcmp(testvec_in, testvec_expected_out, sizeof(testvec_in)) == 0);
ranap_cn_rx_co_free(&message);
}
void test_ranap_rab_ass_resp_ies_check_failure(void)
{
int rc;
ranap_message message;
bool rab_failed_at_hnb;
uint8_t testvec[] = {
0x60, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00,
0x23, 0x40, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x22,
0x40, 0x03, 0x05, 0xd0, 0x00
};
rc = ranap_cn_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec));
OSMO_ASSERT(rc == 0);
rab_failed_at_hnb =
ranap_rab_ass_resp_ies_check_failure(&message.msg.raB_AssignmentResponseIEs, 23);
printf("ranap_rab_ass_resp_ies_check_failure rab_failed_at_hnb=%u (RAB ID 23)\n", rab_failed_at_hnb);
rab_failed_at_hnb =
ranap_rab_ass_resp_ies_check_failure(&message.msg.raB_AssignmentResponseIEs, 44);
printf("ranap_rab_ass_resp_ies_check_failure rab_failed_at_hnb=%u (RAB ID 44, which is not in the message)\n",
rab_failed_at_hnb);
ranap_cn_rx_co_free(&message);
}
void test_ranap_rab_ass_req_ies_check_release(void)
{
int rc;
ranap_message message;
bool rab_release_req;
uint8_t testvec[] = {
0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00,
0x29, 0x40, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x28,
0x40, 0x03, 0x05, 0xd0, 0x00
};
rc = ranap_ran_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec));
OSMO_ASSERT(rc == 0);
rab_release_req =
ranap_rab_ass_req_ies_check_release(&message.msg.raB_AssignmentRequestIEs, 23);
printf("ranap_rab_ass_req_ies_check_release rab_release_req=%u (RAB ID 23)\n", rab_release_req);
rab_release_req =
ranap_rab_ass_req_ies_check_release(&message.msg.raB_AssignmentRequestIEs, 44);
printf("ranap_rab_ass_req_ies_check_release rab_release_req=%u (RAB ID 44, which is not in the message)\n", rab_release_req);
ranap_ran_rx_co_free(&message);
}
void test_ranap_rab_ass_req_ies_get_count(void)
{
int rc;
ranap_message message;
uint8_t testvec[] = {
0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x01, 0x00,
0x36, 0x40, 0x52, 0x00, 0x00, 0x01, 0x00, 0x35,
0x00, 0x48, 0x78, 0x22, 0xcd, 0x80, 0x10, 0x2f,
0xa7, 0x20, 0x1a, 0x2c, 0x00, 0x00, 0xf4, 0x4c,
0x08, 0x0a, 0x02, 0x80, 0x00, 0x51, 0x40, 0x00,
0x27, 0x20, 0x28, 0x14, 0x00, 0x67, 0x40, 0x00,
0x00, 0x22, 0x28, 0x14, 0x00, 0x3c, 0x40, 0x00,
0x00, 0x00, 0x50, 0x3d, 0x02, 0x00, 0x02, 0x27,
0xc0, 0x35, 0x00, 0x01, 0x0a, 0x09, 0x01, 0xa2,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0x76,
0x00, 0x00, 0x40, 0x01, 0x00, 0x00
};
rc = ranap_ran_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec));
OSMO_ASSERT(rc == 0);
rc = ranap_rab_ass_req_ies_get_count(&message.msg.raB_AssignmentRequestIEs);
printf("ranap_rab_ass_req_ies_get_count rc=%d\n", rc);
ranap_ran_rx_co_free(&message);
}
static const struct log_info_cat log_cat[] = {
[DRANAP] = {
.name = "RANAP", .loglevel = LOGL_DEBUG, .enabled = 1,
.color = "",
.description = "RAN Application Part",
},
};
static const struct log_info test_log_info = {
.cat = log_cat,
.num_cat = ARRAY_SIZE(log_cat),
};
int test_init(void)
{
int rc;
tall_hnb_ctx = talloc_named_const(NULL, 0, "hnb_context");
msgb_ctx = msgb_talloc_ctx_init(NULL, 0);
talloc_asn1_ctx = talloc_named_const(NULL, 0, "asn1_context");
rc = osmo_init_logging2(tall_hnb_ctx, &test_log_info);
if (rc < 0)
exit(1);
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_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);
}
int main(int argc, char **argv)
{
test_init();
test_ranap_rab_ass_req_decode_encode();
test_ranap_rab_ass_resp_decode_encode();
test_ranap_rab_ass_req_ies_extract_inet_addr();
test_ranap_rab_ass_resp_ies_extract_inet_addr();
test_ranap_rab_ass_req_ies_replace_inet_addr();
test_ranap_rab_ass_resp_ies_replace_inet_addr();
test_ranap_rab_ass_resp_ies_check_failure();
test_ranap_rab_ass_req_ies_check_release();
test_ranap_rab_ass_req_ies_get_count();
test_cleanup();
return 0;
}
/* Stub */
const char *hnb_context_name(struct hnb_context *ctx)
{
return "TEST";
}

View File

@@ -0,0 +1,21 @@
ranap_rab_ass_req_encode rc=93
INPUT: 0000005900000100364052000001003500487822cd80102fa7201a2c0000f44c080a028000514000272028140067400000222814003c40000000503d02000227c03500010a0901a200000000000000000000000000401f76000040010000
RESULT: 0000005900000100364052000001003500487822cd80102fa7201a2c0000f44c080a028000514000272028140067400000222814003c40000000503d02000227c03500010a0901a200000000000000000000000000401f76000040010000
ranap_rab_ass_resp_encode rc=46
INPUT: 6000002a000001003440230000010033401c603a7c3500010a0901a40000000000000000000000000040040a0000
RESULT: 6000002a000001003440230000010033401c603a7c3500010a0901a40000000000000000000000000040040a0000
ranap_rab_ass_req_extract_inet_addr rc=0
RESULT: addr=10.9.1.162, port=8054, rab-id=11
ranap_rab_ass_resp_extract_inet_addr rc=0
RESULT: addr=10.9.1.164, port=1034
before: addr=10.9.1.162, port=8122, rab_id=39
ranap_rab_ass_req_replace_inet_addr rc=0
after: addr=1.2.3.4, port=1234, rab_id=39
before: addr=10.9.1.164, port=1034
ranap_rab_ass_resp_replace_inet_addr rc=0
after: addr=1.2.3.4, port=1234
ranap_rab_ass_resp_ies_check_failure rab_failed_at_hnb=1 (RAB ID 23)
ranap_rab_ass_resp_ies_check_failure rab_failed_at_hnb=0 (RAB ID 44, which is not in the message)
ranap_rab_ass_req_ies_check_release rab_release_req=1 (RAB ID 23)
ranap_rab_ass_req_ies_check_release rab_release_req=0 (RAB ID 44, which is not in the message)
ranap_rab_ass_req_ies_get_count rc=1

View File

@@ -1,8 +1,8 @@
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
AT_CHECK([$abs_top_builddir/tests/ranap_rab_ass/ranap_rab_ass_test], [0], [expout], [ignore])
AT_CLEANUP