Compare commits

..

2 Commits

Author SHA1 Message Date
Philipp Maier
ed7c4fcfc3 mgcp_codec: do not differentiate between oa and bwe when comparing codec
AMR that has the payload format bandwith-efficient is the same codec as
AMR that has the payload format octet-aligned. Its the same codec, and a
comparison of the codec info with the function codecs_same() should
return true (=equal).

The affected function codecs_same() is used by mgcp_codec_pt_translate().
When the egress payload type number is looked up, the ingress and egress
codec information is compared. When one end is using AMR in
bandwith-efficient format and the other end is using it in
octet-alingned format. Then the codec still must be recognized as the
same codec. Othersiwse the payload type number translation would not
work, even though the codec is the same on both sides.

Change-Id: I64731570c287a75d39c79c10e1bc09a37bdd54d6
Related: SYS#5834
2022-02-16 17:59:43 +01:00
Pau Espin Pedrol
3babd1a803 Make function amr_is_octet_aligned publicly available
it will be used by mgcp_iuup.c in follow-up patch.

Change-Id: Iffaf90c1f713feef0c609a7581a346f5f28141d9
2022-02-16 17:59:18 +01:00
17 changed files with 126 additions and 848 deletions

View File

@@ -107,8 +107,8 @@ We are planning to add further endpoint types for:
You can find the OsmoMGW issue tracker and wiki online at
- https://osmocom.org/projects/osmo-mgw
- https://osmocom.org/projects/osmo-mgw/wiki
- https://osmocom.org/projects/osmomgw
- https://osmocom.org/projects/osmomgw/wiki
RFC 3435 for MGCP is located at

View File

@@ -13,5 +13,4 @@ noinst_HEADERS = \
mgcp_e1.h \
mgcp_network.h \
mgcp_protocol.h \
mgcp_iuup.h \
$(NULL)

View File

@@ -28,7 +28,6 @@
#include <osmocom/mgcp/osmux.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/iuup.h>
#include <inttypes.h>
#define LOGPCONN(conn, cat, level, fmt, args...) \
@@ -48,7 +47,6 @@ enum mgcp_conn_rtp_type {
MGCP_RTP_DEFAULT = 0,
MGCP_OSMUX_BSC,
MGCP_OSMUX_BSC_NAT,
MGCP_RTP_IUUP,
};
/*! Connection type, specifies which member of the union "u" in mgcp_conn
@@ -95,14 +93,6 @@ struct mgcp_conn_rtp {
} stats;
} osmux;
struct {
struct osmo_iuup_instance *iui;
bool active_init; /* true: Send IuUP Init */
int rfci_idx_no_data; /* Index for RFCI NO_DATA (-1 if not available) */
bool configured;
struct osmo_iuup_rnl_prim *init_ind;
} iuup;
struct rate_ctr_group *rate_ctr_group;
};
@@ -186,12 +176,6 @@ static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
}
/* Was conn configured to handle Osmux? */
static inline bool mgcp_conn_rtp_is_iuup(const struct mgcp_conn_rtp *conn)
{
return conn->type == MGCP_RTP_IUUP;
}
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
enum mgcp_conn_type type, char *name);
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);

View File

@@ -1,33 +0,0 @@
/* IuUP connection functionalitites */
/*
* (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Pau Espin Pedrol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <osmocom/core/msgb.h>
struct mgcp_conn_rtp;
int mgcp_conn_iuup_init(struct mgcp_conn_rtp *conn_rtp);
void mgcp_conn_iuup_cleanup(struct mgcp_conn_rtp *conn_rtp);
int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg);
int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg);
int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp);

View File

@@ -70,6 +70,8 @@ struct mgcp_rtp_state {
* data is just re-used) */
uint16_t alt_rtp_tx_sequence;
uint32_t alt_rtp_tx_ssrc;
bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
};
struct mgcp_rtp_codec {
@@ -108,8 +110,8 @@ struct mgcp_rtp_end {
uint32_t packet_duration_ms;
int maximum_packet_time; /* -1: not set */
char *fmtp_extra;
/* are we transmitting packets (true) or dropping (false) outbound packets */
bool output_enabled;
/* are we transmitting packets (1) or dropping (0) outbound packets */
int output_enabled;
/* FIXME: This parameter can be set + printed, but is nowhere used! */
int force_output_ptime;
@@ -175,8 +177,3 @@ void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
const uint16_t seq, const int32_t transit,
const uint32_t ssrc, const bool marker_bit);
void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
int id, int inc);
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
uint32_t mgcp_get_current_ts(unsigned codec_rate);

View File

@@ -49,7 +49,6 @@ enum mgcp_codecs {
CODEC_GSMHR_8000_1 = 111,
CODEC_AMR_8000_1 = 112,
CODEC_AMRWB_16000_1 = 113,
CODEC_IUFP = 96,
};
/* Note: when new codec types are added, the corresponding value strings
* in mgcp_client.c (codec_table) must be updated as well. Enumerations

View File

@@ -0,0 +1,74 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 4
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

View File

@@ -59,7 +59,6 @@ const struct value_string osmo_mgcpc_codec_names[] = {
{ CODEC_GSMHR_8000_1, "GSM-HR-08/8000/1" },
{ CODEC_AMR_8000_1, "AMR/8000/1" },
{ CODEC_AMRWB_16000_1, "AMR-WB/16000/1" },
{ CODEC_IUFP, "VND.3GPP.IUFP/16000" },
{ 0, NULL },
};

View File

@@ -48,5 +48,4 @@ libosmo_mgcp_a_SOURCES = \
mgcp_ctrl.c \
mgcp_ratectr.c \
mgcp_e1.c \
mgcp_iuup.c \
$(NULL)

View File

@@ -417,7 +417,7 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
if (!codec_src)
return -EINVAL;
/* Use the codec information from the source and try to find the
/* Use the codec infrmation from the source and try to find the
* equivalent of it on the destination side */
codecs_assigned = rtp_dst->codecs_assigned;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);

View File

@@ -30,8 +30,6 @@
#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_sdp.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_iuup.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/timer.h>
@@ -110,7 +108,7 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
/* Set default values */
end->frames_per_packet = 0; /* unknown */
end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
end->output_enabled = false;
end->output_enabled = 0;
end->maximum_packet_time = -1;
conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
@@ -131,8 +129,6 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
{
if (mgcp_conn_rtp_is_osmux(conn_rtp))
conn_osmux_disable(conn_rtp);
if (mgcp_conn_rtp_is_iuup(conn_rtp))
mgcp_conn_iuup_cleanup(conn_rtp);
mgcp_free_rtp_port(&conn_rtp->end);
rate_ctr_group_free(conn_rtp->rate_ctr_group);
mgcp_codec_reset_all(conn_rtp);

View File

@@ -1,720 +0,0 @@
/*
* (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All rights not specifically granted under this license are reserved.
*
* Author: Pau Espin Pedrol
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*/
#include <stdint.h>
#include <osmocom/core/byteswap.h>
#include <osmocom/gsm/iuup.h>
#include <osmocom/netif/rtp.h>
#include <osmocom/netif/amr.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_iuup.h>
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_network.h>
#include <osmocom/mgcp/debug.h>
#define MGW_IUUP_MSGB_SIZE 4096
static const struct osmo_iuup_rnl_config def_configure_req = {
.transparent = false,
.active = true,
.supported_versions_mask = 0x0003,
.num_rfci = 0,
.num_subflows = 0,
.IPTIs_present = false,
.t_init = { .t_ms = IUUP_TIMER_INIT_T_DEFAULT, .n_max = IUUP_TIMER_INIT_N_DEFAULT },
.t_ta = { .t_ms = IUUP_TIMER_TA_T_DEFAULT, .n_max = IUUP_TIMER_TA_N_DEFAULT },
.t_rc = { .t_ms = IUUP_TIMER_RC_T_DEFAULT, .n_max = IUUP_TIMER_RC_N_DEFAULT },
};
/* Find a destination connection. */
static struct mgcp_conn *_find_dst_conn(struct mgcp_conn *conn)
{
/* NOTE: This code path runs every time an RTP packet is received. The
* function mgcp_find_dst_conn() we use to determine the detination
* connection will iterate the connection list inside the endpoint.
* Since list iterations are quite costly, we will figure out the
* destination only once and use the optional private data pointer of
* the connection to cache the destination connection pointer. */
struct mgcp_conn *conn_dst;
if (!conn->priv) {
conn_dst = mgcp_find_dst_conn(conn);
conn->priv = conn_dst;
} else {
conn_dst = (struct mgcp_conn *)conn->priv;
}
return conn_dst;
}
/* Find RFCI containing all 0 sizes, -1 if not found. irp is an Initialization.ind prim */
static int _find_rfci_no_data(struct osmo_iuup_rnl_prim *irp)
{
int i;
/* Find RFCI containing NO_DATA: */
for (i = 0; i < irp->u.status.u.initialization.num_rfci; i++) {
int j;
bool is_no_data = true;
for (j = 0; j < irp->u.status.u.initialization.num_subflows; j++) {
if (irp->u.status.u.initialization.subflow_sizes[i][j]) {
is_no_data = false;
break;
}
}
if (is_no_data) {
return i;
}
}
return -1;
}
/* Lookup RFCI to use for specific AMR codec type. -1 if none found */
static int8_t _conn_iuup_amr_ft_2_rfci(struct mgcp_conn_rtp *conn_rtp, uint8_t ft)
{
int8_t i;
unsigned match_bytes = (unsigned)osmo_amr_bytes(ft);
struct osmo_iuup_rnl_prim *irp = conn_rtp->iuup.init_ind;
OSMO_ASSERT(irp);
/* TODO: cache this somehow */
for (i = 0; i < irp->u.status.u.initialization.num_rfci; i++) {
int j;
unsigned num_bits = 0;
for (j = 0; j < irp->u.status.u.initialization.num_subflows; j++)
num_bits += irp->u.status.u.initialization.subflow_sizes[i][j];
if (match_bytes == (num_bits + 7)/8)
return i;
}
return -1;
}
/* Helper function to configure IuUP layer FSM as Init-Passive, based on default config */
static int _conn_iuup_configure_as_passive(struct mgcp_conn_rtp *conn_rtp)
{
struct osmo_iuup_rnl_prim *irp;
int rc;
conn_rtp->iuup.active_init = false;
/* Tx CONFIG.req */
irp = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
irp->u.config = def_configure_req;
irp->u.config.active = conn_rtp->iuup.active_init;
if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp)) == 0)
conn_rtp->iuup.configured = true;
else
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed configuring IuUP layer\n");
return rc;
}
/* Helper function to configure IuUP layer FSM as Init-Active, based on received
* RNL Status-Init primitive from the sister IuUP connection we will bridge to. */
static int _conn_iuup_configure_as_active(struct mgcp_conn_rtp *conn_rtp, struct osmo_iuup_rnl_prim *init_ind)
{
struct osmo_iuup_rnl_prim *irp = init_ind;
struct osmo_iuup_rnl_prim *irp2;
struct msgb *msg;
bool prev_output_enabled;
int rc;
conn_rtp->iuup.active_init = true;
/* Find RFCI containing NO_DATA: */
conn_rtp->iuup.rfci_idx_no_data = _find_rfci_no_data(init_ind);
/* Copy over the rfci_idx_no_data, since we reuse the same subflow set: */
msg = msgb_copy_c(conn_rtp->conn, irp->oph.msg, "iuup-init-copy");
conn_rtp->iuup.init_ind = (struct osmo_iuup_rnl_prim *)msgb_data(msg);
conn_rtp->iuup.init_ind->oph.msg = msg;
/* Tx CONFIG.req */
irp2 = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
irp2->u.config.transparent = false;
irp2->u.config.active = conn_rtp->iuup.active_init;
irp2->u.config.data_pdu_type = irp->u.status.u.initialization.data_pdu_type;
irp2->u.config.supported_versions_mask = def_configure_req.supported_versions_mask;
irp2->u.config.num_rfci = irp->u.status.u.initialization.num_rfci;
irp2->u.config.num_subflows = irp->u.status.u.initialization.num_subflows;
memcpy(irp2->u.config.subflow_sizes, irp->u.status.u.initialization.subflow_sizes,
IUUP_MAX_RFCIS * IUUP_MAX_SUBFLOWS * sizeof(irp2->u.config.subflow_sizes[0][0]));
irp2->u.config.IPTIs_present = irp->u.status.u.initialization.IPTIs_present;
if (irp->u.status.u.initialization.IPTIs_present)
memcpy(irp2->u.config.IPTIs, irp->u.status.u.initialization.IPTIs,
IUUP_MAX_RFCIS * sizeof(irp2->u.config.IPTIs[0]));
irp2->u.config.t_init = def_configure_req.t_init;
irp2->u.config.t_ta = def_configure_req.t_ta;
irp2->u.config.t_rc = def_configure_req.t_rc;
/* We need to force allowance of RTP containing Init-ACK back: */
prev_output_enabled = conn_rtp->end.output_enabled;
conn_rtp->end.output_enabled = true;
if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp2)) == 0)
conn_rtp->iuup.configured = true;
else
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed configuring IuUP layer\n");
conn_rtp->end.output_enabled = prev_output_enabled;
return rc;
}
/* Helper function to push an RTP+IuUP pkt up to the IuUP layer FSM through the
* TNL primitive interface. */
static int _conn_iuup_rtp_pl_up(struct mgcp_conn_rtp *conn_rtp, struct msgb *msg)
{
/* Send RTP payload (IuUP) up the stack: */
struct osmo_iuup_tnl_prim *itp;
int rc;
msg->l2h = msgb_data(msg) + sizeof(struct rtp_hdr);
itp = osmo_iuup_tnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, MGW_IUUP_MSGB_SIZE);
itp->oph.msg->l2h = msgb_put(itp->oph.msg, msgb_l2len(msg));
memcpy(itp->oph.msg->l2h, msgb_l2(msg), msgb_l2len(msg));
if ((rc = osmo_iuup_tnl_prim_up(conn_rtp->iuup.iui, itp)) != 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed passing IuUP-Init to IuUP layer\n");
}
return rc;
}
static int check_rtp_iuup(const struct mgcp_conn_rtp *conn_rtp, struct msgb *msg)
{
size_t min_size = sizeof(struct rtp_hdr);
/* Check there's at least 2 bytes of RTP payload (IuUP header). This is
** mainly to avoid 0-byte payload copy cases */
if (msgb_length(msg) < sizeof(struct rtp_hdr) + 2) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "RTP-IuUP packet too short (%u < %zu)\n",
msgb_length(msg), min_size);
return -1;
}
return 0;
}
/* Bridge received IuUP packet in conn_rtp_src to conn_rtp_dst, an IuUP sister
* conn in the endpoint. The function takes ownsership of the irp */
static int bridge_iuup_to_iuup_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mgcp_conn_rtp *conn_rtp_dst, struct osmo_iuup_rnl_prim *irp)
{
int rc;
/* If we are not configured and we received bridged data, it means
* conn_rtp_src is already configured and INITed, and we can infer
* conn_rtp_src is Init-passive (RNC side), so conn_rtp_dst needs to be
* configured as INIT-active: */
if (!conn_rtp_dst->iuup.configured) {
OSMO_ASSERT(conn_rtp_src->iuup.init_ind);
rc = _conn_iuup_configure_as_active(conn_rtp_dst, conn_rtp_src->iuup.init_ind);
if (rc < 0) {
msgb_free(irp->oph.msg);
return rc;
}
}
/* We simply forward the msg, without freeing it: */
talloc_steal(conn_rtp_dst->conn, irp->oph.msg);
irp->oph.operation = PRIM_OP_REQUEST;
if ((rc = osmo_iuup_rnl_prim_down(conn_rtp_dst->iuup.iui, irp)) != 0)
LOG_CONN_RTP(conn_rtp_dst, LOGL_ERROR, "Failed Tx data down to IuUP layer\n");
return rc;
}
/* Bridge received IuUP packet in conn_rtp_src to conn_rtp_dst, an RTP (no IuUP)
* sister conn in the endpoint. The function takes ownsership of the irp */
static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mgcp_conn_rtp *conn_rtp_dst, struct osmo_iuup_rnl_prim *irp)
{
/* FIXME: We probably need transcoding here?! Or at least look up AMR modes and translate to related RFCI */
uint8_t frame_nr = irp->u.data.frame_nr;
uint8_t fqc = irp->u.data.fqc;
struct msgb *msg = irp->oph.msg;
ssize_t amr_length = 0;
int ft;
uint8_t *amr_data;
struct rtp_hdr *rtp_hdr;
struct amr_hdr *amr_hdr;
int rc;
ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
if (ft < 0) {
LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
"Unknown AMR format for size %u\n", msgb_l3len(msg));
msgb_free(msg);
return ft;
}
msgb_pull_to_l3(msg);
LOGP(DLMGCP, LOGL_DEBUG, "Convert Iuup -> AMR: ft %d, len %d\n", ft, msgb_l3len(msg));
if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
amr_hdr->cmr = 15; /* no change */
amr_hdr->f = 0;
amr_hdr->q = !fqc;
amr_hdr->ft = ft & 0xff;
amr_hdr->pad1 = 0;
amr_hdr->pad2 = 0;
} else {
OSMO_ASSERT(msgb_tailroom(msg) >= 2);
msgb_put(msg, 2);
osmo_amr_iuup_to_bwe(msgb_data(msg), msgb_length(msg) - 2, msgb_length(msg) + 2);
/* fill bwe header */
amr_data = msgb_data(msg);
/* CMR no change | follow bit | ft (3 of 4 bits) */
amr_data[0] = 15 << 4 | (0 << 3) | (ft >> 1);
amr_data[1] |= ((ft & 0x1) << 7) | (((!fqc) & 0x1) << 6);
amr_length = (osmo_amr_bits(ft) + 10 + 7) / 8;
msgb_trim(msg, amr_length);
}
rtp_hdr = (struct rtp_hdr *) msgb_push(msg, sizeof(*rtp_hdr));
*rtp_hdr = (struct rtp_hdr){
.csrc_count = 0,
.extension = 0,
.padding = 0,
.version = 0,
.payload_type = conn_rtp_dst->end.codec->payload_type,
.marker = 0,
.sequence = frame_nr,
.timestamp = 0,
.ssrc = 0
};
rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
msgb_free(msg);
return rc;
}
/* Handle RNL Data primitive received from the IuUP layer FSM: Bridge it to the
* sister connection in the endpoint: */
static int _conn_iuup_rx_rnl_data(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
{
struct mgcp_conn *conn_dst;
struct mgcp_conn_rtp *conn_rtp_dst;
int rc;
conn_dst = _find_dst_conn(conn_rtp_src->conn);
/* There is no destination conn, stop here */
if (!conn_dst) {
LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_DEBUG,
"no connection to forward an incoming IuUP payload to\n");
rc = -1;
goto free_ret;
}
/* The destination conn is not an RTP/IuUP connection */
if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
"unable to find suitable destination conn\n");
rc = -1;
goto free_ret;
}
conn_rtp_dst = &conn_dst->u.rtp;
switch (conn_rtp_dst->type) {
case MGCP_RTP_IUUP:
return bridge_iuup_to_iuup_peer(conn_rtp_src, conn_rtp_dst, irp);
case MGCP_RTP_DEFAULT:
return bridge_iuup_to_rtp_peer(conn_rtp_src, conn_rtp_dst, irp);
case MGCP_OSMUX_BSC:
case MGCP_OSMUX_BSC_NAT:
default:
LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
"Forward of IuUP payload to RTP connection type %u not supported!\n",
conn_rtp_dst->type);
rc = 0;
}
free_ret:
msgb_free(irp->oph.msg);
return rc;
}
/* Handle RNL Status-Init primitive received from the IuUP layer FSM.
* Potentially configure sister conn as IuUP Init-Active: */
static int _conn_iuup_rx_rnl_status_init(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
{
struct mgcp_conn *conn_dst;
struct mgcp_conn_rtp *conn_rtp_dst;
int rc = 0;
struct msgb *msg;
/* Find RFCI containing NO_DATA: */
conn_rtp_src->iuup.rfci_idx_no_data = _find_rfci_no_data(irp);
msg = msgb_copy_c(conn_rtp_src->conn, irp->oph.msg, "iuup-init-copy");
conn_rtp_src->iuup.init_ind = (struct osmo_iuup_rnl_prim *)msgb_data(msg);
conn_rtp_src->iuup.init_ind->oph.msg = msg;
conn_dst = _find_dst_conn(conn_rtp_src->conn);
/* If not yet there, peer will potentially be IuUP-Initialized later
* when we attempt to bridge audio towards it. See bridge_iuup_to_iuup_peer() */
if (!conn_dst)
return 0;
conn_rtp_dst = &conn_dst->u.rtp;
if (!mgcp_conn_rtp_is_iuup(conn_rtp_dst))
return 0; /* Nothing to do */
/* We received IuUP parameters on the peer (RNC), Init actively this conn (against CN): */
if (!conn_rtp_dst->iuup.configured)
rc = _conn_iuup_configure_as_active(conn_rtp_dst, irp);
return rc;
}
/* Handle RNL Status primitives received from the IuUP layer FSM: */
static int _conn_iuup_rx_rnl_status(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
{
int rc;
switch (irp->u.status.procedure) {
case IUUP_PROC_INIT:
rc = _conn_iuup_rx_rnl_status_init(conn_rtp_src, irp);
break;
case IUUP_PROC_RATE_CTRL:
case IUUP_PROC_TIME_ALIGN:
case IUUP_PROC_ERR_EVENT:
default:
LOG_CONN_RTP(conn_rtp_src, LOGL_ERROR,
"Received IuUP RNL STATUS procedure type %u not handled\n",
irp->u.status.procedure);
rc = 0;
}
return rc;
}
/* Received RNL primitive from the IuUP layer FSM containing IuUP Status or
* data. Continue pushing it up the stack, either IuUP Status or Data: */
static int _conn_iuup_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
struct mgcp_conn_rtp *conn_rtp_src = ctx;
struct osmo_iuup_rnl_prim *irp = (struct osmo_iuup_rnl_prim *)oph;
struct msgb *msg = oph->msg;
int rc;
switch (OSMO_PRIM_HDR(&irp->oph)) {
case OSMO_PRIM(OSMO_IUUP_RNL_DATA, PRIM_OP_INDICATION):
/* we pass ownsership of msg here: */
rc = _conn_iuup_rx_rnl_data(conn_rtp_src, irp);
break;
case OSMO_PRIM(OSMO_IUUP_RNL_STATUS, PRIM_OP_INDICATION):
rc = _conn_iuup_rx_rnl_status(conn_rtp_src, irp);
msgb_free(msg);
break;
default:
msgb_free(msg);
OSMO_ASSERT(false);
}
return rc;
}
/*! Send |RTP+IuUP| data down the stack of the specified destination connection.
* \param[in] endp associated endpoint (for configuration, logging).
* \param[in] buf buffer that contains the |RTP+IuUP| data.
* \param[in] len length of the buffer that contains the |RTP+IuUP| data.
* \param[in] conn_src associated source connection.
* \param[in] conn_dst associated destination connection.
* \returns 0 on success, -1 on ERROR. */
static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
{
/*! When no destination connection is available (e.g. when only one
* connection in loopback mode exists), then the source connection
* shall be specified as destination connection */
struct mgcp_rtp_end *rtp_end;
struct mgcp_rtp_state *rtp_state;
char ipbuf[INET6_ADDRSTRLEN];
struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
int buflen = msgb_length(msg);
char *dest_name;
int len;
OSMO_ASSERT(conn_src);
OSMO_ASSERT(conn_dst);
LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering IuUP packet...\n");
/* Note: In case of loopback configuration, both, the source and the
* destination will point to the same connection. */
rtp_end = &conn_dst->end;
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_add(conn_dst, endp, RTP_DROPPED_PACKETS_CTR, 1);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"output disabled, drop to %s %s "
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
);
return 0;
}
/* Specs say, in IuUP, the RTP seqnum and timestamp should actually be
* ignored by the receiver, but still it's useful for debug purposes
* to set it. Moreover, it seems ip.access nano3g produces much worse
* audio output on the air side if timestamp is not set properly. */
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port));
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
(char *)hdr, buflen);
if (len <= 0)
return len;
rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
return len;
}
/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
* socket towards destination peer. */
static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
struct mgcp_conn_rtp *conn_rtp_dst = ctx;
struct mgcp_conn *conn_dst = conn_rtp_dst->conn;
struct osmo_iuup_tnl_prim *itp = (struct osmo_iuup_tnl_prim *)oph;
struct mgcp_conn *conn_src;
struct msgb *msg;
struct rtp_hdr *rtph;
OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST));
msg = oph->msg;
talloc_steal(conn_rtp_dst->conn, msg);
msgb_pull_to_l2(msg);
rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
/* TODO: fill rtph properly: */
*rtph = (struct rtp_hdr){
.csrc_count = 0,
.extension = 0,
.padding = 0,
.version = 2,
.payload_type = conn_rtp_dst->end.codec->payload_type,
.marker = 0,
.sequence = 0,
.timestamp = 0,
.ssrc = 0
};
/* The destination of the destination conn is the source conn, right? */
conn_src = _find_dst_conn(conn_dst);
if (!conn_src) {
LOG_CONN_RTP(conn_rtp_dst, LOGL_NOTICE,
"Couldn't find source conn for IuUP dst conn\n");
/* If there's no sister connection we are either still
* initializing (so we want to send back Init (ACK)), or we are
* probably in loopback mode anyway, so use dst as src. */
conn_src = conn_dst;
}
return mgcp_send_iuup(conn_dst->endp, msg, &conn_src->u.rtp, conn_rtp_dst);
}
/* Used to upgrade a regular RTP connection (MGCP_RTP_DEFAULT) to become a IuUP
* connection (MGCP_RTP_IUUP) */
int mgcp_conn_iuup_init(struct mgcp_conn_rtp *conn_rtp)
{
conn_rtp->type = MGCP_RTP_IUUP;
conn_rtp->iuup.iui = osmo_iuup_instance_alloc(conn_rtp->conn, conn_rtp->conn->id);
OSMO_ASSERT(conn_rtp->iuup.iui);
osmo_iuup_instance_set_user_prim_cb(conn_rtp->iuup.iui, _conn_iuup_user_prim_cb, conn_rtp);
osmo_iuup_instance_set_transport_prim_cb(conn_rtp->iuup.iui, _conn_iuup_transport_prim_cb, conn_rtp);
conn_rtp->iuup.rfci_idx_no_data = -1;
return 0;
}
/* Cleanup specific IuUP connection (MGCP_RTP_IUUP) state, allocated by mgcp_conn_iuup_init() */
void mgcp_conn_iuup_cleanup(struct mgcp_conn_rtp *conn_rtp)
{
osmo_iuup_instance_free(conn_rtp->iuup.iui);
conn_rtp->iuup.iui = NULL;
}
/* Received RTP+IuUP pkt from socket of conn_rtp_src, build a TNL primitive to
* push it further up the stack to the IuUP layer FSM to handle and/or bridge it */
int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
{
struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
struct mgcp_conn_rtp *conn_rtp_src = mc->conn_src;
int rc = 0;
bool force_output_enabled = false;
bool prev_output_enabled;
struct osmo_sockaddr prev_rem_addr;
uint16_t prev_rem_rtp_port;
OSMO_ASSERT(mgcp_conn_rtp_is_iuup(conn_rtp_src));
if ((rc = check_rtp_iuup(conn_rtp_src, msg)) < 0)
goto free_ret;
if (!conn_rtp_src->iuup.configured) {
/* We received the first message without sending any, the peer is the active side (RNC). */
rc = _conn_iuup_configure_as_passive(conn_rtp_src);
if (rc < 0)
goto free_ret;
/* We need to force allowance of RTP containing Init-ACK back: */
prev_output_enabled = conn_rtp_src->end.output_enabled;
conn_rtp_src->end.output_enabled = true;
force_output_enabled = true;
/* Fill in the peer address so that we can send Init-ACK back: */
prev_rem_addr = conn_rtp_src->end.addr;
prev_rem_rtp_port = conn_rtp_src->end.rtp_port;
conn_rtp_src->end.addr = *mc->from_addr;
conn_rtp_src->end.rtp_port = htons(osmo_sockaddr_port(&mc->from_addr->u.sa));
}
rc = _conn_iuup_rtp_pl_up(conn_rtp_src, msg);
if (force_output_enabled) {
conn_rtp_src->end.output_enabled = prev_output_enabled;
conn_rtp_src->end.addr = prev_rem_addr;
conn_rtp_src->end.rtp_port = prev_rem_rtp_port;
}
return rc;
free_ret:
msgb_free(msg);
return rc;
}
/* Build IuUP RNL Data primitive from msg containing an incoming RTP pkt from
* peer and send it down the IuUP layer towards the destination as IuUP/RTP: */
int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg)
{
struct osmo_iuup_rnl_prim *irp;
struct rtp_hdr *rtph;
int rc = -1;
int iuup_length = 0;
int8_t rfci;
/* Tx RNL-DATA.req */
rtph = (struct rtp_hdr *)msgb_data(msg);
msgb_pull(msg, sizeof(*rtph));
/* FIXME: validate amr packets */
irp = osmo_iuup_rnl_prim_alloc(conn_dest_rtp->conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
irp->u.data.frame_nr = htons(rtph->sequence) % 16;
/* TODO: CMR handling & multiple frames handling */
if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) {
LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR,
"Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n",
conn_src_rtp->end.codec->subtype_name);
goto free_ret;
}
if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg);
if (msgb_length(msg) < (sizeof(*amr_hdr))) {
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
"Bridge RTP=>IuUP: too short for AMR OA hdr (%u)\n", msgb_length(msg));
goto free_ret;
}
if (amr_hdr->ft >= AMR_FT_MAX) {
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR OA ft=%u\n", amr_hdr->ft);
goto free_ret;
}
if ((rfci = _conn_iuup_amr_ft_2_rfci(conn_dest_rtp, amr_hdr->ft)) < 0) {
LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR OA ft=%u\n", amr_hdr->ft);
goto free_ret;
}
irp->u.data.fqc = amr_hdr->q;
irp->u.data.rfci = rfci;
msgb_pull(msg, 2);
} else {
uint8_t *amr_bwe_hdr = (uint8_t *) msgb_data(msg);
int8_t ft;
if (msgb_length(msg) < 2) {
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
"Bridge RTP=>IuUP: too short for AMR BE hdr (%u)\n", msgb_length(msg));
goto free_ret;
}
ft = ((amr_bwe_hdr[0] & 0x07) << 1) | ((amr_bwe_hdr[1] & 0x80) >> 7);
if (ft >= AMR_FT_MAX) {
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR BE ft=%u\n", ft);
goto free_ret;
}
if ((rfci = _conn_iuup_amr_ft_2_rfci(conn_dest_rtp, ft)) < 0) {
LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR BE ft=%u\n", ft);
goto free_ret;
}
irp->u.data.fqc = ((amr_bwe_hdr[1] & 0x40) >> 6);
irp->u.data.rfci = rfci;
rc = iuup_length = osmo_amr_bwe_to_iuup(msgb_data(msg), msgb_length(msg));
if (rc < 0) {
LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Bridge RTP=>IuUP: Failed convert the RTP/AMR to IuUP payload\n");
return rc;
}
msgb_trim(msg, iuup_length);
}
irp->oph.msg->l3h = msgb_put(irp->oph.msg, msgb_length(msg));
memcpy(irp->oph.msg->l3h, msgb_data(msg), msgb_length(msg));
if ((rc = osmo_iuup_rnl_prim_down(conn_dest_rtp->iuup.iui, irp)) != 0)
LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Bridge RTP=>IuUP: Failed Tx RTP payload down the IuUP layer\n");
return rc;
free_ret:
msgb_free(irp->oph.msg);
return -1;
}
/* Build IuUP RNL Data primitive from msg containing dummy content and send it
* down the IuUP layer towards the destination as IuUP/RTP: */
int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp)
{
struct osmo_iuup_rnl_prim *irp;
int rc;
if (conn_rtp->iuup.rfci_idx_no_data == -1) {
LOG_CONN_RTP(conn_rtp, LOGL_NOTICE, "No RFCI NO_DATA found, unable to send dummy packet\n");
return -ENOTSUP;
}
irp = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
irp->u.data.frame_nr = 0;
irp->u.data.fqc = IUUP_FQC_FRAME_GOOD;
irp->u.data.rfci = conn_rtp->iuup.rfci_idx_no_data;
irp->oph.msg->l3h = irp->oph.msg->tail;
if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp)) != 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed Tx RTP dummy payload down the IuUP layer\n");
return -EINVAL;
}
return 0;
}

View File

@@ -110,7 +110,8 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
/* Special handling for RTP connections */
if (conn->type == MGCP_CONN_TYPE_RTP) {
conn->u.rtp.end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
conn->u.rtp.end.output_enabled =
conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
}
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
@@ -120,7 +121,7 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
/* Special handling für RTP connections */
if (conn->type == MGCP_CONN_TYPE_RTP) {
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %d\n",
conn->u.rtp.end.output_enabled);
}

View File

@@ -48,7 +48,7 @@
#include <osmocom/mgcp/debug.h>
#include <osmocom/codec/codec.h>
#include <osmocom/mgcp/mgcp_e1.h>
#include <osmocom/mgcp/mgcp_iuup.h>
#define RTP_SEQ_MOD (1 << 16)
#define RTP_MAX_DROPOUT 3000
@@ -59,7 +59,7 @@ enum rtp_proto {
MGCP_PROTO_RTCP,
};
void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
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;
@@ -156,7 +156,7 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
/* This does not need to be a precision timestamp and
* is allowed to wrap quite fast. The returned value is
* 1/codec_rate seconds. */
uint32_t mgcp_get_current_ts(unsigned codec_rate)
static uint32_t get_current_ts(unsigned codec_rate)
{
struct timespec tp;
uint64_t ret;
@@ -529,7 +529,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
seq = ntohs(rtp_hdr->sequence);
timestamp = ntohl(rtp_hdr->timestamp);
arrival_time = mgcp_get_current_ts(rtp_end->codec->rate);
arrival_time = get_current_ts(rtp_end->codec->rate);
ssrc = ntohl(rtp_hdr->ssrc);
marker_bit = !!rtp_hdr->marker;
transit = arrival_time - timestamp;
@@ -789,7 +789,7 @@ 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 */
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
static void forward_data(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
{
int rc;
@@ -815,7 +815,7 @@ static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,
hdr->version = 2;
hdr->payload_type = rtp_end->codec->payload_type;
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
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;
}
@@ -975,7 +975,7 @@ static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
* the length is because we currently handle IUUP packets as RTP
* packets, so they must pass this check, if we weould be more
* strict here, we would possibly break 3G. (see also FIXME note
* below.*/
* below */
return 0;
}
@@ -1013,19 +1013,6 @@ static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
"endpoint type is MGCP_OSMUX_BSC_NAT, "
"using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
return osmux_xfrm_to_osmux((char*)msgb_data(msg), msgb_length(msg), conn_dst);
case MGCP_RTP_IUUP:
if (proto == MGCP_PROTO_RTP) {
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"endpoint type is MGCP_RTP_IUUP, "
"using mgcp_conn_iuup_send_rtp() to forward data over IuUP\n");
return mgcp_conn_iuup_send_rtp(conn_src, conn_dst, msg);
}
/* RTCP: we forward as usual for regular RTP connection */
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"endpoint type is MGCP_RTP_IUUP and proto!=MGCP_PROTO_RTP, "
"using mgcp_send() to forward data directly\n");
return mgcp_send(endp, false,
mc->from_addr, msg, conn_src, conn_dst);
}
/* If the data has not been handled/forwarded until here, it will
@@ -1086,11 +1073,8 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
if (check_rtp_destin(conn) != 0)
goto failed;
if (mgcp_conn_rtp_is_iuup(conn))
rc = mgcp_conn_iuup_send_dummy(conn);
else
rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr, conn->end.rtp_port,
rtp_dummy_payload, sizeof(rtp_dummy_payload));
rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
conn->end.rtp_port, rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc == -1)
goto failed;
@@ -1154,7 +1138,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
* course unable to patch the payload type. A situation like this
* should not occur if transcoding is consequently avoided. Until
* we have transcoding support in osmo-mgw we can not resolve this. */
if (is_rtp && conn_dst->type != MGCP_RTP_IUUP) {
if (is_rtp) {
rc = mgcp_patch_pt(conn_src, conn_dst, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_DEBUG,
@@ -1201,9 +1185,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
mgcp_patch_and_count(endp, rtp_state, rtp_end,
addr, msg);
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg,
conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
@@ -1229,9 +1211,27 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
);
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
/* FIXME: HACK HACK HACK. See OS#2459.
* The ip.access nano3G needs the first RTP payload's first two bytes to read hex
* 'e400', or it will reject the RAB assignment. It seems to not harm other femto
* cells (as long as we patch only the first RTP payload in each stream).
*/
if (!rtp_state->patched_first_rtp_payload
&& conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
uint8_t *data = msgb_data(msg) + 12;
if (data[0] == 0xe0) {
data[0] = 0xe4;
data[1] = 0x00;
rtp_state->patched_first_rtp_payload = true;
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"Patching over first two bytes"
" to fake an IuUP Initialization Ack\n");
}
}
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
(char *)msgb_data(msg), msgb_length(msg));
@@ -1291,9 +1291,6 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
* destination connection is known the RTP packet is sent via
* the destination connection. */
/* If source is IuUP, we need to handle state, forward it through specific bridge path: */
if (mgcp_conn_rtp_is_iuup(conn_src) && mc->proto == MGCP_PROTO_RTP)
return mgcp_conn_iuup_dispatch_rtp(msg);
/* Check if the connection is in loopback mode, if yes, just send the
* incoming data back to the origin */
@@ -1471,7 +1468,7 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
msgb_put(msg, ret);
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
proto == MGCP_PROTO_RTP ? "RTP" : "RTCP",
proto == MGCP_PROTO_RTP ? "RTP" : "RTPC",
msgb_length(msg), osmo_sockaddr_ntop(&addr.u.sa, ipbuf),
osmo_sockaddr_port(&addr.u.sa));
@@ -1509,7 +1506,7 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
/* 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_tap(fd->fd, &conn_src->tap_in, msg);
forward_data(fd->fd, &conn_src->tap_in, msg);
rc = rx_rtp(msg);
@@ -1518,7 +1515,6 @@ out:
return rc;
}
/* Note: This function is able to handle RTP and RTCP */
static int rx_rtp(struct msgb *msg)
{
struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
@@ -1535,8 +1531,7 @@ static int rx_rtp(struct msgb *msg)
* framing mode (octet-aligned vs. bandwith-efficient is explicitly
* define, then we check if the incoming payload matches that
* expectation. */
if (mc->proto == MGCP_PROTO_RTP &&
amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
if (oa < 0)
return -1;

View File

@@ -46,7 +46,6 @@
#include <osmocom/mgcp/mgcp_sdp.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_iuup.h>
/* Contains the last successfully resolved endpoint name. This variable is used
* for the unit-tests to verify that the endpoint was correctly resolved. */
@@ -148,13 +147,7 @@ static int setup_rtp_processing(struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn_dst = conn;
struct mgcp_conn *_conn;
switch (conn->type) {
case MGCP_RTP_DEFAULT:
case MGCP_OSMUX_BSC:
case MGCP_OSMUX_BSC_NAT:
case MGCP_RTP_IUUP:
break;
default:
if (conn->type != MGCP_RTP_DEFAULT && !mgcp_conn_rtp_is_osmux(conn)) {
LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
"RTP-setup: Endpoint is not configured as RTP default, stopping here!\n");
return 0;
@@ -1035,11 +1028,6 @@ mgcp_header_done:
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CODEC_NEGOTIATION));
goto error2;
}
/* Upgrade the conn type RTP_DEFAULT->RTP_IUUP if needed based on requested codec: */
/* TODO: "codec" probably needs to be moved from endp to conn */
if (conn->type == MGCP_RTP_DEFAULT && strcmp(conn->end.codec->subtype_name, "VND.3GPP.IUFP") == 0) {
rc = mgcp_conn_iuup_init(conn);
}
conn->end.fmtp_extra = talloc_strdup(trunk->endpoints,
trunk->audio_fmtp_extra);

View File

@@ -98,7 +98,7 @@ static void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
/* Helper function to update codec map information with additional data from
* SDP, called from: mgcp_parse_sdp_data() */
static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
int payload_type, const char *audio_name)
int payload, const char *audio_name)
{
int i;
@@ -110,7 +110,7 @@ static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
/* Note: We can only update payload codecs that already exist
* in our codec list. If we get an unexpected payload type,
* we just drop it */
if (codecs[i].payload_type != payload_type)
if (codecs[i].payload_type != payload)
continue;
if (sscanf(audio_name, "%63[^/]/%d/%d",
@@ -127,7 +127,7 @@ static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
return;
}
LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload_type,
LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload,
audio_name);
}
@@ -334,7 +334,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
void *tmp_ctx = talloc_new(NULL);
struct mgcp_rtp_end *rtp;
int payload_type;
int payload;
int ptime, ptime2 = 0;
char audio_name[64];
int port, rc;
@@ -355,8 +355,8 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
/* skip these SDP attributes */
break;
case 'a':
if (sscanf(line, "a=rtpmap:%d %63s", &payload_type, audio_name) == 2) {
codecs_update(tmp_ctx, codecs, codecs_used, payload_type, audio_name);
if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) {
codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
break;
}

View File

@@ -868,7 +868,7 @@ static void test_messages(void)
printf("Connection mode not set\n");
OSMO_ASSERT(conn->end.output_enabled
== !!(conn->conn->mode & MGCP_CONN_SEND_ONLY));
== (conn->conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0));
conn->conn->mode |= CONN_UNMODIFIED;