WIP: add IuuP support

Change-Id: I88cfc4fcbd6efa02a6d97a0c602caf9344c6c04d
This commit is contained in:
Alexander Couzens 2021-12-28 01:33:03 +01:00
parent 8a34e1a8f1
commit e6d7bb7388
8 changed files with 151 additions and 61 deletions

View File

@ -8,7 +8,11 @@
#define PTYPE_UNDEFINED (-1)
#include <stdbool.h>
struct mgcp_conn_rtp;
struct mgcp_codec_param;
struct mgcp_rtp_codec;
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
@ -17,3 +21,4 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
const char *subtype_name, unsigned int match_nr);
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);

View File

@ -99,6 +99,7 @@ struct mgcp_conn_rtp {
struct osmo_iuup_instance *iui;
bool active_init; /* true: Send IuUP Init */
bool first_rtp_pkt_received;
uint8_t frame_num; /* shouldn't this part of the IUUP layer? */
} iuup;
struct rate_ctr_group *rate_ctr_group;

View File

@ -29,4 +29,4 @@ 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_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);

View File

@ -38,6 +38,7 @@
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
@ -98,7 +99,7 @@ enum mgcp_codecs map_str_to_codec(const char *str)
codec_name = extract_codec_name(osmo_mgcpc_codec_names[i].str);
if (!codec_name)
continue;
if (strcmp(codec_name, str_buf) == 0)
if (strcasecmp(codec_name, str_buf) == 0)
return osmo_mgcpc_codec_names[i].value;
}

View File

@ -25,6 +25,7 @@
#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <errno.h>
#include <strings.h>
/* Helper function to dump codec information of a specified codec to a printable
* string, used by dump_codec_summary() */
@ -241,6 +242,8 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
codec->payload_type = 112;
else if (!strcmp(codec->subtype_name, "AMR-WB"))
codec->payload_type = 113;
else if (!strcasecmp(codec->subtype_name, "VND.3GPP.IuFP"))
codec->payload_type = 97;
}
/* If we could not determine a payload type we assume that
@ -355,7 +358,7 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
*
* https://tools.ietf.org/html/rfc4867
*/
static bool amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
{
if (!codec->param_present)
return false;
@ -379,7 +382,7 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
return false;
if (!strcmp(codec_a->subtype_name, "AMR")) {
if (amr_is_octet_aligned(codec_a) != amr_is_octet_aligned(codec_b))
if (mgcp_codec_amr_is_octet_aligned(codec_a) != mgcp_codec_amr_is_octet_aligned(codec_b))
return false;
}
@ -417,7 +420,7 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
if (!codec_src)
return -EINVAL;
/* Use the codec infrmation from the source and try to find the
/* Use the codec information 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

@ -14,8 +14,10 @@
#include <osmocom/gsm/iuup.h>
#include <osmocom/netif/amr.h>
#include <osmocom/netif/rtp.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_iuup.h>
#include <osmocom/mgcp/mgcp_endp.h>
@ -104,9 +106,16 @@ static int check_rtp_iuup(const struct mgcp_conn_rtp *conn_rtp, struct msgb *msg
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;
struct mgcp_conn *conn_src, *conn_dst;
struct mgcp_conn_rtp *conn_src_rtp, *conn_rtp_dst;
int rc;
uint8_t rfci, frame_nr, fqc;
int ft;
struct msgb *msg;
struct amr_hdr *amr_hdr;
uint8_t *amr_data;
ssize_t amr_length = 0;
struct rtp_hdr *rtp_hdr;
conn_dst = _find_dst_conn(conn_rtp_src->conn);
@ -138,6 +147,65 @@ static int _conn_iuup_rx_rnl_data(struct mgcp_conn_rtp *conn_rtp_src, struct osm
break;
case MGCP_RTP_DEFAULT:
/* FIXME: We probably need transcoding here?! Or at least look up AMR modes and translate to related RFCI */
rfci = irp->u.data.rfci;
frame_nr = irp->u.data.frame_nr;
fqc = irp->u.data.fqc;
msg = irp->oph.msg;
ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
if (ft < 0) {
/* FIXME LOGP */
return ft;
}
msgb_pull_to_l3(msg);
LOGP(DLMGCP, LOGL_ERROR, "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 {
if (msgb_tailroom(msg) < 2) {
/* FIXME not enought tailroom */
return -4;
}
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);
LOGP(DLMGCP, LOGL_ERROR, "Convert Iuup -> AMR bwe: amr[0] 0x%x 0x%x\n", amr_data[0], amr_data[1]);
amr_data[1] |= ((ft & 0x1) << 7) | (((!fqc) & 0x1) << 6);
LOGP(DLMGCP, LOGL_ERROR, "Convert Iuup -> AMR bwe: amr[0] 0x%x 0x%x\n", amr_data[0], amr_data[1]);
amr_length = (osmo_amr_bits(ft) + 10 + 7) / 8;
msgb_trim(msg, amr_length);
}
rtp_hdr = (struct rtp_hdr *) msgb_push(msg, sizeof(struct rtp_hdr));
*rtp_hdr = (struct rtp_hdr){
.csrc_count = 0,
.extension = 0,
.padding = 0,
.version = 0,
.payload_type = 0,
.marker = 0,
.sequence = 0,
.timestamp = 0,
.ssrc = 0
};
conn_src = _find_dst_conn(conn_dst);
if (conn_src)
conn_src_rtp = &conn_src->u.rtp;
else
conn_src_rtp = &conn_dst->u.rtp;
rc = mgcp_send(conn_dst->endp, 1,
NULL, msg, conn_src_rtp, conn_rtp_dst);
break;
case MGCP_OSMUX_BSC:
case MGCP_OSMUX_BSC_NAT:
default:
@ -222,7 +290,7 @@ static int _conn_iuup_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
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_rtp *conn_src_rtp = NULL, *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;
@ -230,6 +298,7 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
struct rtp_hdr *rtph;
struct osmo_sockaddr from_addr = {0}; /* FIXME: what to do with this one? */
OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST));
msg = oph->msg;
@ -242,8 +311,8 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
.csrc_count = 0,
.extension = 0,
.padding = 0,
.version = 2,
.payload_type = 96,
.version = 0,
.payload_type = conn_rtp_dst->end.codec->payload_type,
.marker = 0,
.sequence = 0,
.timestamp = 0,
@ -251,12 +320,20 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
};
/* TODO: mgcp_send_rtp() expects msg to have OSMO_RTP_MSG_CTX filled */
// struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
// how to handle an early init packet which need to be answered correct! */
/* The destination of the destination conn is the source conn, right? */
conn_src = _find_dst_conn(conn_dst);
if (conn_src)
conn_src_rtp = &conn_src->u.rtp;
else
conn_src_rtp = &conn_dst->u.rtp;
/* FIXME: set from_addr = NULL */
return mgcp_send(conn_dst->endp, 1,
&from_addr, msg, &conn_src->u.rtp, conn_rtp_dst);
&from_addr, msg, conn_src_rtp, conn_rtp_dst);
}
int mgcp_conn_iuup_init(struct mgcp_conn_rtp *conn_rtp)
@ -320,25 +397,49 @@ free_ret:
/* 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_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)
{
struct osmo_iuup_rnl_prim *irp;
struct rtp_hdr *rtph;
int rc;
struct amr_hdr *amr_hdr;
int rc = -1;
int iuup_length = 0;
/* Tx RNL-DATA.req */
rtph = (struct rtp_hdr *)msgb_data(msg);
msgb_pull(msg, sizeof(*rtph));
irp = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
/* 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);
/* FIXME: We probably need transcoding here?! Or at least look up AMR modes and translate to related RFCI */
irp->u.data.rfci = 0;
irp->u.data.frame_nr = rtph->sequence % 4;
irp->u.data.fqc = IUUP_FQC_FRAME_GOOD;
irp->u.data.frame_nr = htons(rtph->sequence) % 16;
if (msgb_length(msg) < (sizeof(struct amr_hdr))) {
return -1;
}
amr_hdr = (struct amr_hdr *) msgb_data(msg);
if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
/* FIXME: CMR handling & multiple frames handling */
irp->u.data.fqc = IUUP_FQC_FRAME_GOOD;
irp->u.data.rfci = amr_hdr->ft < 8 ? 0 : 1;
msgb_pull(msg, 2);
} else {
irp->u.data.fqc = amr_hdr->q;
irp->u.data.rfci = amr_hdr->ft < 8 ? 0 : 1;
rc = iuup_length = osmo_amr_bwe_to_iuup(msgb_data(msg), msgb_length(msg));
if (rc < 0) {
LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Failed convert the RTP/AMR to IuUP payload\n");
return rc;
}
msgb_trim(msg, iuup_length);
}
irp->oph.msg->l3h = msgb_put(irp->oph.msg, msgb_length(msg));
memcpy(irp->oph.msg->l3h, msgb_data(msg), msgb_length(msg));
if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp)) != 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed Tx RTP payload down the IuUP layer\n");
if ((rc = osmo_iuup_rnl_prim_down(conn_dest_rtp->iuup.iui, irp)) != 0) {
LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Failed Tx RTP payload down the IuUP layer\n");
return rc;
}

View File

@ -768,25 +768,6 @@ static bool amr_oa_bwe_convert_indicated(struct mgcp_rtp_codec *codec)
}
/* Return whether an RTP packet with AMR payload is in octet-aligned mode.
* Return 0 if in bandwidth-efficient mode, 1 for octet-aligned mode, and negative if the RTP data is invalid. */
static int amr_oa_check(char *data, int len)
{
struct rtp_hdr *rtp_hdr;
unsigned int payload_len;
if (len < sizeof(struct rtp_hdr))
return -EINVAL;
rtp_hdr = (struct rtp_hdr *)data;
payload_len = len - sizeof(struct rtp_hdr);
if (payload_len < sizeof(struct amr_hdr))
return -EINVAL;
return osmo_amr_is_oa(rtp_hdr->data, payload_len) ? 1 : 0;
}
/* Forward data to a debug tap. This is debug function that is intended for
* debugging the voice traffic with tools like gstreamer */
static void forward_data(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
@ -1018,7 +999,7 @@ static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
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_dst, msg);
return mgcp_conn_iuup_send_rtp(conn_src, conn_dst, msg);
}
/* If the data has not been handled/forwarded until here, it will
@ -1145,10 +1126,12 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
* should not occur if transcoding is consequently avoided. Until
* we have transcoding support in osmo-mgw we can not resolve this. */
if (is_rtp) {
rc = mgcp_patch_pt(conn_src, conn_dst, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"can not patch PT because no suitable egress codec was found.\n");
if (conn_dst->type != MGCP_RTP_IUUP) {
rc = mgcp_patch_pt(conn_src, conn_dst, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"can not patch PT because no suitable egress codec was found.\n");
}
}
}
@ -1191,7 +1174,9 @@ 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 (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg,
conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
@ -1279,10 +1264,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 rhough specific bridge: */
if (mgcp_conn_rtp_is_iuup(conn_src))
return mgcp_conn_iuup_dispatch_rtp(msg);
/* Check if the connection is in loopback mode, if yes, just send the
* incoming data back to the origin */
if (conn->mode == MGCP_CONN_LOOPBACK) {
@ -1308,9 +1289,18 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
conn->u.rtp.end.rtp_port);
}
/* If source is IuUP, we need to handle state, forward it rhough specific bridge: */
if (mgcp_conn_rtp_is_iuup(conn_src))
return mgcp_conn_iuup_dispatch_rtp(msg);
return mgcp_send_rtp(conn_src, msg);
}
/* If source is IuUP, we need to handle state, forward it rhough specific bridge: */
if (mgcp_conn_rtp_is_iuup(conn_src))
return mgcp_conn_iuup_dispatch_rtp(msg);
/* Find a destination connection. */
/* NOTE: This code path runs every time an RTP packet is received. The
* function mgcp_find_dst_conn() we use to determine the detination
@ -1518,18 +1508,6 @@ static int rx_rtp(struct msgb *msg)
mgcp_conn_watchdog_kick(conn_src->conn);
/* If AMR is configured for the ingress connection a conversion of the
* framing mode (octet-aligned vs. bandwith-efficient is explicitly
* define, then we check if the incoming payload matches that
* expectation. */
if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
if (oa < 0)
return -1;
if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned)
return -1;
}
/* Check if the origin of the RTP packet seems plausible */
if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
return -1;

View File

@ -29,6 +29,7 @@
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <strings.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
@ -1031,7 +1032,7 @@ mgcp_header_done:
}
/* 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) {
if (conn->type == MGCP_RTP_DEFAULT && strcasecmp(conn->end.codec->subtype_name, "VND.3GPP.IuFP") == 0) {
rc = mgcp_conn_iuup_init(conn);
}