Compare commits

..

15 Commits

Author SHA1 Message Date
Oliver Smith
750f75a1cd contrib: integrate RPM spec
Remove OpenSUSE bug report link, set version to 0.0.0, make it build with CentOS 8 etc.

Related: OS#4550
Change-Id: I1d03ac87a7d0c3c600d187f3e485cb2dab8838bb
2020-05-15 12:06:05 +02:00
Oliver Smith
d6877eb8f9 contrib: import RPM spec
Copy the RPM spec file from:
https://build.opensuse.org/project/show/home:mnhauke:osmocom:nightly

Related: OS#4550
Change-Id: I6d6119ca5debf4adfec6c155f81027c8a3583537
2020-05-14 11:47:38 +02:00
Alexander Chemeris
ebb9bf3f12 rtp_bridge: Demote a chatty ERROR log message to DEBUG level.
Not having a second leg of an MGCP endpoint is a normal situtation
and can't be treated as an ERROR message, especially not as an ERROR
message logged on every RTP packet. This happens routinely at
the beginning of call setup and we get tens of ERROR messages in
the logs for every call.

Change-Id: If741a742208772bda4e59236345d7ae650368d5a
2020-05-11 18:14:31 +03:00
Alexander Chemeris
61cf9bb5f1 mgcp_network: Fix a typo in the comment bahviour -> behaviour
Change-Id: I59a06b95e9bbf90c038c5c9234f5c857315d5f07
2020-05-11 18:13:53 +03:00
Pau Espin Pedrol
a7152e055a Use OSMO_FD_* instead of deprecated BSC_FD_*
New define is available since libosmocore 1.1.0, and we already require
1.1.0, so no need to update dependenices.
Let's change it to avoid people re-using old BSC_FD_* symbols when
copy-pasting somewhere else.

Change-Id: I9b6463af713f76c06a144bdbf202c0d91eef4d21
2020-05-09 19:15:50 +02:00
Alexander Chemeris
63866009e2 counters: Implement more useful counters.
Right now a lot of errors with MGCP processing are invisible in rate
counters which makes them difficult to trace or even notice in
a production environment. E.g. reaching a limit of MGCP endpoints
is completely invisible even though it's a critical opertion alarm.

Change-Id: I6db68f044255c927dfd534fed880e405ec3ed4d6
2020-05-05 22:17:41 +03:00
Alexander Chemeris
dab89af070 vty: Prepend VTY output of counters for better visual separation.
Before this patch rate counters started right after trunk information
with no visual separation which was quite confusing. We're adding
a new line and a header to warn a user of the section change.

Change-Id: I3943def03ab821b05ac597f40bdfa4a3a71ddca3
2020-05-05 20:38:16 +03:00
Eric
eebbf2b1fc configure.ac: fix libtool issue with clang and sanitizer
As pointed out at https://github.com/libexpat/libexpat/issues/312
libtool does not play nice with clang sanitizer builds at all.
For those builds LD shoud be set to clang too (and LDFLAGS needs the
sanitizer flags as well), because the clang compiler driver knows how
linking to the sanitizer libs works, but then at a later stage libtool
fails to actually produce the shared libraries and the build fails. This
is fixed by this patch.

Addtionally LD_LIBRARY_PATH has no effect on conftest runs during
configure time, so the rpath needs to be set to the asan library path to
ensure the configure run does not fail due to a missing asan library,
i.e.:

SANS='-fsanitize=memory -fsanitize-recover=all -shared-libsan'
export CC=clang-10
ASANPATH=$(dirname `$CC -print-file-name=libclang_rt.asan-x86_64.so`)
export LDFLAGS="-Wl,-rpath,$ASANPATH $SANS $LDFLAGS"

Change-Id: I2314ef45e6f588e88d5aab8213cc7b5cdef11325
2020-04-11 18:33:04 +00:00
Eric
e885bc5c24 tests: dlopen does not imply availability of dlsym..
Check for both.

Change-Id: I1a1e82882ad28dd53e634f10f9cebb4bc74cac1e
2020-04-11 00:57:13 +02:00
Philipp Maier
173dc129fc doc: do not bind osmo-mgw to random ip-address
The example config bind the MGW to a random ip-address, lets use the
loopback address here, this will suit cases where osmo-bts runs on the
same machine as the MGW (nitb). For all other cases were an external BTS
is used the ip-address still needs to be changed.

Change-Id: Iae52c671c48953ea6b52b18c5d77347343cde0df
2020-03-24 20:37:44 +01:00
Neels Hofmeyr
3abced8d64 allow larger MGCP client wqueue: 10 -> 1024
Enlarge the MGCP client workqueue maximum limit by factor 100.

During Abis load testing, a BSC trying to DLCX 200 conns at the same time hit
the limit of 10 very very quickly, and everything broke down.

Change-Id: I8980cce37bae0757828b28455b25c77bcb6316d0
2020-03-10 03:55:35 +01:00
Harald Welte
a48ff4a738 Update per-trunk global packet/byte counters in real-time
We used to update only the per-connection rx/tx packet/byte counters
on-the-fly, but not the per-trunk global counters.  The latter would
only be updated at the end of a connection.  As MGCP connections
can last quite long (think of a long phone call) this is maybe
not the best of ideas.

Note: The all_rtp:err_tstmp_in and all_rt:err_tstmp_out are still
only updated at the end of a connection.

Change-Id: Ib3866cb8149d3257fcf39733846c97c33881c4ee
Related: OS#4437
2020-03-08 14:50:20 +01:00
Neels Hofmeyr
6c92f9d83e fix vty dump_trunk: start from zero, do not omit first CONN
Change-Id: Ibb97fbf5c0b46ab841c3f6126b3622e4a8054feb
2020-03-08 14:12:54 +01:00
Harald Welte
9852e22101 Add CTRL interface to osmo-mgw
OsmoMGW has a lot of nice built-in statistics (rate_ctr,...) but it
seems the only way to look at them is via the VTY. While libosmocore
contains automatic exposure of all rate counters via CTRL, the CTRL
interface simply is not used by osmo-mgw so far.

Closes: OS#4441
Change-Id: I7ed6bdb9f4749c24ca11a5905a620546cfe42952
2020-03-08 13:23:46 +01:00
Harald Welte
b141cccbfb Fix number of endpoints of default trunk
If a config file doesn't have a 'number endpoints' config line,
we would use -1 as unsigned integer and end up with
 number endpoints 4294967295
if the config file is re-written

Change-Id: I05a3814117b1d6e0cdc30740da31709ce333df4b
Closes: OS#4034
2020-03-08 10:51:41 +01:00
34 changed files with 525 additions and 1266 deletions

View File

@@ -22,6 +22,11 @@ AC_PROG_CC
AC_PROG_INSTALL
LT_INIT
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
AS_CASE(["$LD"],[*clang*],
[AS_CASE(["${host_os}"],
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
@@ -38,9 +43,13 @@ dnl checks for libraries
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DLSYM)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.6.0)
@@ -195,7 +204,6 @@ AC_OUTPUT(
tests/atlocal
tests/mgcp_client/Makefile
tests/mgcp/Makefile
tests/iuup/Makefile
doc/Makefile
doc/examples/Makefile
doc/manuals/Makefile

136
contrib/osmo-mgw.spec Normal file
View File

@@ -0,0 +1,136 @@
#
# spec file for package osmo-mgw
#
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
Name: osmo-mgw
Version: 0.0.0
Release: 0
Summary: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
License: AGPL-3.0-or-later AND GPL-2.0-or-later
Group: Hardware/Mobile
URL: https://osmocom.org/projects/osmo-mgw
Source: %{name}-%{version}.tar.xz
BuildRequires: automake >= 1.9
BuildRequires: libtool >= 2
BuildRequires: pkgconfig >= 0.20
%if 0%{?centos_ver}
BuildRequires: systemd
%else
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libosmo-netif) >= 0.6.0
BuildRequires: pkgconfig(libosmocore) >= 1.0.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.1.0
BuildRequires: pkgconfig(libosmogsm) >= 1.0.0
BuildRequires: pkgconfig(libosmovty) >= 1.0.0
BuildRequires: pkgconfig(libosmocoding) >= 1.0.0
%{?systemd_requires}
%description
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
%package -n libosmo-mgcp-client6
Summary: Osmocom's Media Gateway Control Protocol client library
Group: System/Libraries
%description -n libosmo-mgcp-client6
Osmocom's Media Gateway Control Protocol client library.
%package -n libosmo-mgcp-client-devel
Summary: Development files for Osmocom's Media Gateway Control Protocol client library
Group: Development/Libraries/C and C++
Requires: libosmo-mgcp-client6 = %{version}
%description -n libosmo-mgcp-client-devel
Osmocom's Media Gateway Control Protocol client librarary.
This subpackage contains libraries and header files for developing
applications that want to make use of libosmo-mgcp-client.
%package -n libosmo-mgcp-devel
Summary: Development files for Osmocom's Media Gateway server library
Group: Development/Libraries/C and C++
%description -n libosmo-mgcp-devel
Osmocom's Media Gateway Control Protocol server library.
This subpackage contains libraries and header files for developing
applications that want to make use of libosmo-mgcp.
%prep
%setup -q
%build
echo "%{version}" >.tarball-version
autoreconf -fi
%configure \
--disable-static \
--docdir=%{_docdir}/%{name} \
--with-systemdsystemunitdir=%{_unitdir}
make %{?_smp_mflags}
%install
%make_install
find %{buildroot} -type f -name "*.la" -delete -print
%check
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%post -n libosmo-mgcp-client6 -p /sbin/ldconfig
%postun -n libosmo-mgcp-client6 -p /sbin/ldconfig
%if 0%{?suse_version}
%preun
%service_del_preun osmo-mgw.service
%postun
%service_del_postun osmo-mgw.service
%pre
%service_add_pre osmo-mgw.service
%post
%service_add_post osmo-mgw.service
%endif
%files
%license COPYING
%doc AUTHORS README
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-mgw
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw.cfg
%{_bindir}/osmo-mgw
%{_unitdir}/osmo-mgw.service
%dir %{_sysconfdir}/osmocom
%config %{_sysconfdir}/osmocom/osmo-mgw.cfg
%files -n libosmo-mgcp-client6
%{_libdir}/libosmo-mgcp-client.so.6*
%files -n libosmo-mgcp-client-devel
%{_libdir}/libosmo-mgcp-client.so
%{_libdir}/pkgconfig/libosmo-mgcp-client.pc
%dir %{_includedir}/osmocom
%dir %{_includedir}/osmocom/mgcp_client
%{_includedir}/osmocom/mgcp_client/*.h
%files -n libosmo-mgcp-devel
%dir %{_includedir}/osmocom
%dir %{_includedir}/osmocom/mgcp
%{_includedir}/osmocom/mgcp/*.h
%changelog

View File

@@ -4,7 +4,7 @@
mgcp
bind ip 127.0.0.1
rtp port-range 4002 16000
rtp bind-ip 10.9.1.122
rtp bind-ip 127.0.0.1
rtp ip-probing
rtp ip-tos 184
bind port 2427

View File

@@ -6,7 +6,6 @@ noinst_HEADERS = \
mgcp_endp.h \
mgcp_sdp.h \
mgcp_codec.h \
mgcp_ctrl.h \
debug.h \
iuup_cn_node.h \
iuup_protocol.h \
$(NULL)

View File

@@ -29,7 +29,6 @@
/* Debug Areas of the code */
enum {
DRTP,
DIUUP,
Debug_LastEntry,
};

View File

@@ -1,47 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/* IuUP CN node, minimal implementation */
/* _____IuUP_CN_____
* | |
* UE <--> RNC --PDU-> osmo_iuup_cn_rx_pdu() -+-> ---+-> rx_payload()
* | | |
* | <-PDU-- tx_msg() <-------------+-- <-+--- osmo_iuup_cn_tx_payload()
* | |
* -----------------
*/
#pragma once
struct msgb;
typedef int (*osmo_iuup_data_cb_t)(struct msgb *msg, void *node_priv);
struct osmo_iuup_cn_cfg {
void *node_priv;
/* When the IuUP peer sent a voice packet, the clean RTP without the IuUP header is fed to this
* callback. */
osmo_iuup_data_cb_t rx_payload;
/* IuUP handler requests that a PDU shall be sent to the IuUP peer (e.g. the RNC).
* It is guaranteed that the msgb->dst pointer is preserved or copied from the msgb that
* originated the request. */
osmo_iuup_data_cb_t tx_msg;
};
struct osmo_iuup_cn {
struct osmo_iuup_cn_cfg cfg;
char *name;
uint8_t next_frame_nr;
int rtp_payload_type;
};
bool osmo_iuup_cn_is_iuup_init(struct msgb *msg);
struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,
const char *name_fmt, ...);
void osmo_iuup_cn_free(struct osmo_iuup_cn *cn);
int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *payload);
int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu);

View File

@@ -1,117 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/* IuUP protocol handling, minimal implementation */
#pragma once
#include <osmocom/core/endian.h>
#include <osmocom/core/msgb.h>
#define OSMO_IUUP_HEADROOM 32
enum osmo_iuup_pdu_type {
OSMO_IUUP_PDU_DATA_WITH_CRC = 0,
OSMO_IUUP_PDU_CONTROL_PROCEDURE = 14,
};
enum osmo_iuup_acknack {
OSMO_IUUP_ACKNACK_PROCEDURE = 0,
OSMO_IUUP_ACKNACK_ACK = 1,
OSMO_IUUP_ACKNACK_NACK = 2,
};
enum osmo_iuup_procedure {
OSMO_IUUP_PROC_INITIALIZATION = 0,
OSMO_IUUP_PROC_RATE_CONTROL = 1,
OSMO_IUUP_PROC_TIME_ALIGNMENT = 2,
OSMO_IUUP_PROC_ERROR_EVENT = 3,
};
enum osmo_iuup_frame_good {
OSMO_IUUP_FRAME_GOOD = 0,
OSMO_IUUP_FRAME_BAD = 1,
OSMO_IUUP_FRAME_BAD_DUE_TO_RADIO = 2,
};
struct osmo_iuup_hdr_ctrl {
#if OSMO_IS_BIG_ENDIAN
uint8_t pdu_type:4,
ack_nack:2,
frame_nr:2;
uint8_t mode_version:4,
procedure:4;
uint8_t header_crc:6,
payload_crc_hi:2;
uint8_t payload_crc_lo;
uint8_t payload[0];
#elif OSMO_IS_LITTLE_ENDIAN
uint8_t frame_nr:2,
ack_nack:2,
pdu_type:4;
uint8_t procedure:4,
mode_version:4;
uint8_t payload_crc_hi:2,
header_crc:6;
uint8_t payload_crc_lo;
uint8_t payload[0];
#endif
} __attribute__((packed));
union osmo_iuup_hdr_ctrl_payload {
struct {
#if OSMO_IS_BIG_ENDIAN
uint8_t spare:3,
iptis_present:1,
subflows:3,
chain:1;
#elif OSMO_IS_LITTLE_ENDIAN
uint8_t spare:3,
iptis_present:1,
subflows:3,
chain:1;
#endif
} initialization;
struct {
#if OSMO_IS_BIG_ENDIAN
uint8_t error_distance:2,
error_cause:6;
#elif OSMO_IS_LITTLE_ENDIAN
uint8_t error_cause:6,
error_distance:2;
#endif
} error_event;
};
extern const struct value_string osmo_iuup_error_cause_names[];
static inline const char *osmo_iuup_error_cause_name(uint8_t val)
{ return get_value_string(osmo_iuup_error_cause_names, val); }
struct osmo_iuup_hdr_data {
#if OSMO_IS_BIG_ENDIAN
uint8_t pdu_type:4,
frame_nr:4;
uint8_t frame_good:2,
rfci:6;
uint8_t header_crc:6,
payload_crc_hi:2;
uint8_t payload_crc_lo;
#elif OSMO_IS_LITTLE_ENDIAN
uint8_t frame_nr:4,
pdu_type:4;
uint8_t rfci:6,
frame_good:2;
uint8_t payload_crc_hi:2,
header_crc:6;
uint8_t payload_crc_lo;
#endif
uint8_t payload[0];
} __attribute__((packed));
int osmo_iuup_classify(bool log_errors,
const char *log_label,
struct msgb *pdu,
struct osmo_iuup_hdr_ctrl **is_ctrl,
struct osmo_iuup_hdr_data **is_data);
bool osmo_iuup_is_init(struct msgb *pdu);
void osmo_iuup_make_init_ack(struct msgb *ack);
void osmo_iuup_set_checksums(uint8_t *iuup_header_and_payload, unsigned int header_and_payload_len);

View File

@@ -119,6 +119,16 @@ struct mgcp_port_range {
#define MGCP_KEEPALIVE_ONCE (-1)
#define MGCP_KEEPALIVE_NEVER 0
/* Global MCGP general rate counters */
enum {
MGCP_GENERAL_RX_MSGS_TOTAL,
MGCP_GENERAL_RX_MSGS_RETRANSMITTED,
MGCP_GENERAL_RX_MSGS_HANDLED,
MGCP_GENERAL_RX_MSGS_UNHANDLED,
MGCP_GENERAL_RX_FAIL_MSG_PARSE,
MGCP_GENERAL_RX_FAIL_NO_ENDPOINT,
};
/* Global MCGP CRCX related rate counters */
enum {
MGCP_CRCX_SUCCESS,
@@ -207,6 +217,8 @@ struct mgcp_trunk_config {
int vty_number_endpoints;
struct mgcp_endpoint *endpoints;
/* Rate counter group which contains stats for generic MGCP events. */
struct rate_ctr_group *mgcp_general_ctr_group;
/* Rate counter group which contains stats for processed CRCX commands. */
struct rate_ctr_group *mgcp_crcx_ctr_group;
/* Rate counter group which contains stats for processed MDCX commands. */
@@ -279,6 +291,9 @@ struct mgcp_config {
/* time after which inactive connections (CIs) get closed */
int conn_timeout;
/* osmocom CTRL interface */
struct ctrl_handle *ctrl;
};
/* config management */

View File

@@ -5,5 +5,3 @@ void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
const char *subtype_name, unsigned int match_nr);

View File

@@ -0,0 +1,24 @@
/*
* (C) 2020 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
const char *bind_addr, uint16_t port);

View File

@@ -23,27 +23,15 @@
#pragma once
#include <osmocom/core/msgb.h>
struct sockaddr_in;
struct mgcp_conn;
struct mgcp_conn_rtp;
struct mgcp_endpoint;
struct osmo_rtp_msg_ctx {
int proto;
struct mgcp_conn_rtp *conn_src;
struct sockaddr_in *from_addr;
};
#define OSMO_RTP_MSG_CTX(MSGB) (*(struct osmo_rtp_msg_ctx**)&((MSGB)->dst))
#define LOG_ENDP(endp, level, fmt, args...) \
LOGP(DRTP, level, "%x@ " fmt, ENDPOINT_NUMBER(endp), ## args)
/* Callback type for RTP dispatcher functions (e.g mgcp_dispatch_rtp_bridge_cb, see below).
* The OSMO_RTP_MSG_CTX() should be set appropriately on the msg. */
typedef int (*mgcp_dispatch_rtp_cb) (struct msgb *msg);
/* Callback type for RTP dispatcher functions
(e.g mgcp_dispatch_rtp_bridge_cb, see below) */
typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in *addr,
char *buf, unsigned int buf_size,
struct mgcp_conn *conn);
/* Callback type for endpoint specific cleanup actions. This function
* is automatically executed when a connection is freed (see mgcp_conn_free()

View File

@@ -37,13 +37,6 @@
#define CONN_ID_BTS "0"
#define CONN_ID_NET "1"
#define LOG_CONN(conn, level, fmt, args...) \
LOGP(DRTP, level, "(%d@ I:%s) " fmt, \
ENDPOINT_NUMBER((conn)->endp), (conn)->id, ## args)
#define LOG_CONN_RTP(conn_rtp, level, fmt, args...) \
LOG_CONN(conn_rtp->conn, level, fmt, ## args)
enum mgcp_trunk_type {
MGCP_TRUNK_VIRTUAL,
MGCP_TRUNK_E1,
@@ -211,8 +204,6 @@ struct mgcp_conn_rtp {
} osmux;
struct rate_ctr_group *rate_ctr_group;
struct osmo_iuup_cn *iuup;
};
/*! Connection type, specifies which member of the union "u" in mgcp_conn
@@ -275,10 +266,11 @@ struct mgcp_parse_data {
};
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
struct msgb *msg, struct mgcp_conn_rtp *conn_src,
char *buf, int rc, struct mgcp_conn_rtp *conn_src,
struct mgcp_conn_rtp *conn_dst);
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
unsigned int buf_size, struct mgcp_conn *conn);
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
struct mgcp_conn_rtp *conn);
@@ -358,8 +350,3 @@ LOGP(cat, level, "endpoint:0x%x " fmt, \
LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
(conn)->id, \
## args)
void mgcp_patch_and_count(struct mgcp_endpoint *endp,
struct mgcp_rtp_state *state,
struct mgcp_rtp_end *rtp_end,
struct sockaddr_in *addr, struct msgb *msg);

View File

@@ -828,8 +828,8 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
inet_aton(mgcp->actual.remote_addr, &addr.sin_addr);
mgcp->remote_addr = htonl(addr.sin_addr.s_addr);
osmo_wqueue_init(wq, 10);
wq->bfd.when = BSC_FD_READ;
osmo_wqueue_init(wq, 1024);
wq->bfd.when = OSMO_FD_READ;
wq->bfd.data = mgcp;
wq->read_cb = mgcp_do_read;
wq->write_cb = mgcp_do_write;

View File

@@ -40,6 +40,5 @@ libosmo_mgcp_a_SOURCES = \
mgcp_conn.c \
mgcp_stat.c \
mgcp_endp.c \
iuup_protocol.c \
iuup_cn_node.c \
mgcp_ctrl.c \
$(NULL)

View File

@@ -1,211 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/* IuUP Core Network side protocol handling, minimal implementation */
/*
* (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Neels Hofmeyr <neels@hofmeyr.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <talloc.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/msgb.h>
#include <osmocom/netif/rtp.h>
#include <osmocom/mgcp/iuup_cn_node.h>
#include <osmocom/mgcp/iuup_protocol.h>
#include <osmocom/mgcp/debug.h>
#define LOG_IUUP_CN(cn, level, fmt, args...) \
LOGP(DIUUP, level, "(%s) " fmt, (cn)->name, ## args)
struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,
const char *name_fmt, ...)
{
va_list ap;
struct osmo_iuup_cn *cn = talloc_zero(ctx, struct osmo_iuup_cn);
OSMO_ASSERT(cn);
cn->cfg = *cfg;
if (!name_fmt)
name_fmt = "-";
va_start(ap, name_fmt);
cn->name = talloc_vasprintf(cn, name_fmt, ap);
va_end(ap);
LOGP(DIUUP, LOGL_INFO, "(%s) Initializing IuUP node\n", cn->name);
if (!osmo_identifier_valid(cn->name)) {
LOGP(DIUUP, LOGL_ERROR, "Attempting to set illegal id for IuUP CN instance: %s\n",
osmo_quote_str(cn->name, -1));
talloc_free(cn);
return NULL;
}
return cn;
}
void osmo_iuup_cn_free(struct osmo_iuup_cn *cn)
{
talloc_free(cn);
}
static int rx_data(struct osmo_iuup_cn *cn, struct msgb *pdu,
struct osmo_iuup_hdr_data *hdr)
{
/* Remove the IuUP bit from the middle of the buffer by writing the RTP header forward. */
/* And append AMR 12.2k header "0xf03c". - AD HOC fix */
unsigned int pre_hdr_len = ((uint8_t*)hdr) - pdu->data;
memmove(pdu->data + sizeof(*hdr) - 2, pdu->data, pre_hdr_len);
((uint8_t*)hdr)[2] = 0xf0;
((uint8_t*)hdr)[3] = 0x3c;
msgb_pull(pdu, sizeof(*hdr) - 2);
LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP stripping IuUP header from RTP data\n", cn->name);
cn->cfg.rx_payload(pdu, cn->cfg.node_priv);
return 0;
}
static int tx_init_ack(struct osmo_iuup_cn *cn, struct msgb *src_pdu)
{
/* Send Initialization Ack PDU back to the sender */
int rc;
struct msgb *ack = msgb_alloc(4096, "IuUP Initialization Ack");
OSMO_ASSERT(ack);
ack->dst = src_pdu->dst;
/* Just copy the RTP header that was sent... TODO: tweak some RTP values?? */
memcpy(msgb_put(ack, sizeof(struct rtp_hdr)), src_pdu->data, sizeof(struct rtp_hdr));
osmo_iuup_make_init_ack(ack);
LOGP(DIUUP, LOGL_DEBUG, "(%s) Sending Initialization ACK %p\n", cn->name, cn->cfg.node_priv);
rc = cn->cfg.tx_msg(ack, cn->cfg.node_priv);
msgb_free(ack);
return rc;
}
static int rx_control(struct osmo_iuup_cn *cn, struct msgb *pdu,
struct osmo_iuup_hdr_ctrl *hdr)
{
switch (hdr->procedure) {
case OSMO_IUUP_PROC_INITIALIZATION:
switch (hdr->ack_nack) {
case OSMO_IUUP_ACKNACK_PROCEDURE:
LOGP(DIUUP, LOGL_INFO, "(%s) Rx IuUP Initialization, sending ACK\n", cn->name);
cn->rtp_payload_type = ((struct rtp_hdr*)pdu->data)->payload_type;
return tx_init_ack(cn, pdu);
default:
LOGP(DIUUP, LOGL_DEBUG, "(%s) Rx IuUP Initialization, unhandled ack_nack = %d\n",
cn->name, hdr->ack_nack);
break;
}
/* Continue to log "unexpected procedure" below. */
break;
case OSMO_IUUP_PROC_ERROR_EVENT:
{
union osmo_iuup_hdr_ctrl_payload *p = (void*)hdr->payload;
LOGP(DIUUP, LOGL_ERROR,
"(%s) Rx IuUP Error Event: distance=%u, cause=%u=\"%s\"\n",
cn->name, p->error_event.error_distance, p->error_event.error_cause,
osmo_iuup_error_cause_name(p->error_event.error_cause));
return 0;
}
default:
break;
}
LOG_IUUP_CN(cn, LOGL_ERROR,
"Rx control PDU with unexpected procedure: 0x%x acknack=0x%x\n",
hdr->procedure, hdr->ack_nack);
return -EINVAL;
}
/* Feed a received PDU to the IuUP CN node. This function takes ownership of the msgb, it must not be
* freed by the caller. */
int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu)
{
struct osmo_iuup_hdr_ctrl *is_ctrl;
struct osmo_iuup_hdr_data *is_data;
int rc;
rc = osmo_iuup_classify(true, cn->name, pdu, &is_ctrl, &is_data);
if (rc)
return rc;
if (is_ctrl)
return rx_control(cn, pdu, is_ctrl);
if (is_data)
return rx_data(cn, pdu, is_data);
return rc;
}
static uint8_t next_frame_nr(struct osmo_iuup_cn *cn)
{
uint8_t frame_nr = cn->next_frame_nr;
cn->next_frame_nr = (frame_nr + 1) & 0x0f;
return frame_nr;
}
/* Send this RTP packet to the IuUP peer: add IuUP header and call the tx_msg() to transmit the resulting
* message to the IuUP peer.
* Returns 0 on success, negative on error. */
int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *pdu)
{
struct rtp_hdr *rtp_was, *rtp;
struct osmo_iuup_hdr_data *iuup_hdr;
/* Splice an IuUP header in between RTP header and payload data */
rtp_was = (void*)pdu->data;
/* copy the RTP header part backwards by the size needed for the IuUP header */
/* also strips 2 bytes from the front of RTP payload - AMR header - AD HOC fix */
rtp = (void*)msgb_push(pdu, sizeof(*iuup_hdr) - 2);
memmove(rtp, rtp_was, sizeof(*rtp));
/* The IuUP side negotiated a payload type number to use during Initialization. The RTP packet going to the IuUP
* peer should reflect this payload_type. This should already have happened in mgcp_patch_pt(), but can't hurt
* to patch over it again. */
rtp->payload_type = cn->rtp_payload_type;
iuup_hdr = (void*)rtp->data;
*iuup_hdr = (struct osmo_iuup_hdr_data){
.pdu_type = OSMO_IUUP_PDU_DATA_WITH_CRC,
.frame_nr = next_frame_nr(cn),
.frame_good = OSMO_IUUP_FRAME_GOOD,
};
osmo_iuup_set_checksums((uint8_t*)iuup_hdr, pdu->tail - (uint8_t*)iuup_hdr);
LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP inserting IuUP header in RTP data (frame nr %u)\n",
cn->name, iuup_hdr->frame_nr);
return cn->cfg.tx_msg(pdu, cn->cfg.node_priv);
}

View File

@@ -1,286 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/* IuUP Core Network side protocol, minimal implementation */
/*
* (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Neels Hofmeyr <neels@hofmeyr.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <errno.h>
#include <osmocom/mgcp/iuup_protocol.h>
#include <osmocom/mgcp/debug.h>
#include <osmocom/netif/rtp.h>
/* Calculating two bytes of CRC is ok to do by a loop */
static uint8_t header_crc6(const uint8_t *hdr)
{
int bit;
/* Polynomial: D^6 + D^5 + D^3 + D^2 + D^1 + 1
* that's 1101111 or 0x6f;
* align its lowest bit with a uint16_t's highest bit: */
uint32_t polynomial = 0x6f << 15; // 00110111 10000000 00000000
uint32_t remainder = ( ((uint32_t)hdr[0]) << 8 | hdr[1] ) << 6;
for (bit = 15; bit >= 0; bit--)
{
if (remainder & (0x40 << bit))
remainder ^= polynomial;
polynomial >>= 1;
}
return remainder;
}
/*
* Charles Michael Heard's CRC-10 code, from
*
* http://web.archive.org/web/20061005231950/http://cell-relay.indiana.edu/cell-relay/publications/software/CRC/crc10.html
*
* with the CRC table initialized with values computed by
* his "gen_byte_crc10_table()" routine, rather than by calling that
* routine at run time, and with various data type cleanups.
*/
static const uint16_t byte_crc10_table[256] = {
0x0000, 0x0233, 0x0255, 0x0066, 0x0299, 0x00aa, 0x00cc, 0x02ff,
0x0301, 0x0132, 0x0154, 0x0367, 0x0198, 0x03ab, 0x03cd, 0x01fe,
0x0031, 0x0202, 0x0264, 0x0057, 0x02a8, 0x009b, 0x00fd, 0x02ce,
0x0330, 0x0103, 0x0165, 0x0356, 0x01a9, 0x039a, 0x03fc, 0x01cf,
0x0062, 0x0251, 0x0237, 0x0004, 0x02fb, 0x00c8, 0x00ae, 0x029d,
0x0363, 0x0150, 0x0136, 0x0305, 0x01fa, 0x03c9, 0x03af, 0x019c,
0x0053, 0x0260, 0x0206, 0x0035, 0x02ca, 0x00f9, 0x009f, 0x02ac,
0x0352, 0x0161, 0x0107, 0x0334, 0x01cb, 0x03f8, 0x039e, 0x01ad,
0x00c4, 0x02f7, 0x0291, 0x00a2, 0x025d, 0x006e, 0x0008, 0x023b,
0x03c5, 0x01f6, 0x0190, 0x03a3, 0x015c, 0x036f, 0x0309, 0x013a,
0x00f5, 0x02c6, 0x02a0, 0x0093, 0x026c, 0x005f, 0x0039, 0x020a,
0x03f4, 0x01c7, 0x01a1, 0x0392, 0x016d, 0x035e, 0x0338, 0x010b,
0x00a6, 0x0295, 0x02f3, 0x00c0, 0x023f, 0x000c, 0x006a, 0x0259,
0x03a7, 0x0194, 0x01f2, 0x03c1, 0x013e, 0x030d, 0x036b, 0x0158,
0x0097, 0x02a4, 0x02c2, 0x00f1, 0x020e, 0x003d, 0x005b, 0x0268,
0x0396, 0x01a5, 0x01c3, 0x03f0, 0x010f, 0x033c, 0x035a, 0x0169,
0x0188, 0x03bb, 0x03dd, 0x01ee, 0x0311, 0x0122, 0x0144, 0x0377,
0x0289, 0x00ba, 0x00dc, 0x02ef, 0x0010, 0x0223, 0x0245, 0x0076,
0x01b9, 0x038a, 0x03ec, 0x01df, 0x0320, 0x0113, 0x0175, 0x0346,
0x02b8, 0x008b, 0x00ed, 0x02de, 0x0021, 0x0212, 0x0274, 0x0047,
0x01ea, 0x03d9, 0x03bf, 0x018c, 0x0373, 0x0140, 0x0126, 0x0315,
0x02eb, 0x00d8, 0x00be, 0x028d, 0x0072, 0x0241, 0x0227, 0x0014,
0x01db, 0x03e8, 0x038e, 0x01bd, 0x0342, 0x0171, 0x0117, 0x0324,
0x02da, 0x00e9, 0x008f, 0x02bc, 0x0043, 0x0270, 0x0216, 0x0025,
0x014c, 0x037f, 0x0319, 0x012a, 0x03d5, 0x01e6, 0x0180, 0x03b3,
0x024d, 0x007e, 0x0018, 0x022b, 0x00d4, 0x02e7, 0x0281, 0x00b2,
0x017d, 0x034e, 0x0328, 0x011b, 0x03e4, 0x01d7, 0x01b1, 0x0382,
0x027c, 0x004f, 0x0029, 0x021a, 0x00e5, 0x02d6, 0x02b0, 0x0083,
0x012e, 0x031d, 0x037b, 0x0148, 0x03b7, 0x0184, 0x01e2, 0x03d1,
0x022f, 0x001c, 0x007a, 0x0249, 0x00b6, 0x0285, 0x02e3, 0x00d0,
0x011f, 0x032c, 0x034a, 0x0179, 0x0386, 0x01b5, 0x01d3, 0x03e0,
0x021e, 0x002d, 0x004b, 0x0278, 0x0087, 0x02b4, 0x02d2, 0x00e1
};
static uint16_t crc10(uint16_t crc10_accum, const uint8_t *payload, unsigned int payload_len)
{
int i;
for (i = 0; i < payload_len; i++) {
crc10_accum = ((crc10_accum << 8) & 0x300)
^ byte_crc10_table[(crc10_accum >> 2) & 0xff]
^ payload[i];
}
return crc10_accum;
}
/* When a payload of a multiple of bytes has run through, we need to still feed 10 bits of zeros into the
* CRC10 to get the payload's checksum result that we can send to a peer. That can't be done with above
* table, because it acts as if full 16 bits are fed. This stops after 10 bits. */
static uint16_t crc10_remainder(uint16_t crc10_accum)
{
int bit;
/* Polynomial: D^10 + D^9 + D^5 + D^4 + D^1 + 1
* that's 11000110011 or 0x633;
* align its lowest bit with a 10bit value's highest bit: */
uint32_t polynomial = 0x633 << 9; // 1100 01100110 00000000
uint32_t remainder = ((uint32_t)crc10_accum) << 10;
/* Run on 10 bits */
for (bit = 9; bit >= 0; bit--)
{
if (remainder & ((1 << 10) << bit))
remainder ^= polynomial;
polynomial >>= 1;
}
return remainder & 0x3ff;
}
static uint16_t payload_crc10(const uint8_t *payload, unsigned int payload_len)
{
uint16_t crc10_accum = crc10(0, payload, payload_len);
return crc10_remainder(crc10_accum);
}
/* Given an IuUP PDU data block, write the correct header and payload CRC checksums at the right places.
*/
void osmo_iuup_set_checksums(uint8_t *iuup_header_and_payload, unsigned int header_and_payload_len)
{
/* For both data and ctrl, the checksums and payload are at the same offset */
struct osmo_iuup_hdr_data *hdr = (void*)iuup_header_and_payload;
uint16_t crc;
unsigned int payload_len;
hdr->header_crc = header_crc6(iuup_header_and_payload);
payload_len = iuup_header_and_payload + header_and_payload_len - hdr->payload;
crc = payload_crc10(hdr->payload, payload_len);
hdr->payload_crc_hi = (crc >> 8) & 0x3;
hdr->payload_crc_lo = crc & 0xff;
}
/* Validate minimum message sizes, IuUP PDU type, header- and payload checksums. If it is a Control
* Procedure PDU, return the header position in is_ctrl, if it is a Data PDU, return the header position
* in is_data. If log_errors is true, log on DIUUP with the given log label for context. Return NULL in
* both is_ctrl and is_data, and return a negative error code if the PDU could not be identified as a
* valid RTP PDU containing an IuUP part. */
int osmo_iuup_classify(bool log_errors,
const char *log_label,
struct msgb *pdu,
struct osmo_iuup_hdr_ctrl **is_ctrl,
struct osmo_iuup_hdr_data **is_data)
{
struct rtp_hdr *rtp = (void*)pdu->data;
struct osmo_iuup_hdr_ctrl *hdr = (void*)rtp->data;
unsigned int payload_len;
uint16_t crc_calculated;
uint16_t crc_from_peer;
#define ERR(fmt, args...) do { \
if (log_errors) \
LOGP(DIUUP, LOGL_ERROR, "(%s) " fmt, log_label? : "-", ## args); \
return -EINVAL; \
} while (0)
if (is_ctrl)
*is_ctrl = NULL;
if (is_data)
*is_data = NULL;
/* We need at least a header of 4 bytes. The osmo_iuup_hdr_ctrl already includes a byte of
* payload, so use osmo_iuup_hdr_data to check the minimum here. */
if (pdu->len < (sizeof(*rtp) + sizeof(struct osmo_iuup_hdr_data)))
ERR("IuUP PDU too short: %u\n", pdu->len);
/* Let's not validate checksums if the header type isn't sane */
switch (hdr->pdu_type) {
case OSMO_IUUP_PDU_DATA_WITH_CRC:
/* If the caller isn't interested in data PDUs, cut short here. */
if (!is_data)
return 0;
break;
case OSMO_IUUP_PDU_CONTROL_PROCEDURE:
/* If the caller isn't interested in control PDUs, cut short here. */
if (!is_ctrl)
return 0;
if (pdu->len < (sizeof(*rtp) + sizeof(struct osmo_iuup_hdr_ctrl)))
ERR("IuUP control PDU too short: %u\n", pdu->len);
break;
default:
ERR("IuUP with invalid type: %u\n", hdr->pdu_type);
}
/* For both data and ctrl, the checksums and payload are at the same offset */
crc_calculated = header_crc6((uint8_t*)hdr);
if (crc_calculated != hdr->header_crc)
ERR("IuUP PDU with invalid header CRC (peer sent 0x%x, calculated 0x%x)\n",
hdr->header_crc, crc_calculated);
payload_len = pdu->tail - hdr->payload;
crc_calculated = payload_crc10(hdr->payload, payload_len);
crc_from_peer = (((uint16_t)hdr->payload_crc_hi) << 8) | hdr->payload_crc_lo;
if (crc_from_peer != crc_calculated)
ERR("IuUP PDU with invalid payload CRC (peer sent 0x%x, calculated 0x%x)\n",
crc_from_peer, crc_calculated);
switch (hdr->pdu_type) {
case OSMO_IUUP_PDU_DATA_WITH_CRC:
if (is_data)
*is_data = (void*)hdr;
return 0;
case OSMO_IUUP_PDU_CONTROL_PROCEDURE:
if (is_ctrl)
*is_ctrl = hdr;
return 0;
default:
ERR("IuUP with invalid type: %u\n", hdr->pdu_type);
}
#undef ERR
}
/* Return true if this RTP packet contains an IuUP Initialization header (detect IuUP peer). */
bool osmo_iuup_is_init(struct msgb *pdu)
{
struct osmo_iuup_hdr_ctrl *is_ctrl;
osmo_iuup_classify(false, NULL, pdu, &is_ctrl, NULL);
return is_ctrl
&& is_ctrl->procedure == OSMO_IUUP_PROC_INITIALIZATION
&& is_ctrl->ack_nack == OSMO_IUUP_ACKNACK_PROCEDURE;
}
/* Append an IuUP Initialization ACK message */
void osmo_iuup_make_init_ack(struct msgb *ack)
{
/* Send Initialization Ack PDU back to the sender */
struct osmo_iuup_hdr_ctrl *hdr;
OSMO_ASSERT(ack);
hdr = (void*)msgb_put(ack, sizeof(*hdr));
*hdr = (struct osmo_iuup_hdr_ctrl){
.pdu_type = OSMO_IUUP_PDU_CONTROL_PROCEDURE,
.ack_nack = OSMO_IUUP_ACKNACK_ACK,
.procedure = OSMO_IUUP_PROC_INITIALIZATION,
};
osmo_iuup_set_checksums((uint8_t*)hdr, sizeof(*hdr));
}
const struct value_string osmo_iuup_error_cause_names[] = {
{ 0, "CRC error of frame header" },
{ 1, "CRC error of frame payload" },
{ 2, "Unexpected frame number" },
{ 3, "Frame loss" },
{ 4, "PDU type unknown" },
{ 5, "Unknown procedure" },
{ 6, "Unknown reserved value" },
{ 7, "Unknown field" },
{ 8, "Frame too short" },
{ 9, "Missing fields" },
{ 16, "Unexpected PDU type" },
{ 17, "spare" },
{ 18, "Unexpected procedure" },
{ 19, "Unexpected RFCI" },
{ 20, "Unexpected value" },
{ 42, "Initialisation failure" },
{ 43, "Initialisation failure (network error, timer expiry)" },
{ 44, "Initialisation failure (Iu UP function error, repeated NACK)" },
{ 45, "Rate control failure" },
{ 46, "Error event failure" },
{ 47, "Time Alignment not supported" },
{ 48, "Requested Time Alignment not possible" },
{ 49, "Iu UP Mode version not supported" },
{}
};

View File

@@ -451,19 +451,3 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
return codec_dst->payload_type;
}
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
const char *subtype_name, unsigned int match_nr)
{
int i;
for (i = 0; i < conn->end.codecs_assigned; i++) {
if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
if (match_nr) {
match_nr--;
continue;
}
return &conn->end.codecs[i];
}
}
return NULL;
}

View File

@@ -259,7 +259,6 @@ aggregate_rtp_conn_stats(struct mgcp_trunk_config *trunk, struct mgcp_conn_rtp *
{
struct rate_ctr_group *all_stats = trunk->all_rtp_conn_stats;
struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
int i;
if (all_stats == NULL || conn_stats == NULL)
return;
@@ -269,8 +268,11 @@ aggregate_rtp_conn_stats(struct mgcp_trunk_config *trunk, struct mgcp_conn_rtp *
* All other counters in both counter groups correspond to each other. */
OSMO_ASSERT(conn_stats->desc->num_ctr + 1 == all_stats->desc->num_ctr);
for (i = 0; i < conn_stats->desc->num_ctr; i++)
rate_ctr_add(&all_stats->ctr[i], conn_stats->ctr[i].current);
/* all other counters are [now] updated in real-time */
rate_ctr_add(&all_stats->ctr[IN_STREAM_ERR_TSTMP_CTR],
conn_stats->ctr[IN_STREAM_ERR_TSTMP_CTR].current);
rate_ctr_add(&all_stats->ctr[OUT_STREAM_ERR_TSTMP_CTR],
conn_stats->ctr[OUT_STREAM_ERR_TSTMP_CTR].current);
rate_ctr_inc(&all_stats->ctr[RTP_NUM_CONNECTIONS]);
}

View File

@@ -0,0 +1,36 @@
/*
* (C) 2020 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/ctrl/control_if.h>
#include <osmocom/mgcp/mgcp.h>
static int mgw_ctrl_node_lookup(void *data, vector vline, int *node_type,
void **node_data, int *i)
{
return 0;
}
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
const char *bind_addr, uint16_t port)
{
return ctrl_interface_setup_dynip2(cfg, bind_addr, port, mgw_ctrl_node_lookup,
_LAST_CTRL_NODE);
}

View File

@@ -45,8 +45,6 @@
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/debug.h>
#include <osmocom/codec/codec.h>
#include <osmocom/mgcp/iuup_cn_node.h>
#include <osmocom/mgcp/iuup_protocol.h>
#define RTP_SEQ_MOD (1 << 16)
@@ -54,12 +52,26 @@
#define RTP_MAX_MISORDER 100
#define RTP_BUF_SIZE 4096
enum rtp_proto {
enum {
MGCP_PROTO_RTP,
MGCP_PROTO_RTCP,
};
static int rx_rtp(struct msgb *msg);
static void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
int id, int inc)
{
struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
struct rate_ctr_group *trunk_stats = endp->tcfg->all_rtp_conn_stats;
/* add to both the per-connection and the per-trunk global stats */
rate_ctr_add(&conn_stats->ctr[id], inc);
rate_ctr_add(&trunk_stats->ctr[id], inc);
}
static void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
{
rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
}
/*! Determine the local rtp bind IP-address.
* \param[out] addr caller provided memory to store the resulting IP-Address
@@ -473,43 +485,21 @@ void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
* Patch the payload type of an RTP packet so that it uses the payload type
* that is valid for the destination connection (conn_dst) */
static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
struct mgcp_conn_rtp *conn_dst, char *data, int len)
{
struct rtp_hdr *rtp_hdr;
uint8_t pt_in;
int pt_out;
if (msg->len < sizeof(struct rtp_hdr)) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
msg->len, sizeof(struct rtp_hdr));
if (len < sizeof(struct rtp_hdr))
return -EINVAL;
}
rtp_hdr = (struct rtp_hdr *)msg->data;
rtp_hdr = (struct rtp_hdr *)data;
if (conn_src->iuup) {
/* The source is an IuUP payload. We have received a dynamic payload type number on the IuUP side, and
* towards the pure RTP side it should go out as "AMR/8000". Make sure that the payload type number in
* the RTP packet matches the a=rtpmap:N payload type number configured for AMR. */
const struct mgcp_rtp_codec *amr_codec = mgcp_codec_pt_find_by_subtype_name(conn_dst, "AMR", 0);
if (!amr_codec) {
/* There is no AMR codec configured on the outgoing conn. */
return -EINVAL;
}
pt_out = amr_codec->payload_type;
} else if (conn_dst->iuup) {
/* The destination is an IuUP payload. Use whatever payload number was negotiated during IuUP
* Initialization. */
pt_out = conn_dst->iuup->rtp_payload_type;
} else {
/* Both sides are normal RTP payloads. Consult the rtpmap settings received by SDP. */
pt_in = rtp_hdr->payload_type;
pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
if (pt_out < 0)
return -EINVAL;
}
pt_in = rtp_hdr->payload_type;
pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
if (pt_out < 0)
return -EINVAL;
rtp_hdr->payload_type = (uint8_t) pt_out;
return 0;
@@ -524,7 +514,7 @@ static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
void mgcp_patch_and_count(struct mgcp_endpoint *endp,
struct mgcp_rtp_state *state,
struct mgcp_rtp_end *rtp_end,
struct sockaddr_in *addr, struct msgb *msg)
struct sockaddr_in *addr, char *data, int len)
{
uint32_t arrival_time;
int32_t transit;
@@ -532,12 +522,11 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
uint32_t timestamp, ssrc;
struct rtp_hdr *rtp_hdr;
int payload = rtp_end->codec->payload_type;
unsigned int len = msg->len;
if (len < sizeof(*rtp_hdr))
return;
rtp_hdr = (struct rtp_hdr *)msg->data;
rtp_hdr = (struct rtp_hdr *)data;
seq = ntohs(rtp_hdr->sequence);
timestamp = ntohl(rtp_hdr->timestamp);
arrival_time = get_current_ts(rtp_end->codec->rate);
@@ -797,14 +786,15 @@ static int amr_oa_check(char *data, int len)
/* Forward data to a debug tap. This is debug function that is intended for
* debugging the voice traffic with tools like gstreamer */
static void forward_data(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
static void forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf,
int len)
{
int rc;
if (!tap->enabled)
return;
rc = sendto(fd, msg->data, msg->len, 0, (struct sockaddr *)&tap->forward,
rc = sendto(fd, buf, len, 0, (struct sockaddr *)&tap->forward,
sizeof(tap->forward));
if (rc < 0)
@@ -822,7 +812,7 @@ static void forward_data(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
* \param[in] conn_dst associated destination connection
* \returns 0 on success, -1 on ERROR */
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
struct msgb *msg, struct mgcp_conn_rtp *conn_src,
char *buf, int len, struct mgcp_conn_rtp *conn_src,
struct mgcp_conn_rtp *conn_dst)
{
/*! When no destination connection is available (e.g. when only one
@@ -834,7 +824,6 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
struct mgcp_rtp_state *rtp_state;
char *dest_name;
int rc;
int len;
OSMO_ASSERT(conn_src);
OSMO_ASSERT(conn_dst);
@@ -858,7 +847,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
* should not occur if transcoding is consequently avoided. Until
* we have transcoding support in osmo-mgw we can not resolve this. */
if (is_rtp) {
rc = mgcp_patch_pt(conn_src, conn_dst, msg);
rc = mgcp_patch_pt(conn_src, conn_dst, buf, len);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"can not patch PT because no suitable egress codec was found.\n");
@@ -872,7 +861,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
dest_name = conn_dst->conn->name;
if (!rtp_end->output_enabled) {
rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_DROPPED_PACKETS_CTR]);
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_DROPPED_PACKETS_CTR);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"output disabled, drop to %s %s "
"rtp_port:%u rtcp_port:%u\n",
@@ -883,21 +872,21 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
} else if (is_rtp) {
int cont;
int nbytes = 0;
int buflen = msg->len;
int buflen = len;
do {
/* Run transcoder */
cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
(char*)msg->data, &buflen,
buf, &buflen,
RTP_BUF_SIZE);
if (cont < 0)
break;
if (addr)
mgcp_patch_and_count(endp, rtp_state, rtp_end,
addr, msg);
addr, buf, buflen);
if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, (char*)msg->data, &buflen,
rc = amr_oa_bwe_convert(endp, buf, &buflen,
conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
@@ -908,7 +897,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
else if (rtp_end->rfc5993_hr_convert
&& strcmp(conn_src->end.codec->subtype_name,
"GSM-HR-08") == 0) {
rc = rfc5993_hr_convert(endp, (char*)msg->data, &buflen);
rc = rfc5993_hr_convert(endp, buf, &buflen);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
break;
@@ -924,9 +913,8 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
/* Forward a copy of the RTP data to a debug ip/port */
forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
buf, buflen);
#if 0
/* FIXME: HACK HACK HACK. See OS#2459.
* The ip.access nano3G needs the first RTP payload's first two bytes to read hex
* 'e400', or it will reject the RAB assignment. It seems to not harm other femto
@@ -934,7 +922,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
*/
if (!rtp_state->patched_first_rtp_payload
&& conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
uint8_t *data = msg->data + 12;
uint8_t *data = (uint8_t *) & buf[12];
if (data[0] == 0xe0) {
data[0] = 0xe4;
data[1] = 0x00;
@@ -944,19 +932,16 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
" to fake an IuUP Initialization Ack\n");
}
}
#endif
if (conn_dst->iuup)
len = osmo_iuup_cn_tx_payload(conn_dst->iuup, msg);
else
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
(char*)msg->data, msg->len);
len = mgcp_udp_send(rtp_end->rtp.fd,
&rtp_end->addr,
rtp_end->rtp_port, buf, buflen);
if (len <= 0)
return len;
rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
nbytes += len;
buflen = cont;
@@ -971,10 +956,10 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
len = mgcp_udp_send(rtp_end->rtcp.fd,
&rtp_end->addr,
rtp_end->rtcp_port, (char*)msg->data, msg->len);
rtp_end->rtcp_port, buf, len);
rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
return len;
}
@@ -982,6 +967,45 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
return 0;
}
/* Helper function for mgcp_recv(),
Receive one RTP Packet + Originating address from file descriptor */
static int receive_from(struct mgcp_endpoint *endp, int fd,
struct sockaddr_in *addr, char *buf, int bufsize)
{
int rc;
socklen_t slen = sizeof(*addr);
struct sockaddr_in addr_sink;
char buf_sink[RTP_BUF_SIZE];
bool tossed = false;
if (!addr)
addr = &addr_sink;
if (!buf) {
tossed = true;
buf = buf_sink;
bufsize = sizeof(buf_sink);
}
rc = recvfrom(fd, buf, bufsize, 0, (struct sockaddr *)addr, &slen);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"receiving %u bytes length packet from %s:%u ...\n",
rc, inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to receive packet, errno: %d/%s\n",
errno, strerror(errno));
return -1;
}
if (tossed) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "packet tossed\n");
}
return rc;
}
/* Check if the origin (addr) matches the address/port data of the RTP
* connections. */
static int check_rtp_origin(struct mgcp_conn_rtp *conn,
@@ -1074,7 +1098,7 @@ static int check_rtp_destin(struct mgcp_conn_rtp *conn)
/* Do some basic checks to make sure that the RTCP packets we are going to
* process are not complete garbage */
static int check_rtcp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
static int check_rtcp(char *buf, unsigned int buf_size)
{
struct rtcp_hdr *hdr;
unsigned int len;
@@ -1082,45 +1106,33 @@ static int check_rtcp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
/* RTPC packets that are just a header without data do not make
* any sense. */
if (msg->len < sizeof(struct rtcp_hdr)) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP packet too short (%u < %zu)\n",
msg->len, sizeof(struct rtcp_hdr));
if (buf_size < sizeof(struct rtcp_hdr))
return -EINVAL;
}
/* Make sure that the length of the received packet does not exceed
* the available buffer size */
hdr = (struct rtcp_hdr *)msg->data;
hdr = (struct rtcp_hdr *)buf;
len = (osmo_ntohs(hdr->length) + 1) * 4;
if (len > msg->len) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP header length exceeds packet size (%u > %u)\n",
len, msg->len);
if (len > buf_size)
return -EINVAL;
}
/* Make sure we accept only packets that have a proper packet type set
* See also: http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */
type = hdr->type;
if ((type < 192 || type > 195) && (type < 200 || type > 213)) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP header: invalid type: %u\n", type);
if ((type < 192 || type > 195) && (type < 200 || type > 213))
return -EINVAL;
}
return 0;
}
/* Do some basic checks to make sure that the RTP packets we are going to
* process are not complete garbage */
static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
static int check_rtp(char *buf, unsigned int buf_size)
{
size_t min_size = sizeof(struct rtp_hdr);
if (conn_src->iuup)
min_size += sizeof(struct osmo_iuup_hdr_data);
if (msg->len < min_size) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
msg->len, min_size);
return -1;
}
/* RTP packets that are just a header without data do not make
* any sense. */
if (buf_size < sizeof(struct rtp_hdr))
return -EINVAL;
/* FIXME: Add more checks, the reason why we do not check more than
* the length is because we currently handle IUUP packets as RTP
@@ -1131,14 +1143,86 @@ static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
return 0;
}
/* Receive RTP data from a specified source connection and dispatch it to a
* destination connection. */
static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
unsigned int buf_size, struct osmo_fd *fd)
{
struct mgcp_endpoint *endp;
struct mgcp_conn_rtp *conn;
struct mgcp_trunk_config *tcfg;
int rc;
conn = (struct mgcp_conn_rtp*) fd->data;
endp = conn->conn->endp;
tcfg = endp->tcfg;
LOGPCONN(conn->conn, DRTP, LOGL_DEBUG, "receiving RTP/RTCP packet...\n");
rc = receive_from(endp, fd->fd, addr, buf, buf_size);
if (rc <= 0)
return -1;
/* FIXME: The way how we detect the protocol looks odd. We should look
* into the packet header. Also we should introduce a packet type
* MGCP_PROTO_IUUP because currently we handle IUUP packets like RTP
* packets which is problematic. */
*proto = fd == &conn->end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
if (*proto == MGCP_PROTO_RTP) {
if (check_rtp(buf, rc) < 0) {
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
"invalid RTP packet received -- packet tossed\n");
return -1;
}
} else if (*proto == MGCP_PROTO_RTCP) {
if (check_rtcp(buf, rc) < 0) {
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
"invalid RTCP packet received -- packet tossed\n");
return -1;
}
}
LOGPCONN(conn->conn, DRTP, LOGL_DEBUG, "");
LOGPC(DRTP, LOGL_DEBUG, "receiving from %s %s %d\n",
conn->conn->name, inet_ntoa(addr->sin_addr),
ntohs(addr->sin_port));
LOGPENDP(endp, DRTP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn->conn));
/* Check if the origin of the RTP packet seems plausible */
if (tcfg->rtp_accept_all == 0) {
if (check_rtp_origin(conn, addr) != 0)
return -1;
}
/* Filter out dummy message */
if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {
LOGPCONN(conn->conn, DRTP, LOGL_NOTICE,
"dummy message received\n");
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
"packet tossed\n");
return 0;
}
/* Increment RX statistics */
rtpconn_rate_ctr_inc(conn, endp, RTP_PACKETS_RX_CTR);
rtpconn_rate_ctr_add(conn, endp, RTP_OCTETS_RX_CTR, rc);
/* Forward a copy of the RTP data to a debug ip/port */
forward_data(fd->fd, &conn->tap_in, buf, rc);
return rc;
}
/* Send RTP data. Possible options are standard RTP packet
* transmission or trsmission via an osmux connection */
static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,
unsigned int buf_size,
struct mgcp_conn_rtp *conn_src,
struct mgcp_conn_rtp *conn_dst)
{
enum rtp_proto proto = OSMO_RTP_MSG_CTX(msg)->proto;
struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
struct mgcp_endpoint *endp = conn_src->conn->endp;
struct mgcp_endpoint *endp;
endp = conn_src->conn->endp;
LOGPENDP(endp, DRTP, LOGL_DEBUG, "destin conn:%s\n",
mgcp_conn_dump(conn_dst->conn));
@@ -1157,13 +1241,13 @@ static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
"endpoint type is MGCP_RTP_DEFAULT, "
"using mgcp_send() to forward data directly\n");
return mgcp_send(endp, proto == MGCP_PROTO_RTP,
from_addr, msg, conn_src, conn_dst);
addr, buf, buf_size, conn_src, conn_dst);
case MGCP_OSMUX_BSC_NAT:
case MGCP_OSMUX_BSC:
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"endpoint type is MGCP_OSMUX_BSC_NAT, "
"using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
return osmux_xfrm_to_osmux((char*)msg->data, msg->len, conn_dst);
return osmux_xfrm_to_osmux(buf, buf_size, conn_dst);
}
/* If the data has not been handled/forwarded until here, it will
@@ -1181,15 +1265,13 @@ static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
* \param[in] buf_size size data length of buf
* \param[in] conn originating connection
* \returns 0 on success, -1 on ERROR */
int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
unsigned int buf_size, struct mgcp_conn *conn)
{
struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
struct mgcp_conn *conn = conn_src->conn;
struct mgcp_conn *conn_dst;
struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
/*! NOTE: This callback function implements the endpoint specific
* dispatch bahviour of an rtp bridge/proxy endpoint. It is assumed
* dispatch behaviour of an rtp bridge/proxy endpoint. It is assumed
* that the endpoint will hold only two connections. This premise
* is used to determine the opposite connection (it is always the
* connection that is not the originating connection). Once the
@@ -1205,10 +1287,11 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
* address data from the UDP packet header to patch the
* outgoing address in connection on the fly */
if (conn->u.rtp.end.rtp_port == 0) {
conn->u.rtp.end.addr = from_addr->sin_addr;
conn->u.rtp.end.rtp_port = from_addr->sin_port;
conn->u.rtp.end.addr = addr->sin_addr;
conn->u.rtp.end.rtp_port = addr->sin_port;
}
return mgcp_send_rtp(conn_src, msg);
return mgcp_send_rtp(proto, addr, buf,
buf_size, &conn->u.rtp, &conn->u.rtp);
}
/* Find a destination connection. */
@@ -1227,8 +1310,8 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
/* There is no destination conn, stop here */
if (!conn_dst) {
LOGPCONN(conn, DRTP, LOGL_ERROR,
"unable to find destination conn\n");
LOGPCONN(conn, DRTP, LOGL_DEBUG,
"no connection to forward an incoming RTP packet to\n");
return -1;
}
@@ -1240,7 +1323,9 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
}
/* Dispatch RTP packet to destination RTP connection */
return mgcp_send_rtp(&conn_dst->u.rtp, msg);
return mgcp_send_rtp(proto, addr, buf,
buf_size, &conn->u.rtp, &conn_dst->u.rtp);
}
/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
@@ -1262,76 +1347,6 @@ void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *co
}
}
static bool is_dummy_msg(enum rtp_proto proto, struct msgb *msg)
{
return msg->len == 1 && msg->data[0] == MGCP_DUMMY_LOAD;
}
struct pdu_ctx {
struct sockaddr_in *from_addr;
struct mgcp_conn_rtp *conn_src;
};
/* IuUP CN node has stripped an IuUP header and forwards RTP data to distribute to the peers. */
int iuup_rx_payload(struct msgb *msg, void *node_priv)
{
struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "iuup_rx_payload(%u bytes)\n", msg->len);
return rx_rtp(msg);
}
/* IuUP CN node has composed a message that contains an IuUP header and asks us to send to the IuUP peer.
*/
int iuup_tx_msg(struct msgb *msg, void *node_priv)
{
const struct in_addr zero_addr = {};
struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
struct mgcp_conn_rtp *conn_dst = node_priv;
struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
struct mgcp_rtp_end *rtp_end = &conn_dst->end;
struct in_addr to_addr = rtp_end->addr;
uint16_t to_port = rtp_end->rtp_port;
if (conn_src == conn_dst
&& !memcmp(&zero_addr, &to_addr, sizeof(zero_addr)) && !to_port) {
LOG_CONN_RTP(conn_dst, LOGL_DEBUG, "iuup_tx_msg(): direct IuUP reply\n");
/* IuUP wants to send a message back to the same peer that sent an RTP package, but there
* is no address configured for that peer yet. It is probably an IuUP Initialization ACK
* reply. Use the sender address to send the reply.
*
* During 3G RAB Assignment, a 3G cell might first probe the MGW and expect an IuUP
* Initialization ACK before it replies to the MSC with a successful RAB Assignment; only
* after that reply does MSC officially know which RTP address+port the 3G cell wants to
* use and can tell this MGW about it, so this "loopback" is, for some 3G cells, the only
* chance we have to get a successful RAB Assignment done (particularly the nano3G does
* this). */
to_addr = from_addr->sin_addr;
to_port = from_addr->sin_port;
}
LOG_CONN_RTP(conn_dst, LOGL_DEBUG, "iuup_tx_msg(%u bytes) to %s:%u\n", msg->len,
inet_ntoa(to_addr), ntohs(to_port));
return mgcp_udp_send(rtp_end->rtp.fd, &to_addr, to_port, (char*)msg->data, msg->len);
}
static void iuup_init(struct mgcp_conn_rtp *conn_src)
{
struct osmo_iuup_cn_cfg cfg = {
.node_priv = conn_src,
.rx_payload = iuup_rx_payload,
.tx_msg = iuup_tx_msg,
};
if (conn_src->iuup) {
LOG_CONN_RTP(conn_src, LOGL_NOTICE, "Rx IuUP init, but already initialized. Ignoring.\n");
return;
}
conn_src->iuup = osmo_iuup_cn_init(conn_src->conn, &cfg, "endp_%d_conn_%s",
ENDPOINT_NUMBER(conn_src->conn->endp), conn_src->conn->id);
}
/* Handle incoming RTP data from NET */
static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
{
@@ -1345,88 +1360,23 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
struct mgcp_conn_rtp *conn_src;
struct mgcp_endpoint *endp;
struct sockaddr_in addr;
socklen_t slen = sizeof(addr);
int ret;
enum rtp_proto proto;
struct osmo_rtp_msg_ctx mc;
struct msgb *msg = msgb_alloc_headroom(RTP_BUF_SIZE + OSMO_IUUP_HEADROOM,
OSMO_IUUP_HEADROOM, "RTP-rx");
int rc;
char buf[RTP_BUF_SIZE];
int proto;
int len;
conn_src = (struct mgcp_conn_rtp *)fd->data;
OSMO_ASSERT(conn_src);
endp = conn_src->conn->endp;
OSMO_ASSERT(endp);
proto = (fd == &conn_src->end.rtp)? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
LOGPENDP(endp, DRTP, LOGL_DEBUG, "source conn:%s\n",
mgcp_conn_dump(conn_src->conn));
ret = recvfrom(fd->fd, msg->data, msg->data_len, 0, (struct sockaddr *)&addr, &slen);
if (ret <= 0) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(errno));
rc = -1;
goto out;
}
msgb_put(msg, ret);
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
proto == MGCP_PROTO_RTP ? "RTP" : "RTPC",
msg->len, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))
|| (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {
/* Logging happened in the two check_ functions */
rc = -1;
goto out;
}
if (is_dummy_msg(proto, msg)) {
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx dummy packet (dropped)\n");
rc = 0;
goto out;
}
mc = (struct osmo_rtp_msg_ctx){
.proto = proto,
.conn_src = conn_src,
.from_addr = &addr,
};
OSMO_RTP_MSG_CTX(msg) = &mc;
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",
OSMO_RTP_MSG_CTX(msg)->proto,
OSMO_RTP_MSG_CTX(msg)->conn_src,
osmo_hexdump((void*)OSMO_RTP_MSG_CTX(msg)->from_addr, sizeof(struct sockaddr_in)));
/* Increment RX statistics */
rate_ctr_inc(&conn_src->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR]);
rate_ctr_add(&conn_src->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR], msg->len);
/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
/* Forward a copy of the RTP data to a debug ip/port */
forward_data(fd->fd, &conn_src->tap_in, msg);
if (proto == MGCP_PROTO_RTP && osmo_iuup_is_init(msg))
iuup_init(conn_src);
if (conn_src->iuup && proto == MGCP_PROTO_RTP)
rc = osmo_iuup_cn_rx_pdu(conn_src->iuup, msg);
else
rc = rx_rtp(msg);
out:
msgb_free(msg);
return rc;
}
static int rx_rtp(struct msgb *msg)
{
struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
struct mgcp_conn *conn = conn_src->conn;
struct mgcp_trunk_config *tcfg = conn->endp->tcfg;
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msg->len);
/* Receive packet */
len = mgcp_recv(&proto, &addr, buf, sizeof(buf), fd);
if (len < 0)
return -1;
mgcp_conn_watchdog_kick(conn_src->conn);
@@ -1435,20 +1385,17 @@ static int rx_rtp(struct msgb *msg)
* define, then we check if the incoming payload matches that
* expectation. */
if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
int oa = amr_oa_check((char*)msg->data, msg->len);
int oa = amr_oa_check(buf, len);
if (oa < 0)
return -1;
if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned)
return -1;
}
/* Check if the origin of the RTP packet seems plausible */
if (!tcfg->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
return -1;
/* Execute endpoint specific implementation that handles the
* dispatching of the RTP data */
return conn->endp->type->dispatch_rtp_cb(msg);
return endp->type->dispatch_rtp_cb(proto, &addr, buf, len,
conn_src->conn);
}
/*! set IP Type of Service parameter.
@@ -1515,7 +1462,7 @@ static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
mgcp_set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
mgcp_set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
rtp_end->rtp.when = BSC_FD_READ;
rtp_end->rtp.when = OSMO_FD_READ;
if (osmo_fd_register(&rtp_end->rtp) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTP port %d\n",
@@ -1523,7 +1470,7 @@ static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
goto cleanup2;
}
rtp_end->rtcp.when = BSC_FD_READ;
rtp_end->rtcp.when = OSMO_FD_READ;
if (osmo_fd_register(&rtp_end->rtcp) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTCP port %d\n",

View File

@@ -234,8 +234,13 @@ static void scheduled_from_osmux_tx_rtp_cb(struct msgb *msg, void *data)
{
struct mgcp_conn_rtp *conn = data;
struct mgcp_endpoint *endp = conn->conn->endp;
struct sockaddr_in addr = {
.sin_addr = conn->end.addr,
.sin_port = conn->end.rtp_port,
}; /* FIXME: not set/used in cb */
endp->type->dispatch_rtp_cb(msg);
endp->type->dispatch_rtp_cb(MGCP_PROTO_RTP, &addr, (char *)msg->data, msg->len, conn->conn);
msgb_free(msg);
}
@@ -401,7 +406,7 @@ int osmux_init(int role, struct mgcp_config *cfg)
return ret;
}
mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
osmux_fd.when |= BSC_FD_READ;
osmux_fd.when |= OSMO_FD_READ;
ret = osmo_fd_register(&osmux_fd);
if (ret < 0) {

View File

@@ -53,6 +53,24 @@ struct mgcp_request {
#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
{ .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
/* rx_msgs = rx_msgs_retransmitted + rx_msgs_handled + rx_msgs_unhandled + err_rx_msg_parse + err_rx_no_endpoint */
[MGCP_GENERAL_RX_MSGS_TOTAL] = {"mgcp:rx_msgs", "total number of MGCP messages received."},
[MGCP_GENERAL_RX_MSGS_RETRANSMITTED] = {"mgcp:rx_msgs_retransmitted", "number of received retransmissions."},
[MGCP_GENERAL_RX_MSGS_HANDLED] = {"mgcp:rx_msgs_handled", "number of handled MGCP messages."},
[MGCP_GENERAL_RX_MSGS_UNHANDLED] = {"mgcp:rx_msgs_unhandled", "number of unhandled MGCP messages."},
[MGCP_GENERAL_RX_FAIL_MSG_PARSE] = {"mgcp:err_rx_msg_parse", "error parsing MGCP message."},
[MGCP_GENERAL_RX_FAIL_NO_ENDPOINT] = {"mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints."},
};
const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
.group_name_prefix = "mgcp",
.group_description = "mgcp general statistics",
.class_id = OSMO_STATS_CLASS_GLOBAL,
.num_ctr = ARRAY_SIZE(mgcp_general_ctr_desc),
.ctr_desc = mgcp_general_ctr_desc
};
static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
[MGCP_CRCX_SUCCESS] = {"crcx:success", "CRCX command processed successfully."},
[MGCP_CRCX_FAIL_BAD_ACTION] = {"crcx:bad_action", "bad action in CRCX command."},
@@ -361,24 +379,33 @@ static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
* - or a response (three numbers, space, transaction id) */
struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
{
struct mgcp_trunk_config *tcfg = &cfg->trunk;
struct rate_ctr_group *rate_ctrs = tcfg->mgcp_general_ctr_group;
struct mgcp_parse_data pdata;
int rc, i, code, handled = 0;
struct msgb *resp = NULL;
char *data;
/* Count all messages, even incorect ones */
rate_ctr_inc(&rate_ctrs->ctr[MGCP_GENERAL_RX_MSGS_TOTAL]);
if (msgb_l2len(msg) < 4) {
LOGP(DLMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
rate_ctr_inc(&rate_ctrs->ctr[MGCP_GENERAL_RX_FAIL_MSG_PARSE]);
return NULL;
}
if (mgcp_msg_terminate_nul(msg))
if (mgcp_msg_terminate_nul(msg)) {
rate_ctr_inc(&rate_ctrs->ctr[MGCP_GENERAL_RX_FAIL_MSG_PARSE]);
return NULL;
}
mgcp_disp_msg(msg->l2h, msgb_l2len(msg), "Received message");
/* attempt to treat it as a response */
if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
LOGP(DLMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
rate_ctr_inc(&rate_ctrs->ctr[MGCP_GENERAL_RX_FAIL_MSG_PARSE]);
return NULL;
}
@@ -394,12 +421,14 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
if (pdata.endp && pdata.trans
&& pdata.endp->last_trans
&& strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
rate_ctr_inc(&rate_ctrs->ctr[MGCP_GENERAL_RX_MSGS_RETRANSMITTED]);
return do_retransmission(pdata.endp);
}
/* check for general parser failure */
if (rc < 0) {
LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to find the endpoint\n", msg->l2h);
rate_ctr_inc(&rate_ctrs->ctr[MGCP_GENERAL_RX_FAIL_NO_ENDPOINT]);
return create_err_response(NULL, -rc, (const char *) msg->l2h, pdata.trans);
}
@@ -413,9 +442,13 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
}
}
if (!handled)
if (handled) {
rate_ctr_inc(&rate_ctrs->ctr[MGCP_GENERAL_RX_MSGS_HANDLED]);
} else {
rate_ctr_inc(&rate_ctrs->ctr[MGCP_GENERAL_RX_MSGS_UNHANDLED]);
LOGP(DLMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n",
&msg->l2h[0]);
}
return resp;
}
@@ -1556,11 +1589,19 @@ static int alloc_mgcp_rate_counters(struct mgcp_trunk_config *trunk, void *ctx)
/* FIXME: Each new rate counter group requires a unique index. At the
* moment we generate an index using a counter, but perhaps there is
* a better way of assigning indices? */
static unsigned int general_rate_ctr_index = 0;
static unsigned int crcx_rate_ctr_index = 0;
static unsigned int mdcx_rate_ctr_index = 0;
static unsigned int dlcx_rate_ctr_index = 0;
static unsigned int all_rtp_conn_rate_ctr_index = 0;
if (trunk->mgcp_general_ctr_group == NULL) {
trunk->mgcp_general_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_general_ctr_group_desc, general_rate_ctr_index);
if (!trunk->mgcp_general_ctr_group)
return -1;
talloc_set_destructor(trunk->mgcp_general_ctr_group, free_rate_counter_group);
general_rate_ctr_index++;
}
if (trunk->mgcp_crcx_ctr_group == NULL) {
trunk->mgcp_crcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index);
if (!trunk->mgcp_crcx_ctr_group)
@@ -1620,7 +1661,7 @@ struct mgcp_config *mgcp_config_alloc(void)
cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
/* default trunk handling */
/* default trunk handling; TODO: avoid duplication with mgcp_trunk_alloc() below */
cfg->trunk.cfg = cfg;
cfg->trunk.trunk_nr = 0;
cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
@@ -1628,6 +1669,7 @@ struct mgcp_config *mgcp_config_alloc(void)
cfg->trunk.audio_payload = 126;
cfg->trunk.audio_send_ptime = 1;
cfg->trunk.audio_send_name = 1;
cfg->trunk.vty_number_endpoints = 33;
cfg->trunk.omit_rtcp = 0;
mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
if (alloc_mgcp_rate_counters(&cfg->trunk, cfg) < 0) {

View File

@@ -255,13 +255,21 @@ static void dump_trunk(struct vty *vty, struct mgcp_trunk_config *cfg, int show_
return;
}
for (i = 1; i < cfg->number_endpoints; ++i) {
for (i = 0; i < cfg->number_endpoints; ++i) {
struct mgcp_endpoint *endp = &cfg->endpoints[i];
dump_endpoint(vty, endp, i, cfg->trunk_nr, cfg->trunk_type, show_stats);
if (i < cfg->number_endpoints - 1)
vty_out(vty, "%s", VTY_NEWLINE);
}
if (show_stats) {
vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, "Rate counters:%s", VTY_NEWLINE);
}
if (show_stats && cfg->mgcp_general_ctr_group) {
vty_out(vty, " %s:%s", cfg->mgcp_general_ctr_group->desc->group_description, VTY_NEWLINE);
vty_out_rate_ctr_group_fmt(vty, " %25n: %10c (%S/s %M/m %H/h %D/d) %d", cfg->mgcp_general_ctr_group);
}
if (show_stats && cfg->mgcp_crcx_ctr_group) {
vty_out(vty, " %s:%s", cfg->mgcp_crcx_ctr_group->desc->group_description, VTY_NEWLINE);
vty_out_rate_ctr_group_fmt(vty, " %25n: %10c (%S/s %M/m %H/h %D/d) %d", cfg->mgcp_crcx_ctr_group);

View File

@@ -9,6 +9,7 @@ AM_CFLAGS = \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -26,5 +27,6 @@ osmo_mgw_LDADD = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(NULL)

View File

@@ -38,6 +38,7 @@
#include <osmocom/mgcp/vty.h>
#include <osmocom/mgcp/debug.h>
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_ctrl.h>
#include <osmocom/core/application.h>
#include <osmocom/core/msgb.h>
@@ -48,6 +49,8 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/socket.h>
#include <osmocom/ctrl/control_vty.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/ports.h>
@@ -60,6 +63,11 @@
#define _GNU_SOURCE
#include <getopt.h>
/* can be changed once libosmocore 1.4.0 is released */
#ifndef OSMO_CTRL_PORT_MGW
#define OSMO_CTRL_PORT_MGW 4267
#endif
/* FIXME: Make use of the rtp proxy code */
static struct mgcp_config *cfg;
@@ -248,12 +256,6 @@ static const struct log_info_cat log_categories[] = {
.color = "\033[1;30m",
.enabled = 1,.loglevel = LOGL_NOTICE,
},
[DIUUP] = {
.name = "DIUUP",
.description = "IuUP within RTP stream handling",
.color = "\033[1;31m",
.enabled = 1,.loglevel = LOGL_NOTICE,
},
};
const struct log_info log_info = {
@@ -284,6 +286,7 @@ int main(int argc, char **argv)
osmo_talloc_vty_add_cmds();
osmo_stats_vty_add_cmds();
mgcp_vty_init();
ctrl_vty_init(cfg);
handle_options(argc, argv);
@@ -300,6 +303,12 @@ int main(int argc, char **argv)
if (rc < 0)
return rc;
cfg->ctrl = mgw_ctrl_interface_setup(cfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
if (!cfg->ctrl) {
fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
}
/* Set the reset callback function. This functions is called when the
* mgcp-command "RSIP" (Reset in Progress) is received */
cfg->reset_cb = mgcp_rsip_cb;

View File

@@ -1,7 +1,6 @@
SUBDIRS = \
mgcp_client \
mgcp \
iuup \
$(NULL)
# The `:;' works around a Bash 3.2 bug when the output is not writeable.

View File

@@ -1,45 +0,0 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
-I$(top_srcdir) \
$(NULL)
AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
$(COVERAGE_LDFLAGS) \
$(NULL)
EXTRA_DIST = \
iuup_test.ok \
iuup_test.err \
$(NULL)
noinst_PROGRAMS = \
iuup_test \
$(NULL)
iuup_test_SOURCES = \
iuup_test.c \
$(NULL)
iuup_test_LDADD = \
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBRARY_DL) \
$(LIBOSMONETIF_LIBS) \
-lm \
$(NULL)
update_exp:
$(builddir)/iuup_test >$(srcdir)/iuup_test.ok 2>$(srcdir)/iuup_test.err

View File

@@ -1,156 +0,0 @@
#include <stdint.h>
#include <string.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/application.h>
#include <osmocom/core/logging.h>
#include <osmocom/mgcp/iuup_cn_node.h>
#include <osmocom/mgcp/iuup_protocol.h>
void *ctx = NULL;
static const char *dump(struct msgb *msg)
{
return osmo_hexdump_nospc(msg->data, msg->len);
}
struct msgb *msgb_from_hex(const char *label, const char *hex)
{
struct msgb *msg = msgb_alloc_headroom(4096 + OSMO_IUUP_HEADROOM,
OSMO_IUUP_HEADROOM, label);
unsigned char *rc;
msg->l2h = msg->data;
rc = msgb_put(msg, osmo_hexparse(hex, msg->data, msgb_tailroom(msg)));
OSMO_ASSERT(rc == msg->l2h);
return msg;
}
const char *expect_rx_payload = NULL;
int rx_payload(struct msgb *msg, void *node_priv)
{
printf("rx_payload() invoked by iuup_cn!\n");
printf(" [IuUP] -RTP->\n");
printf("%s\n", dump(msg));
printf("node_priv=%p\n", node_priv);
if (!expect_rx_payload) {
printf("ERROR: did not expect rx_payload()\n");
exit(-1);
} else if (strcmp(expect_rx_payload, dump(msg))) {
printf("ERROR: mismatches expected msg %s\n", expect_rx_payload);
exit(-1);
} else
printf("ok: matches expected msg\n");
expect_rx_payload = NULL;
return 0;
}
const char *expect_tx_msg = NULL;
int tx_msg(struct msgb *msg, void *node_priv)
{
printf("tx_msg() invoked by iuup_cn!\n");
printf(" <-PDU- [IuUP]\n");
printf("%s\n", dump(msg));
printf("node_priv=%p\n", node_priv);
if (!expect_tx_msg) {
printf("ERROR: did not expect tx_msg()\n");
exit(-1);
} else if (strcmp(expect_tx_msg, dump(msg))) {
printf("ERROR: mismatches expected msg %s\n", expect_tx_msg);
exit(-1);
} else
printf("ok: matches expected msg\n");
expect_tx_msg = NULL;
return 0;
}
static int rx_pdu(struct osmo_iuup_cn *cn, struct msgb *msg)
{
int rc;
printf(" -PDU-> [IuUP]\n");
printf("%s\n", dump(msg));
rc = osmo_iuup_cn_rx_pdu(cn, msg);
printf("rc=%d\n", rc);
return rc;
}
static int tx_payload(struct osmo_iuup_cn *cn, struct msgb *msg)
{
int rc;
printf(" [IuUP] <-RTP-\n");
printf("%s\n", dump(msg));
rc = osmo_iuup_cn_tx_payload(cn, msg);
printf("rc=%d\n", rc);
return rc;
}
void test_cn_session()
{
void *node_priv = (void*)0x2342;
struct osmo_iuup_cn_cfg cfg = {
.node_priv = node_priv,
.rx_payload = rx_payload,
.tx_msg = tx_msg,
};
struct osmo_iuup_cn *cn = osmo_iuup_cn_init(ctx, &cfg, __func__);
OSMO_ASSERT(cn);
printf("\nSend IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack\n");
expect_tx_msg = "8060dc5219495e3f00010111" /* RTP header */
"e4002400"; /* IuUP Init Ack */
rx_pdu(cn,
msgb_from_hex("IuUP-Init",
"8060dc5219495e3f00010111" /* <- RTP header */
"e000df99" /* <- IuUP header */
"160051673c01270000820000001710000100" /* IuUP params */));
#define RTP_HEADER "8060944c6256042c00010102"
#define IUUP_HEADER "0100e2b3"
#define RTP_PAYLOAD "6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0"
printf("\nReceive payload encapsulated in IuUP. Expecting rx_payload() of just RTP packet\n");
printf("i.e. should strip away " IUUP_HEADER "\n");
expect_rx_payload = RTP_HEADER "f03c" RTP_PAYLOAD;
rx_pdu(cn,
msgb_from_hex("IuUP-Data",
RTP_HEADER IUUP_HEADER RTP_PAYLOAD));
printf("\nTransmit RTP. Expecting tx_msg() with inserted IuUP header\n");
expect_tx_msg = RTP_HEADER "000002b3" RTP_PAYLOAD;
tx_payload(cn,
msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
printf("\nMore RTP, each time the Frame Nr advances, causing a new header CRC.\n");
expect_tx_msg = RTP_HEADER "0100e2b3" RTP_PAYLOAD;
tx_payload(cn,
msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
expect_tx_msg = RTP_HEADER "02007eb3" RTP_PAYLOAD;
tx_payload(cn,
msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
expect_tx_msg = RTP_HEADER "03009eb3" RTP_PAYLOAD;
tx_payload(cn,
msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
printf("All done.\n");
}
static const struct log_info_cat log_categories[] = {
};
const struct log_info log_info = {
.cat = log_categories,
.num_cat = ARRAY_SIZE(log_categories),
};
int main(void)
{
ctx = talloc_named_const(NULL, 0, __FILE__);
void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
osmo_init_logging2(ctx, &log_info);
test_cn_session();
talloc_free(msgb_ctx);
return 0;
}

View File

@@ -1,58 +0,0 @@
Send IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack
-PDU-> [IuUP]
8060dc5219495e3f00010111e000df99160051673c01270000820000001710000100
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
8060dc5219495e3f00010111e4002400
node_priv=0x2342
ok: matches expected msg
rc=0
Receive payload encapsulated in IuUP. Expecting rx_payload() of just RTP packet
i.e. should strip away 0100e2b3
-PDU-> [IuUP]
8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
rx_payload() invoked by iuup_cn!
[IuUP] -RTP->
8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
node_priv=0x2342
ok: matches expected msg
rc=0
Transmit RTP. Expecting tx_msg() with inserted IuUP header
[IuUP] <-RTP-
8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
8060944c6256042c00010102000002b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
node_priv=0x2342
ok: matches expected msg
rc=0
More RTP, each time the Frame Nr advances, causing a new header CRC.
[IuUP] <-RTP-
8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
node_priv=0x2342
ok: matches expected msg
rc=0
[IuUP] <-RTP-
8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
8060944c6256042c0001010202007eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
node_priv=0x2342
ok: matches expected msg
rc=0
[IuUP] <-RTP-
8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
8060944c6256042c0001010203009eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
node_priv=0x2342
ok: matches expected msg
rc=0
All done.

View File

@@ -36,6 +36,7 @@ mgcp_test_LDADD = \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBRARY_DL) \
$(LIBRARY_DLSYM) \
$(LIBOSMONETIF_LIBS) \
-lm \
$(NULL)

View File

@@ -28,7 +28,6 @@
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_sdp.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
@@ -1257,7 +1256,7 @@ struct rtp_packet_info test_rtp_packets1[] = {
void mgcp_patch_and_count(struct mgcp_endpoint *endp,
struct mgcp_rtp_state *state,
struct mgcp_rtp_end *rtp_end,
struct sockaddr_in *addr, struct msgb *msg);
struct sockaddr_in *addr, char *data, int len);
static void test_packet_error_detection(int patch_ssrc, int patch_ts)
{
@@ -1269,6 +1268,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
struct mgcp_rtp_state state;
struct mgcp_rtp_end *rtp;
struct sockaddr_in addr = { 0 };
char buffer[4096];
uint32_t last_ssrc = 0;
uint32_t last_timestamp = 0;
uint32_t last_seqno = 0;
@@ -1316,17 +1316,16 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
struct rtp_packet_info *info = test_rtp_packets1 + i;
struct msgb *msg = msgb_alloc(4096, __func__);
force_monotonic_time_us = round(1000000.0 * info->txtime);
OSMO_ASSERT(info->len <= msgb_tailroom(msg));
OSMO_ASSERT(info->len <= sizeof(buffer));
OSMO_ASSERT(info->len >= 0);
msg->l3h = msgb_put(msg, info->len);
memcpy((char*)msgb_l3(msg), info->data, info->len);
memmove(buffer, info->data, info->len);
mgcp_rtp_end_config(&endp, 1, rtp);
mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
mgcp_patch_and_count(&endp, &state, rtp, &addr,
buffer, info->len);
if (state.out_stream.ssrc != last_ssrc) {
printf("Output SSRC changed to %08x\n",
@@ -1353,8 +1352,6 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
last_timestamp = state.out_stream.last_timestamp;
last_seqno = state.out_stream.last_seq;
msgb_free(msg);
}
force_monotonic_time_us = -1;

View File

@@ -35,6 +35,7 @@ mgcp_client_test_LDADD = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBRARY_DL) \
$(LIBRARY_DLSYM) \
$(LIBOSMONETIF_LIBS) \
$(NULL)

View File

@@ -13,10 +13,3 @@ AT_KEYWORDS([mgcp])
cat $abs_srcdir/mgcp/mgcp_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_test], [], [expout], [ignore])
AT_CLEANUP
AT_SETUP([iuup])
AT_KEYWORDS([iuup])
cat $abs_srcdir/iuup/iuup_test.ok > expout
cat $abs_srcdir/iuup/iuup_test.err > experr
AT_CHECK([$abs_top_builddir/tests/iuup/iuup_test], [], [expout], [experr])
AT_CLEANUP