This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
laforge gerrit-no-reply at lists.osmocom.orglaforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-mgw/+/19524 ) Change subject: mgcp_e1: finish E1 support, add E1 support from libosmoabis ...................................................................... mgcp_e1: finish E1 support, add E1 support from libosmoabis Currently only the endpoint handling for E1 exists, but there is no actual code behind it that handles the E1 traffic. Change-Id: I6b93809b5ac7d01af55888347dd787b0bc997ae1 Related: OS#2659 --- M configure.ac M include/osmocom/mgcp/Makefile.am M include/osmocom/mgcp/debug.h M include/osmocom/mgcp/mgcp_conn.h A include/osmocom/mgcp/mgcp_e1.h M include/osmocom/mgcp/mgcp_endp.h M include/osmocom/mgcp/mgcp_internal.h M include/osmocom/mgcp/mgcp_ratectr.h M include/osmocom/mgcp/mgcp_trunk.h M src/libosmo-mgcp/Makefile.am M src/libosmo-mgcp/mgcp_conn.c A src/libosmo-mgcp/mgcp_e1.c M src/libosmo-mgcp/mgcp_endp.c M src/libosmo-mgcp/mgcp_network.c M src/libosmo-mgcp/mgcp_protocol.c M src/libosmo-mgcp/mgcp_ratectr.c M src/libosmo-mgcp/mgcp_trunk.c M src/libosmo-mgcp/mgcp_vty.c M src/osmo-mgw/Makefile.am M src/osmo-mgw/mgw_main.c M tests/mgcp/Makefile.am M tests/mgcp/mgcp_test.c 22 files changed, 1,076 insertions(+), 62 deletions(-) Approvals: Jenkins Builder: Verified laforge: Looks good to me, approved diff --git a/configure.ac b/configure.ac index 7c63437..db44893 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,8 @@ 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) +PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0) +PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 0.6.0) AC_ARG_ENABLE(sanitize, [AS_HELP_STRING( diff --git a/include/osmocom/mgcp/Makefile.am b/include/osmocom/mgcp/Makefile.am index fb7654f..549ba87 100644 --- a/include/osmocom/mgcp/Makefile.am +++ b/include/osmocom/mgcp/Makefile.am @@ -10,4 +10,5 @@ mgcp_trunk.h \ debug.h \ mgcp_ratectr.h \ + mgcp_e1.h \ $(NULL) diff --git a/include/osmocom/mgcp/debug.h b/include/osmocom/mgcp/debug.h index ddeb0dc..7044c1e 100644 --- a/include/osmocom/mgcp/debug.h +++ b/include/osmocom/mgcp/debug.h @@ -29,6 +29,7 @@ /* Debug Areas of the code */ enum { DRTP, + DE1, Debug_LastEntry, }; diff --git a/include/osmocom/mgcp/mgcp_conn.h b/include/osmocom/mgcp/mgcp_conn.h index ff5a779..78d5ea8 100644 --- a/include/osmocom/mgcp/mgcp_conn.h +++ b/include/osmocom/mgcp/mgcp_conn.h @@ -124,3 +124,4 @@ void mgcp_conn_free_all(struct mgcp_endpoint *endp); char *mgcp_conn_dump(struct mgcp_conn *conn); struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn); +struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp); diff --git a/include/osmocom/mgcp/mgcp_e1.h b/include/osmocom/mgcp/mgcp_e1.h new file mode 100644 index 0000000..a4ae854 --- /dev/null +++ b/include/osmocom/mgcp/mgcp_e1.h @@ -0,0 +1,28 @@ +#pragma once + +/* A 64k timeslot on an E1 line can be subdevied into the following + * subslot combinations: + * + * subslot: offset: + * [ ][ ][ 16k ][8k_subslot] 0 + * [ ][ 32k ][_subslot__][8k_subslot] 1 + * [ ][ subslot ][ 16k ][8k_subslot] 2 + * [ 64k ][__________][_subslot__][8k_subslot] 3 + * [ timeslot ][ ][ 16k ][8k_subslot] 4 + * [ ][ 32K ][_subslot__][8k_subslot] 5 + * [ ][ subslot ][ 16k ][8k_subslot] 6 + * [ ][ ][ subslot ][8k_subslot] 7 + * + * Since overlapping assignment of subslots is not possible there is a limited + * set of subslot assignments possible. The e1_rates array lists the possible + * assignments as depicted above. Also each subslot assignment comes along with + * a bit offset in the E1 bitstream. The e1_offsets arrays lists the bit + * offsets. */ +static const uint8_t e1_rates[] = { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 }; +static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 }; + +int mgcp_e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr); +int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs); +void mgcp_e1_endp_update(struct mgcp_endpoint *endp); +void mgcp_e1_endp_release(struct mgcp_endpoint *endp); +int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg); diff --git a/include/osmocom/mgcp/mgcp_endp.h b/include/osmocom/mgcp/mgcp_endp.h index c16ea4b..065494f 100644 --- a/include/osmocom/mgcp/mgcp_endp.h +++ b/include/osmocom/mgcp/mgcp_endp.h @@ -24,6 +24,7 @@ #pragma once #include <osmocom/core/msgb.h> +#include <osmocom/gsm/i460_mux.h> struct sockaddr_in; struct mgcp_conn; @@ -116,10 +117,23 @@ /*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */ uint32_t x_osmo_ign; + + /* E1 specific */ + struct { + struct osmo_i460_schan_desc scd; + struct osmo_i460_subchan *schan; + struct osmo_fsm_inst *trau_sync_fi; + struct osmo_trau2rtp_state *trau_rtp_st; + uint8_t last_amr_ft; + struct mgcp_rtp_codec *last_codec; + } e1; + }; struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index); void mgcp_endp_release(struct mgcp_endpoint *endp); +int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid); +void mgcp_endp_update(struct mgcp_endpoint *endp); struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname, const struct mgcp_trunk *trunk); struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname, diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h index 3d7224e..86b2a57 100644 --- a/include/osmocom/mgcp/mgcp_internal.h +++ b/include/osmocom/mgcp/mgcp_internal.h @@ -71,6 +71,10 @@ /* duration of a packet (FIXME: in which unit?) */ uint32_t packet_duration; + /* Note: These states are not continuously updated, they serve as an + * information source to patch certain values in the RTP header. Do + * not use this state if constantly updated data about the RTP stream + * is needed. (see also mgcp_patch_and_count() */ struct mgcp_rtp_stream_state in_stream; struct mgcp_rtp_stream_state out_stream; @@ -85,6 +89,13 @@ int cycles; } stats; + /* Alternative values for RTP tx, in case no sufficient header + * information is available so the header needs to be generated + * locally (when just forwarding packets, the header of incoming + * data is just re-used) */ + uint16_t alt_rtp_tx_sequence; + uint32_t alt_rtp_tx_ssrc; + bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */ }; @@ -296,3 +307,5 @@ struct mgcp_rtp_state *state, struct mgcp_rtp_end *rtp_end, struct sockaddr_in *addr, struct msgb *msg); + +#define RTP_BUF_SIZE 4096 diff --git a/include/osmocom/mgcp/mgcp_ratectr.h b/include/osmocom/mgcp/mgcp_ratectr.h index d0bc628..ff59ea4 100644 --- a/include/osmocom/mgcp/mgcp_ratectr.h +++ b/include/osmocom/mgcp/mgcp_ratectr.h @@ -29,6 +29,7 @@ MGCP_CRCX_FAIL_CODEC_NEGOTIATION, MGCP_CRCX_FAIL_BIND_PORT, MGCP_CRCX_FAIL_AVAIL, + MGCP_CRCX_FAIL_CLAIM, }; /* Global MCGP MDCX related rate counters */ @@ -63,6 +64,13 @@ MGCP_DLCX_FAIL_AVAIL, }; +/* Trunk-global E1 related counters */ +enum { + E1_I460_TRAU_RX_FAIL_CTR, + E1_I460_TRAU_TX_FAIL_CTR, + E1_I460_TRAU_MUX_EMPTY_CTR, +}; + /* NOTE: When adding counters, also the dump_ratectr_* routines in vty.c must be updated. */ struct mgcp_ratectr_global { @@ -79,6 +87,8 @@ struct rate_ctr_group *mgcp_dlcx_ctr_group; /* Rate counter group which aggregates stats of individual RTP connections. */ struct rate_ctr_group *all_rtp_conn_stats; + /* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */ + struct rate_ctr_group *e1_stats; }; int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr); diff --git a/include/osmocom/mgcp/mgcp_trunk.h b/include/osmocom/mgcp/mgcp_trunk.h index aa6dd29..d99f801 100644 --- a/include/osmocom/mgcp/mgcp_trunk.h +++ b/include/osmocom/mgcp/mgcp_trunk.h @@ -1,5 +1,13 @@ #pragma once +#include <osmocom/gsm/i460_mux.h> + +#define LOGPTRUNK(trunk, cat, level, fmt, args...) \ +LOGP(cat, level, "trunk:%u " fmt, \ + trunk ? trunk->trunk_nr : 0, \ + ## args) + + enum mgcp_trunk_type { MGCP_TRUNK_VIRTUAL, MGCP_TRUNK_E1, @@ -39,18 +47,32 @@ int rtp_accept_all; unsigned int number_endpoints; - unsigned int vty_number_endpoints; struct mgcp_endpoint **endpoints; /* global rate counters to measure the trunks overall performance and health */ struct mgcp_ratectr_trunk ratectr; + + union { + /* Virtual trunk specific */ + struct { + unsigned int vty_number_endpoints; + } v; + /* E1 specific */ + struct { + unsigned int vty_line_nr; + struct e1inp_line *line; + bool ts_in_use[31]; + struct osmo_i460_timeslot i460_ts[31]; + } e1; + }; }; struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr); -int mgcp_trunk_alloc_endpts(struct mgcp_trunk *tcfg); +int mgcp_trunk_equip(struct mgcp_trunk *trunk); struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr); struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname); int e1_trunk_nr_from_epname(const char *epname); +struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num); /* The virtual trunk is always created on trunk id 0 for historical reasons, * use this define constant as ID when allocating a virtual trunk. Other diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am index 77d0cdf..91b2bf6 100644 --- a/src/libosmo-mgcp/Makefile.am +++ b/src/libosmo-mgcp/Makefile.am @@ -10,6 +10,8 @@ $(LIBOSMOGSM_CFLAGS) \ $(LIBOSMOVTY_CFLAGS) \ $(LIBOSMONETIF_CFLAGS) \ + $(LIBOSMOABIS_CFLAGS) \ + $(LIBOSMOTRAU_CFLAGS) \ $(COVERAGE_CFLAGS) \ $(NULL) @@ -18,6 +20,8 @@ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOVTY_LIBS) \ $(LIBOSMONETIF_LIBS) \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOTRAU_LIBS) \ $(COVERAGE_LDFLAGS) \ $(NULL) @@ -43,4 +47,5 @@ mgcp_trunk.c \ mgcp_ctrl.c \ mgcp_ratectr.c \ + mgcp_e1.c \ $(NULL) diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c index 6802b91..8c7918e 100644 --- a/src/libosmo-mgcp/mgcp_conn.c +++ b/src/libosmo-mgcp/mgcp_conn.c @@ -397,3 +397,13 @@ return NULL; } + +/*! get oldest connection in the list. + * \param[in] endp associated endpoint */ +struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp) +{ + if (llist_empty(&endp->conns)) + return NULL; + + return llist_last_entry(&endp->conns, struct mgcp_conn, entry); +} diff --git a/src/libosmo-mgcp/mgcp_e1.c b/src/libosmo-mgcp/mgcp_e1.c new file mode 100644 index 0000000..1e227dc --- /dev/null +++ b/src/libosmo-mgcp/mgcp_e1.c @@ -0,0 +1,687 @@ +/* E1 traffic handling */ + +/* + * (C) 2020 by sysmocom s.f.m.c. GmbH <info at 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 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/mgcp/mgcp_internal.h> +#include <osmocom/mgcp/mgcp_endp.h> +#include <osmocom/mgcp/mgcp_trunk.h> +#include <osmocom/mgcp/mgcp_conn.h> +#include <osmocom/core/msgb.h> +#include <osmocom/abis/e1_input.h> +#include <osmocom/abis/abis.h> + +#include <osmocom/trau/trau_sync.h> +#include <osmocom/trau/trau_frame.h> +#include <osmocom/trau/trau_rtp.h> +#include <osmocom/mgcp/mgcp_conn.h> +#include <osmocom/netif/rtp.h> +#include <osmocom/mgcp/debug.h> +#include <osmocom/mgcp/mgcp_e1.h> +#include <osmocom/codec/codec.h> + +#define DEBUG_BITS_MAX 80 +#define DEBUG_BYTES_MAX 40 +#define DEBUG_E1_TS 0 +#define E1_TS_BYTES 160 +#define E1_TRAU_BITS 320 +#define E1_TRAU_BITS_MSGB 2048 + +static struct mgcp_config *cfg; + +static const struct e1inp_line_ops dummy_e1_line_ops = { + .sign_link_up = NULL, + .sign_link_down = NULL, + .sign_link = NULL, +}; + +/* EFR idle frame */ +static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, +}; + +/* FR idle frame */ +static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, +}; + +/* Idle speech frame, see also GSM 08.60, chapter 3.4 */ +static const ubit_t idle_tf_spch[] = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, +}; + +/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may + * run empty. In order to make sure that the TRAU frame transmission continues + * we generate idle TRAU frames here. */ +static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_data) +{ + struct mgcp_endpoint *endp = user_data; + struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats; + struct msgb *msg = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame"); + uint8_t *ptr; + const uint8_t *ptr_ft; + enum osmo_trau_frame_type ft; + + rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_MUX_EMPTY_CTR]); + + /* Choose an appropiate idle frame type */ + ft = endp->e1.trau_rtp_st->type; + switch (ft) { + case OSMO_TRAU16_FT_FR: + ptr_ft = idle_tf_fr; + break; + case OSMO_TRAU16_FT_EFR: + ptr_ft = idle_tf_efr; + break; + default: + /* FIXME: What about 8k subslots and AMR frames? */ + ptr_ft = idle_tf_spch; + } + + /* Put the replacement into a message buffer and enqueue it into the + * I.460 multiplexer */ + ptr = msgb_put(msg, E1_TRAU_BITS); + memcpy(ptr, ptr_ft, E1_TRAU_BITS); + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-IDLE-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg), + osmo_ubit_dump(msgb_data(msg), msgb_length(msg) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg))); + osmo_i460_mux_enqueue(endp->e1.schan, msg); +} + +/* called by I.460 de-multeiplexer; feed output of I.460 demux into TRAU frame sync */ +static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits, + unsigned int num_bits) +{ + struct mgcp_endpoint *endp = user_data; + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: receiving %u bits from subslot: %s...\n", num_bits, + osmo_ubit_dump(bits, num_bits > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : num_bits)); + + OSMO_ASSERT(endp->e1.trau_sync_fi); + osmo_trau_sync_rx_ubits(endp->e1.trau_sync_fi, bits, num_bits); +} + +/* called for each synchronized TRAU frame received; decode frame + convert to RTP + * (the resulting frame will be prepended with an all-zero (12-byte) rtp header) */ +static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int num_bits) +{ + struct msgb *msg = msgb_alloc(RTP_BUF_SIZE, "RTP-rx-from-E1"); + unsigned int rtp_hdr_len = sizeof(struct rtp_hdr); + struct mgcp_endpoint *endp = user_data; + struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats; + struct mgcp_conn *conn_dst; + struct osmo_trau_frame fr; + int rc; + + if (!bits || num_bits == 0) + goto skip; + + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: receiving %u TRAU frame bits from E1 subslot: %s...\n", + num_bits, osmo_ubit_dump(bits, num_bits > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : num_bits)); + + /* Decode TRAU frame */ + switch (endp->e1.scd.rate) { + case OSMO_I460_RATE_8k: + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoding 8k trau frame...\n"); + rc = osmo_trau_frame_decode_8k(&fr, bits, OSMO_TRAU_DIR_UL); + break; + case OSMO_I460_RATE_16k: + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoding 16k trau frame...\n"); + rc = osmo_trau_frame_decode_16k(&fr, bits, OSMO_TRAU_DIR_UL); + break; + default: + /* TRAU frames only exist in 8K or 16K subslots. */ + OSMO_ASSERT(false); + break; + } + if (rc != 0) { + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: unable to decode trau frame\n"); + goto skip; + } + + /* Check if the payload type is supported and what the expected lenth + * of the RTP payload will be. */ + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoded trau frame type: %s\n", + osmo_trau_frame_type_name(fr.type)); + + /* Convert decoded trau frame to RTP frame */ + struct osmo_trau2rtp_state t2rs = { + .type = fr.type, + }; + rc = osmo_trau2rtp(msgb_data(msg) + rtp_hdr_len, msg->data_len - rtp_hdr_len, &fr, &t2rs); + if (rc <= 0) { + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: unable to convert trau frame to RTP audio\n"); + goto skip; + } + msgb_put(msg, rtp_hdr_len + rc); + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: encoded %u bytes of RTP audio: %s\n", rc, + osmo_hexdump(msgb_data(msg) + rtp_hdr_len, msgb_length(msg) - rtp_hdr_len)); + + /* Forward RTP data to IP */ + conn_dst = llist_first_entry(&endp->conns, struct mgcp_conn, entry); + if (!conn_dst) { + LOGPENDP(endp, DE1, LOGL_DEBUG, + "E1-I.460-RX: unable to forward RTP audio data from E1: no connection to forward an incoming RTP packet to\n"); + goto skip; + } + OSMO_ASSERT(conn_dst->type == MGCP_CONN_TYPE_RTP); + + mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp); + + msgb_free(msg); + return; +skip: + rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_RX_FAIL_CTR]); + msgb_free(msg); + return; +} + +/* Function to handle outgoing E1 traffic */ +static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk) +{ + struct msgb *msg = msgb_alloc(E1_TS_BYTES, "E1-TX-timeslot-bytes"); + uint8_t *ptr; + + /* Get E1 frame from I.460 multiplexer */ + ptr = msgb_put(msg, E1_TS_BYTES); + osmo_i460_mux_out(&trunk->e1.i460_ts[ts->num - 1], ptr, E1_TS_BYTES); + +#if DEBUG_E1_TS == 1 + LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1-TX: (ts:%u) sending %u bytes: %s...\n", ts->num, msgb_length(msg), + osmo_hexdump_nospc(msgb_data(msg), + msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg))); +#endif + /* Hand data over to the E1 stack */ + msgb_enqueue(&ts->raw.tx_queue, msg); + return; +} + +/* Callback function to handle incoming E1 traffic */ +static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg) +{ + struct mgcp_trunk *trunk; + + /* Find associated trunk */ + trunk = mgcp_trunk_by_line_num(cfg, ts->line->num); + if (!trunk) { + LOGP(DE1, LOGL_DEBUG, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num); + return; + } + + /* Check if the incoming data looks sane */ + if (msgb_length(msg) != E1_TS_BYTES) { + LOGPTRUNK(trunk, DE1, LOGL_NOTICE, + "E1-RX: (ts:%u) expected length is %u, actual length is %u!\n", ts->num, E1_TS_BYTES, + msgb_length(msg)); + } +#if DEBUG_E1_TS == 1 + LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1-RX: (ts:%u) receiving %u bytes: %s...\n", ts->num, + msgb_length(msg), osmo_hexdump_nospc(msgb_data(msg), + msgb_length(msg) > + DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg))); +#endif + + /* Hand data over to the I.460 demultiplexer. */ + osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg)); + + /* Trigger sending of pending E1 traffic */ + e1_send(ts, trunk); +} + +/*! Find an endpoint by its name on a specified trunk. + * \param[in] trunk trunk configuration. + * \param[in] ts_nr E1 timeslot number. + * \returns -EINVAL on failure, 0 on success. */ +int mgcp_e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr) +{ + /*! Each timeslot needs only to be configured once. The Timeslot then + * stays open and permanently receives data. It is then up to the + * I.460 demultiplexer to add/remove subchannels as needed. It is + * allowed to call this function multiple times since we check if the + * timeslot is already configured. */ + + struct e1inp_line *e1_line; + int rc; + + OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS); + cfg = trunk->cfg; + + if (trunk->e1.ts_in_use[ts_nr - 1]) { + LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u already set up, skipping...\n", ts_nr); + return 0; + } + + /* Get E1 line */ + if (!trunk->e1.line) { + e1_line = e1inp_line_find(trunk->e1.vty_line_nr); + if (!e1_line) { + LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "no such E1 line %u - check VTY config!\n", + trunk->e1.vty_line_nr); + return -EINVAL; + } + e1inp_line_bind_ops(e1_line, &dummy_e1_line_ops); + } else + e1_line = trunk->e1.line; + if (!e1_line) + return -EINVAL; + + /* Configure E1 timeslot */ + rc = e1inp_ts_config_raw(&e1_line->ts[ts_nr - 1], e1_line, e1_recv_cb); + if (rc < 0) + return -EINVAL; + e1inp_line_update(e1_line); + if (rc < 0) + return -EINVAL; + + LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u set up successfully.\n", ts_nr); + trunk->e1.ts_in_use[ts_nr - 1] = true; + + return 0; +} + +/* Determine a suitable TRAU frame type for a given codec */ +static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name, enum osmo_i460_rate i460_rate, + uint8_t amr_ft, struct mgcp_endpoint *endp) +{ + if (strcmp(sdp_subtype_name, "GSM") == 0) + return OSMO_TRAU16_FT_FR; + else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0) + return OSMO_TRAU16_FT_EFR; + else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) + return OSMO_TRAU16_FT_HR; + else if (strcmp(sdp_subtype_name, "AMR") == 0) { + if (i460_rate == OSMO_I460_RATE_8k) { + switch (amr_ft) { + case AMR_4_75: + case AMR_5_15: + case AMR_5_90: + return OSMO_TRAU8_AMR_LOW; + case AMR_6_70: + return OSMO_TRAU8_AMR_6k7; + case AMR_7_40: + return OSMO_TRAU8_AMR_7k4; + default: + LOGPENDP(endp, DE1, LOGL_ERROR, + "E1-TRAU-TX: unsupported or illegal AMR frame type: %u\n", amr_ft); + return OSMO_TRAU_FT_NONE; + } + } + return OSMO_TRAU16_FT_AMR; + } else { + LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n", + sdp_subtype_name); + return OSMO_TRAU_FT_NONE; + } +} + +/* Determine a suitable TRAU frame type for a given codec */ +static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name, enum osmo_i460_rate i460_rate, + uint8_t amr_ft, struct mgcp_endpoint *endp) +{ + if (strcmp(sdp_subtype_name, "GSM") == 0) + return OSMO_TRAU_SYNCP_16_FR_EFR; + else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0) + return OSMO_TRAU_SYNCP_16_FR_EFR; + else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) + return OSMO_TRAU_SYNCP_8_HR; + else if (strcmp(sdp_subtype_name, "AMR") == 0) { + if (i460_rate == OSMO_I460_RATE_8k) { + switch (amr_ft) { + case AMR_4_75: + case AMR_5_15: + case AMR_5_90: + return OSMO_TRAU_SYNCP_8_AMR_LOW; + case AMR_6_70: + return OSMO_TRAU_SYNCP_8_AMR_6K7; + case AMR_7_40: + return OSMO_TRAU_SYNCP_8_AMR_7K4; + default: + LOGPENDP(endp, DE1, LOGL_ERROR, + "E1-TRAU-TX: unsupported or illegal AMR frame type: %u\n", amr_ft); + return OSMO_TRAU_SYNCP_16_FR_EFR; + } + } + return OSMO_TRAU_SYNCP_16_FR_EFR; + } else { + LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n", + sdp_subtype_name); + return OSMO_TRAU_SYNCP_16_FR_EFR; + } +} + +/* Find out if a given TRAU frame type is AMR */ +static bool tf_type_is_amr(enum osmo_trau_frame_type ft) +{ + + switch (ft) { + case OSMO_TRAU16_FT_AMR: + case OSMO_TRAU8_AMR_LOW: + case OSMO_TRAU8_AMR_6k7: + case OSMO_TRAU8_AMR_7k4: + return true; + default: + return false; + } +} + +/* !Equip E1 endpoint with I.460 mux resources. + * \param[in] endp endpoint to equip + * \param[in] ts E1 timeslot number. + * \param[in] ss E1 subslot number. + * \param[in] offset E1 bit offset. + * \returns 0 on success, -EINVAL on error. */ +int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs) +{ + int rc; + enum osmo_tray_sync_pat_id sync_pat_id = OSMO_TRAU_SYNCP_16_FR_EFR; + + OSMO_ASSERT(ts != 0); + OSMO_ASSERT(ts != 0xFF); + OSMO_ASSERT(ss != 0xFF); + OSMO_ASSERT(offs != 0xFF); + + memset(&endp->e1, 0, sizeof(endp->e1)); + + endp->e1.last_amr_ft = AMR_4_75; + + /* Set up E1 line / timeslot */ + rc = mgcp_e1_init(endp->trunk, ts); + if (rc != 0) + return -EINVAL; + + /* Set up I.460 mux */ + switch (e1_rates[ss]) { + case 64: + endp->e1.scd.rate = OSMO_I460_RATE_64k; + endp->e1.scd.demux.num_bits = 160 * 8; + break; + case 32: + endp->e1.scd.rate = OSMO_I460_RATE_32k; + endp->e1.scd.demux.num_bits = 80 * 8; + break; + case 16: + endp->e1.scd.rate = OSMO_I460_RATE_16k; + endp->e1.scd.demux.num_bits = 40 * 8; + sync_pat_id = OSMO_TRAU_SYNCP_16_FR_EFR; + break; + case 8: + endp->e1.scd.rate = OSMO_I460_RATE_8k; + endp->e1.scd.demux.num_bits = 20 * 8; + sync_pat_id = OSMO_TRAU_SYNCP_8_HR; + break; + } + endp->e1.scd.bit_offset = offs; + endp->e1.scd.demux.out_cb_bits = e1_i460_demux_bits_cb; + endp->e1.scd.demux.out_cb_bytes = NULL; + endp->e1.scd.demux.user_data = endp; + endp->e1.scd.mux.in_cb_queue_empty = e1_i460_mux_empty_cb; + endp->e1.scd.mux.user_data = endp; + + LOGPENDP(endp, DE1, LOGL_DEBUG, "adding I.460 subchannel: ts=%u, bit_offset=%u, rate=%uk, num_bits=%lu\n", ts, + offs, e1_rates[ss], endp->e1.scd.demux.num_bits); + endp->e1.schan = osmo_i460_subchan_add(endp, &endp->trunk->e1.i460_ts[ts - 1], &endp->e1.scd); + if (!endp->e1.schan) { + LOGPENDP(endp, DE1, LOGL_ERROR, "adding I.460 subchannel: failed!\n"); + return -EINVAL; + } + + if (endp->e1.scd.rate == OSMO_I460_RATE_16k || endp->e1.scd.rate == OSMO_I460_RATE_8k) { + /* TRAU frames are only specified for 16k and 8k subslots. For all other subslot + * types the concept of TRAU frames does not apply. However, at the moment this + * is the only format we currently support in osmo-mgw */ + endp->e1.trau_sync_fi = osmo_trau_sync_alloc(endp, "trau-sync", sync_frame_out_cb, sync_pat_id, endp); + if (!endp->e1.trau_sync_fi) { + LOGPENDP(endp, DE1, LOGL_ERROR, "adding I.460 TRAU frame sync: failed!\n"); + return -EINVAL; + } + endp->e1.trau_rtp_st = talloc_zero(endp->e1.trau_sync_fi, struct osmo_trau2rtp_state); + endp->e1.trau_rtp_st->type = OSMO_TRAU_FT_NONE; + } else { + LOGPENDP(endp, DE1, LOGL_ERROR, + "osmo-mgw currently only supports 16K and 8K subslots (TRAU frames)!\n"); + return -EINVAL; + } + + return 0; +} + +/*! Update E1 related parameters (codec and sync pattern). + * \param[in] endp endpoint to update. */ +void mgcp_e1_endp_update(struct mgcp_endpoint *endp) +{ + struct mgcp_conn *conn; + struct mgcp_rtp_codec *codec; + enum osmo_tray_sync_pat_id sync_pat_id; + + /* In order to determine the codec, find the oldest connection on + * the endpoint and use its codec information. Normally on an E1 + * endpoint no more than one connection should exist. */ + conn = mgcp_conn_get_oldest(endp); + OSMO_ASSERT(conn); + codec = conn->u.rtp.end.codec; + OSMO_ASSERT(codec); + + /* Update codec information */ + endp->e1.trau_rtp_st->type = + determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp); + endp->e1.last_codec = codec; + + /* Update sync pattern */ + sync_pat_id = determine_trau_sync_pat(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp); + osmo_trau_sync_set_pat(endp->e1.trau_sync_fi, sync_pat_id); +} + +/*! Remove E1 resources from endpoint + * \param[in] endp endpoint to release. */ +void mgcp_e1_endp_release(struct mgcp_endpoint *endp) +{ + LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n"); + + if (endp->e1.schan) + osmo_i460_subchan_del(endp->e1.schan); + if (endp->e1.trau_rtp_st) + talloc_free(endp->e1.trau_rtp_st); + if (endp->e1.trau_sync_fi) + osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL); + + memset(&endp->e1, 0, sizeof(endp->e1)); +} + +/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit. + * \param[in] endp related endpoint (does not take ownership). + * \param[in] codec configuration. + * \param[in] msg RTP message buffer (including RTP header). + * \returns 0 on success, -1 on ERROR. */ +int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg) +{ + struct msgb *msg_tf = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-TX-TRAU-frame"); + struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats; + unsigned int rtp_hdr_len = sizeof(struct rtp_hdr); + struct osmo_trau_frame tf; + uint8_t amr_ft; + int rc; + + /* Extract AMR frame type from AMR head (if AMR is used) */ + if (tf_type_is_amr(endp->e1.trau_rtp_st->type)) + amr_ft = (msgb_data(msg)[rtp_hdr_len + 1] >> 3) & 0xf; + else + amr_ft = 0xff; + + /* Adapt TRAU frame type on codec changes */ + OSMO_ASSERT(endp->e1.last_codec); + if (codec != endp->e1.last_codec || (amr_ft != 0xff && amr_ft != endp->e1.last_amr_ft)) { + endp->e1.trau_rtp_st->type = + determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, amr_ft, endp); + endp->e1.last_codec = codec; + endp->e1.last_amr_ft = amr_ft; + } + if (endp->e1.trau_rtp_st->type == OSMO_TRAU_FT_NONE) + goto skip; + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: using trau frame type for encoding: %s\n", + osmo_trau_frame_type_name(endp->e1.trau_rtp_st->type)); + + /* Convert from RTP to TRAU format */ + msg->l2h = msgb_data(msg) + rtp_hdr_len; + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: decoding %u bytes of RTP audio to TRAU format: %s\n", + msgb_length(msg), osmo_hexdump(msgb_l2(msg), msgb_l2len(msg))); + memset(&tf, 0, sizeof(tf)); + tf.dir = OSMO_TRAU_DIR_DL; + rc = osmo_rtp2trau(&tf, msgb_l2(msg), msgb_l2len(msg), endp->e1.trau_rtp_st); + if (rc < 0) { + LOGPENDP(endp, DE1, LOGL_DEBUG, + "E1-I.460-TX: failed to decode from RTP payload format to TRAU format\n"); + goto skip; + } + rc = osmo_trau_frame_encode(msgb_data(msg_tf), msg_tf->data_len, &tf); + if (rc < 0) { + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: failed to encode TRAU frame\n"); + goto skip; + } + msgb_put(msg_tf, rc); + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg_tf), + osmo_ubit_dump(msgb_data(msg_tf), + msgb_length(msg_tf) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg_tf))); + + /* Enqueue data to I.460 multiplexer */ + OSMO_ASSERT(endp->e1.schan); + OSMO_ASSERT(endp->e1.trau_sync_fi); + + osmo_i460_mux_enqueue(endp->e1.schan, msg_tf); + LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: %u bits of audio enqued for E1 tx\n", msgb_length(msg_tf)); + + return 0; +skip: + rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_TX_FAIL_CTR]); + msgb_free(msg_tf); + return -1; +} diff --git a/src/libosmo-mgcp/mgcp_endp.c b/src/libosmo-mgcp/mgcp_endp.c index 5d9ec27..f0ad0a7 100644 --- a/src/libosmo-mgcp/mgcp_endp.c +++ b/src/libosmo-mgcp/mgcp_endp.c @@ -25,33 +25,12 @@ #include <osmocom/mgcp/mgcp_endp.h> #include <osmocom/mgcp/mgcp_trunk.h> +#include <osmocom/mgcp/mgcp_e1.h> + #define E1_TIMESLOTS 32 #define E1_RATE_MAX 64 #define E1_OFFS_MAX 8 -/* A 64k timeslot on an E1 line can be subdevied into the following - * subslot combinations: - * - * subslot: offset: - * [ ][ ][ 16k ][8k_subslot] 0 - * [ ][ 32k ][_subslot__][8k_subslot] 1 - * [ ][ subslot ][ 16k ][8k_subslot] 2 - * [ 64k ][__________][_subslot__][8k_subslot] 3 - * [ timeslot ][ ][ 16k ][8k_subslot] 4 - * [ ][ 32K ][_subslot__][8k_subslot] 5 - * [ ][ subslot ][ 16k ][8k_subslot] 6 - * [ ][ ][ subslot ][8k_subslot] 7 - * - * Since overlapping assignment of subslots is not possible there is a limited - * set of subslot assignments possible. The e1_rates array lists the possible - * assignments as depicted above. Also each subslot assignment comes along with - * a bit offset in the E1 bitstream. The e1_offsets arrays lists the bit - * offsets. */ -static const uint8_t e1_rates[] = - { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 }; -static const uint8_t e1_offsets[] = - { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 }; - /* Endpoint typeset definition */ const struct mgcp_endpoint_typeset ep_typeset = { /* Specify endpoint properties for RTP endpoint */ @@ -116,7 +95,7 @@ endp->name = gen_virtual_epname(endp, trunk->cfg->domain, index); break; case MGCP_TRUNK_E1: - endp->type = &ep_typeset.rtp; + endp->type = &ep_typeset.e1; endp->name = gen_e1_epname(endp, trunk->cfg->domain, trunk->trunk_nr, index / MGCP_ENDP_E1_SUBSLOTS, index % MGCP_ENDP_E1_SUBSLOTS); @@ -149,6 +128,9 @@ talloc_free(endp->local_options.codec); endp->local_options.codec = NULL; endp->wildcarded_req = false; + + if (endp->trunk->trunk_type == MGCP_TRUNK_E1) + mgcp_e1_endp_release(endp); } /* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or @@ -614,3 +596,71 @@ return false; } + +/*! claim endpoint, sets callid and activates endpoint, should be called at the + * beginning of the CRCX procedure when it is clear that a new call should be + * created. + * \param[in] endp endpoint to claim. + * \param[in] callid that is assingned to this endpoint. */ +int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid) +{ + int rc = 0; + uint8_t ts; + uint8_t ss; + uint8_t offs; + + /* TODO: Make this function more intelligent, it should run the + * call id checks we currently have in protocol.c directly here. */ + + /* Set the callid, creation of another connection will only be possible + * when the callid matches up. (Connections are distinguished by their + * connection ids) */ + endp->callid = talloc_strdup(endp, callid); + OSMO_ASSERT(endp->callid); + + /* Allocate resources */ + switch (endp->trunk->trunk_type) { + case MGCP_TRUNK_VIRTUAL: + /* No additional initaliziation required here, virtual + * endpoints will open/close network sockets themselves + * on demand. */ + break; + case MGCP_TRUNK_E1: + ts = e1_ts_nr_from_epname(endp->name); + ss = e1_ss_nr_from_epname(endp->name); + offs = e1_offs_from_epname(endp->name); + OSMO_ASSERT(ts != 0xFF); + OSMO_ASSERT(ts != 0); + OSMO_ASSERT(ss != 0xFF); + OSMO_ASSERT(offs != 0xFF); + rc = mgcp_e1_endp_equip(endp, ts, ss, offs); + break; + default: + OSMO_ASSERT(false); + } + + /* Make sure the endpoint is released when claiming the endpoint + * failes. */ + if (rc < 0) + mgcp_endp_release(endp); + + return rc; +} + +/*! update endpoint, updates internal endpoint specific data, should be + * after when MDCX or CRCX has been executed successuflly. + * \param[in] endp endpoint to update. */ +void mgcp_endp_update(struct mgcp_endpoint *endp) +{ + /* Allocate resources */ + switch (endp->trunk->trunk_type) { + case MGCP_TRUNK_VIRTUAL: + /* No updating initaliziation required for virtual endpoints. */ + break; + case MGCP_TRUNK_E1: + mgcp_e1_endp_update(endp); + break; + default: + OSMO_ASSERT(false); + } +} diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c index 155ed20..e0aa42e 100644 --- a/src/libosmo-mgcp/mgcp_network.c +++ b/src/libosmo-mgcp/mgcp_network.c @@ -46,12 +46,11 @@ #include <osmocom/mgcp/mgcp_codec.h> #include <osmocom/mgcp/debug.h> #include <osmocom/codec/codec.h> - +#include <osmocom/mgcp/mgcp_e1.h> #define RTP_SEQ_MOD (1 << 16) #define RTP_MAX_DROPOUT 3000 #define RTP_MAX_MISORDER 100 -#define RTP_BUF_SIZE 4096 enum rtp_proto { MGCP_PROTO_RTP, @@ -798,6 +797,23 @@ "Forwarding tapped (debug) voice data failed.\n"); } +/* Generate an RTP header if it is missing */ +static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end, + struct mgcp_rtp_state *state) +{ + struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg); + + if (hdr->version > 0) + return; + + hdr->version = 2; + hdr->payload_type = rtp_end->codec->payload_type; + hdr->timestamp = osmo_htonl(get_current_ts(rtp_end->codec->rate)); + hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence); + hdr->ssrc = state->alt_rtp_tx_ssrc; +} + + /*! Send RTP/RTCP data to a specified destination connection. * \param[in] endp associated endpoint (for configuration, logging). * \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP. @@ -857,6 +873,11 @@ rtp_state = &conn_src->state; dest_name = conn_dst->conn->name; + /* Ensure we have an alternative SSRC in case we need it, see also + * gen_rtp_header() */ + if (rtp_state->alt_rtp_tx_ssrc == 0) + rtp_state->alt_rtp_tx_ssrc = rand(); + if (!rtp_end->output_enabled) { rtpconn_rate_ctr_inc(conn_dst, endp, RTP_DROPPED_PACKETS_CTR); LOGPENDP(endp, DRTP, LOGL_DEBUG, @@ -870,6 +891,11 @@ int cont; int nbytes = 0; int buflen = msgb_length(msg); + + /* Make sure we have a valid RTP header, in cases where no RTP + * header is present, we will generate one. */ + gen_rtp_header(msg, rtp_end, rtp_state); + do { /* Run transcoder */ cont = endp->cfg->rtp_processing_cb(endp, rtp_end, @@ -938,6 +964,7 @@ rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR); rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len); + rtp_state->alt_rtp_tx_sequence++; nbytes += len; buflen = cont; @@ -956,6 +983,7 @@ rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR); rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len); + rtp_state->alt_rtp_tx_sequence++; return len; } @@ -1236,12 +1264,24 @@ struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg); struct mgcp_conn_rtp *conn_src = mc->conn_src; struct mgcp_conn *conn = conn_src->conn; + struct sockaddr_in *from_addr = mc->from_addr; - /* FIXME: integrate E1 support from libsomoabis, also implement - * handling for RTCP packets, which can not converted to E1. */ - LOGPCONN(conn, DRTP, LOGL_FATAL, - "cannot dispatch! E1 support is not implemented yet!\n"); - return -1; + /* Check if the connection is in loopback mode, if yes, just send the + * incoming data back to the origin */ + if (conn->mode == MGCP_CONN_LOOPBACK) { + /* When we are in loopback mode, we loop back all incoming + * packets back to their origin. We will use the originating + * 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; + } + return mgcp_send_rtp(conn_src, msg); + } + + /* Forward to E1 */ + return mgcp_e1_send_rtp(conn->endp, conn->u.rtp.end.codec, msg); } /*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed. @@ -1267,8 +1307,9 @@ * \param[in] conn Connection that is about to be removed (ignored). */ void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn) { - LOGPCONN(conn, DRTP, LOGL_FATAL, - "cannot dispatch! E1 support is not implemented yet!\n"); + /* Cleanup tasks for E1 are the same as for regular endpoint. The + * shut down of the E1 part is handled separately. */ + mgcp_cleanup_rtp_bridge_cb(endp, conn); } static bool is_dummy_msg(enum rtp_proto proto, struct msgb *msg) diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c index bc96462..2a6581e 100644 --- a/src/libosmo-mgcp/mgcp_protocol.c +++ b/src/libosmo-mgcp/mgcp_protocol.c @@ -849,10 +849,16 @@ } } - /* Set the callid, creation of another connection will only be possible - * when the callid matches up. (Connections are distinguished by their - * connection ids) */ - endp->callid = talloc_strdup(trunk->endpoints, callid); + if (!endp->callid) { + /* Claim endpoint resources. This will also set the callid, + * creating additional connections will only be possible if + * the callid matches up (see above). */ + rc = mgcp_endp_claim(endp, callid); + if (rc != 0) { + rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_CLAIM]); + return create_err_response(endp, 502, "CRCX", p->trans); + } + } snprintf(conn_name, sizeof(conn_name), "%s", callid); _conn = mgcp_conn_alloc(trunk->endpoints, endp, MGCP_CONN_TYPE_RTP, conn_name); @@ -863,6 +869,7 @@ goto error2; } + conn = mgcp_conn_get_rtp(endp, _conn->id); OSMO_ASSERT(conn); @@ -979,6 +986,7 @@ LOGPCONN(_conn, DLMGCP, LOGL_NOTICE, "CRCX: connection successfully created\n"); rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_SUCCESS]); + mgcp_endp_update(endp); return create_response_with_sdp(endp, conn, "CRCX", p->trans, true); error2: mgcp_endp_release(endp); @@ -1206,6 +1214,7 @@ LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE, "MDCX: connection successfully modified\n"); + mgcp_endp_update(endp); return create_response_with_sdp(endp, conn, "MDCX", p->trans, false); error3: return create_err_response(endp, error_code, "MDCX", p->trans); diff --git a/src/libosmo-mgcp/mgcp_ratectr.c b/src/libosmo-mgcp/mgcp_ratectr.c index 1a89c83..aacdd85 100644 --- a/src/libosmo-mgcp/mgcp_ratectr.c +++ b/src/libosmo-mgcp/mgcp_ratectr.c @@ -64,6 +64,7 @@ [MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." }, [MGCP_CRCX_FAIL_BIND_PORT] = { "crcx:bind_port", "port bind failure." }, [MGCP_CRCX_FAIL_AVAIL] = { "crcx:unavailable", "endpoint unavailable." }, + [MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." }, }; const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = { @@ -124,6 +125,20 @@ .ctr_desc = mgcp_dlcx_ctr_desc }; +static const struct rate_ctr_desc e1_rate_ctr_desc[] = { + [E1_I460_TRAU_RX_FAIL_CTR] = {"e1:rx_fail", "Inbound I.460 TRAU failures."}, + [E1_I460_TRAU_TX_FAIL_CTR] = {"e1:tx_fail", "Outbound I.460 TRAU failures."}, + [E1_I460_TRAU_MUX_EMPTY_CTR] = {"e1:i460", "Outbound I.460 MUX queue empty."} +}; + +const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = { + .group_name_prefix = "e1", + .group_description = "e1 statistics", + .class_id = OSMO_STATS_CLASS_GLOBAL, + .num_ctr = ARRAY_SIZE(e1_rate_ctr_desc), + .ctr_desc = e1_rate_ctr_desc +}; + const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = { .group_name_prefix = "all_rtp_conn", .group_description = "aggregated statistics for all rtp connections", @@ -203,5 +218,12 @@ talloc_set_destructor(ratectr->all_rtp_conn_stats, free_rate_counter_group); all_rtp_conn_rate_ctr_index++; } + if (ratectr->e1_stats == NULL) { + ratectr->e1_stats = rate_ctr_group_alloc(ctx, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index); + if (!ratectr->e1_stats) + return -EINVAL; + talloc_set_destructor(ratectr->e1_stats, free_rate_counter_group); + mdcx_rate_ctr_index++; + } return 0; } diff --git a/src/libosmo-mgcp/mgcp_trunk.c b/src/libosmo-mgcp/mgcp_trunk.c index 0d7b385..dfedc4b 100644 --- a/src/libosmo-mgcp/mgcp_trunk.c +++ b/src/libosmo-mgcp/mgcp_trunk.c @@ -24,6 +24,8 @@ #include <osmocom/mgcp/mgcp_internal.h> #include <osmocom/mgcp/mgcp_endp.h> #include <osmocom/mgcp/mgcp_trunk.h> +#include <osmocom/mgcp/mgcp_e1.h> +#include <osmocom/abis/e1_input.h> /*! allocate trunk and add it (if required) to the trunk list. * (called once at startup by VTY). @@ -47,7 +49,7 @@ trunk->audio_send_ptime = 1; trunk->audio_send_name = 1; - trunk->vty_number_endpoints = 32; + trunk->v.vty_number_endpoints = 32; trunk->omit_rtcp = 0; mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE); @@ -81,13 +83,13 @@ /* Due to historical reasons the endpoints on the virtual * trunk start counting at 1. */ first_endpoint_nr = 1; - number_endpoints = trunk->vty_number_endpoints; + number_endpoints = trunk->v.vty_number_endpoints; break; case MGCP_TRUNK_E1: /* The first timeslot on an E1 line is reserved for framing * and alignment and can not be used for audio transport */ first_endpoint_nr = 1 * MGCP_ENDP_E1_SUBSLOTS; - number_endpoints = 31 * MGCP_ENDP_E1_SUBSLOTS; + number_endpoints = (NUM_E1_TS-1) * MGCP_ENDP_E1_SUBSLOTS; break; default: OSMO_ASSERT(false); @@ -122,6 +124,41 @@ return 0; } +/*! Equip trunk with endpoints and resources + * (called once at startup by VTY). + * \param[in] trunk trunk configuration. + * \returns 0 on success, -1 on failure. */ +int mgcp_trunk_equip(struct mgcp_trunk *trunk) +{ + unsigned int i; + + /* Allocate endpoints */ + if(mgcp_trunk_alloc_endpts(trunk) != 0) + return -1; + + /* Allocate resources */ + switch (trunk->trunk_type) { + case MGCP_TRUNK_VIRTUAL: + /* No additional initaliziation required here, virtual + * endpoints will open/close network sockets themselves + * on demand. */ + break; + case MGCP_TRUNK_E1: + /* The TS initalization happens once on startup for all + * timeslots. This only affects the i460 multiplexer. Until + * now no E1 resources are claimed yet. This happens on demand + * when the related endpoint is actually used */ + memset(trunk->e1.i460_ts, 0, sizeof(trunk->e1.i460_ts)); + for (i = 0; i < (NUM_E1_TS-1); i++) + osmo_i460_ts_init(&trunk->e1.i460_ts[i]); + break; + default: + OSMO_ASSERT(false); + } + + return 0; +} + /*! get trunk configuration by trunk number (index). * \param[in] cfg mgcp configuration. * \param[in] ttype trunk type. @@ -199,3 +236,19 @@ LOGP(DLMGCP, LOGL_ERROR, "unable to find trunk for endpoint name \"%s\"!\n", epname); return NULL; } + +/*! Find a trunk (E1) by its associated E1 line number. + * \param[in] num e1 line number. + * \returns trunk or NULL if trunk was not found. */ +struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num) +{ + /*! When used on trunks other than E1, the result will always be NULL. */ + struct mgcp_trunk *trunk; + + llist_for_each_entry(trunk, &cfg->trunks, entry) { + if (trunk->trunk_type == MGCP_TRUNK_E1 && trunk->e1.vty_line_nr == num) + return trunk; + } + + return NULL; +} diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c index 35b75fb..b8ec241 100644 --- a/src/libosmo-mgcp/mgcp_vty.c +++ b/src/libosmo-mgcp/mgcp_vty.c @@ -112,7 +112,7 @@ trunk->audio_send_name ? "" : "no ", VTY_NEWLINE); vty_out(vty, " loop %u%s", ! !trunk->audio_loop, VTY_NEWLINE); vty_out(vty, " number endpoints %u%s", - trunk->vty_number_endpoints, VTY_NEWLINE); + trunk->v.vty_number_endpoints, VTY_NEWLINE); vty_out(vty, " %sallow-transcoding%s", trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE); if (g_cfg->call_agent_addr) @@ -243,8 +243,10 @@ } } -static void dump_ratectr_trunk(struct vty *vty, struct mgcp_ratectr_trunk *ratectr) +static void dump_ratectr_trunk(struct vty *vty, struct mgcp_trunk *trunk) { + struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr; + vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Rate counters (trunk):%s", VTY_NEWLINE); @@ -280,6 +282,15 @@ " %25n: %10c (%S/s %M/m %H/h %D/d) %d", ratectr->all_rtp_conn_stats); } + + if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) { + vty_out(vty, " %s:%s", + ratectr->e1_stats->desc->group_description, + VTY_NEWLINE); + vty_out_rate_ctr_group_fmt(vty, + " %25n: %10c (%S/s %M/m %H/h %D/d) %d", + ratectr->e1_stats); + } } @@ -305,7 +316,7 @@ } if (show_stats) - dump_ratectr_trunk(vty, &trunk->ratectr); + dump_ratectr_trunk(vty, trunk); } #define SHOW_MGCP_STR "Display information about the MGCP Media Gateway\n" @@ -715,7 +726,7 @@ { struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); OSMO_ASSERT(trunk); - trunk->vty_number_endpoints = atoi(argv[0]); + trunk->v.vty_number_endpoints = atoi(argv[0]); return CMD_SUCCESS; } @@ -894,6 +905,7 @@ continue; vty_out(vty, " trunk %d%s", trunk->trunk_nr, VTY_NEWLINE); + vty_out(vty, " line %u%s", trunk->e1.vty_line_nr, VTY_NEWLINE); vty_out(vty, " %ssdp audio-payload send-ptime%s", trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE); vty_out(vty, " %ssdp audio-payload send-name%s", @@ -1159,6 +1171,19 @@ return CMD_SUCCESS; } +#define LINE_STR "Configure trunk for given Line\nE1/T1 Line Number\n" + +DEFUN(cfg_trunk_line, + cfg_trunk_line_cmd, + "line <0-255>", + LINE_STR) +{ + struct mgcp_trunk *trunk = vty->index; + int line_nr = atoi(argv[0]); + trunk->e1.vty_line_nr = line_nr; + return CMD_SUCCESS; +} + DEFUN(loop_conn, loop_conn_cmd, "loop-endpoint <0-64> NAME (0|1)", @@ -1549,6 +1574,7 @@ install_element(TRUNK_NODE, &cfg_trunk_no_sdp_payload_send_name_cmd); install_element(TRUNK_NODE, &cfg_trunk_allow_transcoding_cmd); install_element(TRUNK_NODE, &cfg_trunk_no_allow_transcoding_cmd); + install_element(TRUNK_NODE, &cfg_trunk_line_cmd); return 0; } @@ -1577,7 +1603,7 @@ } llist_for_each_entry(trunk, &g_cfg->trunks, entry) { - if (mgcp_trunk_alloc_endpts(trunk) != 0) { + if (mgcp_trunk_equip(trunk) != 0) { LOGP(DLMGCP, LOGL_ERROR, "Failed to initialize trunk %d (%d endpoints)\n", trunk->trunk_nr, trunk->number_endpoints); diff --git a/src/osmo-mgw/Makefile.am b/src/osmo-mgw/Makefile.am index d38df9f..928390b 100644 --- a/src/osmo-mgw/Makefile.am +++ b/src/osmo-mgw/Makefile.am @@ -11,6 +11,8 @@ $(LIBOSMOGSM_CFLAGS) \ $(LIBOSMOCTRL_CFLAGS) \ $(LIBOSMONETIF_CFLAGS) \ + $(LIBOSMOABIS_CFLAGS) \ + $(LIBOSMOTRAU_CFLAGS) \ $(COVERAGE_CFLAGS) \ $(NULL) @@ -29,4 +31,6 @@ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOCTRL_LIBS) \ $(LIBOSMONETIF_LIBS) \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOTRAU_LIBS) \ $(NULL) diff --git a/src/osmo-mgw/mgw_main.c b/src/osmo-mgw/mgw_main.c index 6ca1800..036e0c0 100644 --- a/src/osmo-mgw/mgw_main.c +++ b/src/osmo-mgw/mgw_main.c @@ -30,6 +30,8 @@ #include <limits.h> #include <unistd.h> #include <errno.h> +#include <osmocom/core/msgb.h> +#include <osmocom/abis/e1_input.h> #include <sys/socket.h> @@ -58,6 +60,7 @@ #include <osmocom/vty/command.h> #include <osmocom/vty/stats.h> #include <osmocom/vty/misc.h> +#include <osmocom/abis/abis.h> #include "../../bscconfig.h" @@ -268,7 +271,13 @@ .description = "RTP stream handling", .color = "\033[1;30m", .enabled = 1,.loglevel = LOGL_NOTICE, - }, + }, + [DE1] = { + .name = "DE1", + .description = "E1 line handling", + .color = "\033[1;31m", + .enabled = 1,.loglevel = LOGL_NOTICE, + }, }; const struct log_info log_info = { @@ -288,6 +297,7 @@ osmo_init_ignore_signals(); osmo_init_logging2(tall_bsc_ctx, &log_info); + libosmo_abis_init(tall_bsc_ctx); cfg = mgcp_config_alloc(); if (!cfg) @@ -300,6 +310,7 @@ osmo_stats_vty_add_cmds(); mgcp_vty_init(); ctrl_vty_init(cfg); + e1inp_vty_init(); handle_options(argc, argv); diff --git a/tests/mgcp/Makefile.am b/tests/mgcp/Makefile.am index 95444b5..1224c0a 100644 --- a/tests/mgcp/Makefile.am +++ b/tests/mgcp/Makefile.am @@ -11,6 +11,8 @@ $(LIBOSMOVTY_CFLAGS) \ $(LIBOSMOGSM_CFLAGS) \ $(LIBOSMONETIF_CFLAGS) \ + $(LIBOSMOABIS_CFLAGS) \ + $(LIBOSMOTRAU_CFLAGS) \ $(COVERAGE_CFLAGS) \ $(NULL) @@ -35,6 +37,8 @@ $(LIBOSMOCORE_LIBS) \ $(LIBOSMOVTY_LIBS) \ $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOTRAU_LIBS) \ $(LIBRARY_DL) \ $(LIBRARY_DLSYM) \ $(LIBOSMONETIF_LIBS) \ diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c index 458f6c9..a050a0b 100644 --- a/tests/mgcp/mgcp_test.c +++ b/tests/mgcp/mgcp_test.c @@ -771,8 +771,8 @@ cfg = mgcp_config_alloc(); trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); - trunk->vty_number_endpoints = 64; - mgcp_trunk_alloc_endpts(trunk); + trunk->v.vty_number_endpoints = 64; + mgcp_trunk_equip(trunk); cfg->policy_cb = mgcp_test_policy_cb; memset(last_conn_id, 0, sizeof(last_conn_id)); @@ -908,8 +908,8 @@ cfg = mgcp_config_alloc(); trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); - trunk->vty_number_endpoints = 64; - mgcp_trunk_alloc_endpts(trunk); + trunk->v.vty_number_endpoints = 64; + mgcp_trunk_equip(trunk); memset(last_conn_id, 0, sizeof(last_conn_id)); @@ -973,8 +973,8 @@ trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); cfg->rqnt_cb = rqnt_cb; - trunk->vty_number_endpoints = 64; - mgcp_trunk_alloc_endpts(trunk); + trunk->v.vty_number_endpoints = 64; + mgcp_trunk_equip(trunk); inp = create_msg(CRCX, NULL); msg = mgcp_handle_message(cfg, inp); @@ -1050,7 +1050,7 @@ endp.cfg = &cfg; endp.type = &ep_typeset.rtp; - trunk.vty_number_endpoints = 1; + trunk.v.vty_number_endpoints = 1; trunk.endpoints = endpoints; trunk.endpoints[0] = &endp; endp.trunk = &trunk; @@ -1301,7 +1301,7 @@ endp.cfg = &cfg; endp.type = &ep_typeset.rtp; - trunk.vty_number_endpoints = 1; + trunk.v.vty_number_endpoints = 1; trunk.endpoints = endpoints; trunk.endpoints[0] = &endp; trunk.force_constant_ssrc = patch_ssrc; @@ -1382,8 +1382,8 @@ cfg = mgcp_config_alloc(); trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); - trunk->vty_number_endpoints = 64; - mgcp_trunk_alloc_endpts(trunk); + trunk->v.vty_number_endpoints = 64; + mgcp_trunk_equip(trunk); cfg->policy_cb = mgcp_test_policy_cb; /* Allocate endpoint 1 at mgw with two codecs */ @@ -1531,8 +1531,8 @@ cfg = mgcp_config_alloc(); trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); - trunk->vty_number_endpoints = 64; - mgcp_trunk_alloc_endpts(trunk); + trunk->v.vty_number_endpoints = 64; + mgcp_trunk_equip(trunk); endp = mgcp_endp_by_name(NULL, "rtpbridge/1 at mgw", cfg); OSMO_ASSERT(endp); @@ -1581,9 +1581,9 @@ cfg = mgcp_config_alloc(); trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); - trunk->vty_number_endpoints = 64; + trunk->v.vty_number_endpoints = 64; trunk->audio_send_name = 0; - mgcp_trunk_alloc_endpts(trunk); + mgcp_trunk_equip(trunk); cfg->policy_cb = mgcp_test_policy_cb; -- To view, visit https://gerrit.osmocom.org/c/osmo-mgw/+/19524 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-mgw Gerrit-Branch: master Gerrit-Change-Id: I6b93809b5ac7d01af55888347dd787b0bc997ae1 Gerrit-Change-Number: 19524 Gerrit-PatchSet: 3 Gerrit-Owner: dexter <pmaier at sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge at osmocom.org> Gerrit-MessageType: merged -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200812/d64c5ecc/attachment.htm>