mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-10-23 08:12:01 +00:00
Compare commits
1 Commits
master
...
rhizomatic
Author | SHA1 | Date | |
---|---|---|---|
|
4dde3b6873 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,8 +8,6 @@ Makefile
|
||||
Makefile.in
|
||||
bscconfig.h
|
||||
bscconfig.h.in
|
||||
include/osmocom/mgcp_client/mgcp_common.h
|
||||
include/osmocom/mgcp_client/version.h
|
||||
src/osmo-mgw/osmo-mgw
|
||||
*.*~
|
||||
*.sw?
|
||||
|
@@ -9,4 +9,3 @@
|
||||
#library what description / commit summary line
|
||||
libosmocore bump_dep; workaround Bump libosmocore version dependency after I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5
|
||||
has been merged to libosmocore.git; then remove my_msgb_copy_c wrapper function.
|
||||
libosmocodec bump_dep We depend on the additions of I2c510ac62a0786c137115c45eee7a48b9736265f
|
||||
|
@@ -45,7 +45,6 @@ AC_SUBST(LIBRARY_DLSYM)
|
||||
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec >= 1.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.11.0)
|
||||
|
9
debian/control
vendored
9
debian/control
vendored
@@ -9,7 +9,6 @@ Build-Depends: debhelper (>= 10),
|
||||
libosmocore-dev (>= 1.11.0),
|
||||
libosmo-netif-dev (>= 1.6.0),
|
||||
libosmo-abis-dev (>= 2.0.0),
|
||||
osmo-gsm-manuals-dev (>= 1.6.0)
|
||||
Standards-Version: 3.9.8
|
||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
|
||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
|
||||
@@ -36,11 +35,3 @@ Multi-Arch: same
|
||||
Depends: libosmo-mgcp-client14 (= ${binary:Version}), ${misc:Depends}
|
||||
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
|
||||
|
||||
Package: osmo-mgw-doc
|
||||
Architecture: all
|
||||
Section: doc
|
||||
Priority: optional
|
||||
Depends: ${misc:Depends}
|
||||
Description: ${misc:Package} PDF documentation
|
||||
Various manuals: user manual, VTY reference manual and/or
|
||||
protocol/interface manuals.
|
||||
|
2
debian/rules
vendored
2
debian/rules
vendored
@@ -30,7 +30,7 @@ override_dh_auto_test:
|
||||
dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
|
||||
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system
|
||||
|
||||
# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
|
||||
override_dh_compress:
|
||||
|
@@ -70,85 +70,3 @@ a=ptime:40
|
||||
=== `X-Osmux`
|
||||
|
||||
See <<mgcp-extension-osmux>>
|
||||
|
||||
=== Non-standard SDP codec parameters
|
||||
|
||||
CRCX command message normally includes an SDP block that specifies the RTP
|
||||
address of the connecting peer and the list of codecs accepted by that entity.
|
||||
Codec specifications may include optional parameters given via `a=fmtp` lines;
|
||||
one well-known parameter is `octet-align`, defined for AMR and AMR-WB codecs.
|
||||
|
||||
In addition to standard (RFC-defined) codec parameters (of which the
|
||||
just-mentioned `octet-align` parameter is the only one implemented so far),
|
||||
OsmoMGW also understands some non-standard (Osmocom-private) codec parameters
|
||||
as listed below.
|
||||
These Osmocom-private codec parameters are meaningful only in the context
|
||||
of OsmoBSC driving an E1 Abis MGW, which may be either OsmoMGW or a specialized
|
||||
third-party replacement.
|
||||
|
||||
The MGCP extension described in this section is meaningful only for E1
|
||||
endpoints - it has absolutely no effect on `rtpbridge` endpoints!
|
||||
|
||||
==== `tw-ts-001` parameter for FR and EFR codecs
|
||||
|
||||
GSM Full Rate codec is known in SDP as `GSM`; GSM Enhanced Full Rate codec
|
||||
is known in SDP as `GSM-EFR`.
|
||||
When either codec is to be transported in RTP, there is a choice between
|
||||
two different payload formats: RFC 3551 or TW-TS-001.
|
||||
RFC 3551 is the standard in non-GSM Internet applications, and it is the
|
||||
format specified in later 3GPP releases for IP-based transport of
|
||||
compressed speech - however, it exhibits functional regressions compared
|
||||
to the original TRAU-UL frame format of GSM 08.60.
|
||||
TW-TS-001 is an enhanced alternative payload format for the same codecs
|
||||
that restores the original functionality and semantics of TRAU-UL frames.
|
||||
|
||||
In the context of CRCX or MDCX command messages from OsmoBSC to an E1 Abis MGW,
|
||||
`tw-ts-001` codec parameter (attached to either `GSM` or `GSM-EFR` codec)
|
||||
instructs the MGW whether or not it should emit the extended payload format
|
||||
of TW-TS-001 for GSM uplink traffic converted to RTP.
|
||||
In the absence of this parameter, IETF-standard and 3GPP-standard RFC 3551
|
||||
format is emitted; if TW-TS-001 output is desired, please specify
|
||||
`tw-ts-001=1` on the appropriate `a=fmtp` line.
|
||||
|
||||
.Example: `CRCX` message requesting EFR codec with TW-TS-001 extensions
|
||||
----
|
||||
CRCX 2 ds/e1-0/s-2/su16-2@mgw MGCP 1.0
|
||||
M: recvonly
|
||||
C: 2
|
||||
L: p:20
|
||||
|
||||
v=0
|
||||
c=IN IP4 123.12.12.123
|
||||
m=audio 1234 RTP/AVP 110
|
||||
a=rtpmap:110 GSM-EFR/8000/1
|
||||
a=fmtp:110 tw-ts-001=1
|
||||
----
|
||||
|
||||
==== `tw-ts-002` parameter for HR codec
|
||||
|
||||
GSM Half Rate codec is known in SDP as `GSM-HR-08`.
|
||||
The same dichotomy that exists between RFC 3551 and TW-TS-001 RTP payload
|
||||
formats for FR and EFR codecs also exists for HR codec, except that
|
||||
the two opposing alternatives are now RFC 5993 and TW-TS-002.
|
||||
|
||||
In the context of CRCX or MDCX command messages from OsmoBSC to an E1 Abis MGW,
|
||||
`tw-ts-002` codec parameter (attached to `GSM-HR-08` codec)
|
||||
instructs the MGW whether or not it should emit the extended payload format
|
||||
of TW-TS-002 for GSM uplink traffic converted to RTP.
|
||||
In the absence of this parameter, IETF-standard and 3GPP-standard RFC 5993
|
||||
format is emitted; if TW-TS-002 output is desired, please specify
|
||||
`tw-ts-002=1` on the appropriate `a=fmtp` line.
|
||||
|
||||
.Example: `CRCX` message requesting HR codec with TW-TS-002 extensions
|
||||
----
|
||||
CRCX 2 ds/e1-0/s-2/su8-2@mgw MGCP 1.0
|
||||
M: recvonly
|
||||
C: 2
|
||||
L: p:20
|
||||
|
||||
v=0
|
||||
c=IN IP4 123.12.12.123
|
||||
m=audio 1234 RTP/AVP 111
|
||||
a=rtpmap:111 GSM-HR-08/8000/1
|
||||
a=fmtp:111 tw-ts-002=1
|
||||
----
|
||||
|
@@ -40,8 +40,6 @@
|
||||
|
||||
#include "mgcp_ratectr.h"
|
||||
|
||||
extern void *tall_mgw_ctx;
|
||||
|
||||
#define RTP_PORT_DEFAULT_RANGE_START 16002
|
||||
#define RTP_PORT_DEFAULT_RANGE_END RTP_PORT_DEFAULT_RANGE_START + 64
|
||||
|
||||
@@ -52,6 +50,11 @@ struct mgcp_endpoint;
|
||||
struct mgcp_config;
|
||||
struct mgcp_trunk;
|
||||
struct mgcp_rtp_end;
|
||||
|
||||
#define MGCP_ENDP_CRCX 1
|
||||
#define MGCP_ENDP_DLCX 2
|
||||
#define MGCP_ENDP_MDCX 3
|
||||
|
||||
/*
|
||||
* what to do with the msg?
|
||||
* - continue as usual?
|
||||
@@ -130,6 +133,10 @@ struct mgcp_config {
|
||||
char source_addr[INET6_ADDRSTRLEN];
|
||||
char call_agent_addr[INET6_ADDRSTRLEN];
|
||||
|
||||
/* RTP processing */
|
||||
mgcp_processing rtp_processing_cb;
|
||||
mgcp_processing_setup setup_rtp_processing_cb;
|
||||
|
||||
struct osmo_wqueue gw_fd;
|
||||
|
||||
struct mgcp_port_range net_ports;
|
||||
|
@@ -63,10 +63,6 @@ enum mgcp_x_osmo_ign {
|
||||
struct mgcp_codec_param {
|
||||
bool amr_octet_aligned_present;
|
||||
bool amr_octet_aligned;
|
||||
bool fr_efr_twts001_present;
|
||||
bool fr_efr_twts001;
|
||||
bool hr_twts002_present;
|
||||
bool hr_twts002;
|
||||
};
|
||||
|
||||
/* Ensure that the msg->l2h is NUL terminated. */
|
||||
|
@@ -22,6 +22,6 @@ static const uint8_t e1_rates[] = { 64, 32, 32, 16, 16, 16, 16, 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_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
|
||||
int mgcp_e1_endp_update(struct mgcp_endpoint *endp);
|
||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
|
||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts);
|
||||
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);
|
||||
|
@@ -124,7 +124,6 @@ struct mgcp_endpoint {
|
||||
struct osmo_fsm_inst *trau_sync_fi;
|
||||
struct osmo_trau2rtp_state *trau_rtp_st;
|
||||
uint8_t last_amr_ft;
|
||||
uint8_t rtp_extensions;
|
||||
struct mgcp_rtp_codec *last_codec;
|
||||
} e1;
|
||||
|
||||
@@ -132,7 +131,7 @@ struct mgcp_endpoint {
|
||||
|
||||
struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
|
||||
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
|
||||
int mgcp_endp_update(struct mgcp_endpoint *endp, struct mgcp_conn *conn, enum mgcp_verb verb);
|
||||
void mgcp_endp_update(struct mgcp_endpoint *endp);
|
||||
bool mgcp_endp_is_wildcarded(const char *epname);
|
||||
bool mgcp_endp_is_null(const char *epname);
|
||||
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
|
||||
@@ -150,7 +149,6 @@ void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
|
||||
const struct mgcp_trunk *trunk);
|
||||
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
|
||||
const struct mgcp_trunk *trunk);
|
||||
void mgcp_endp_update_lco(struct mgcp_endpoint *endp, const struct mgcp_lco *lco);
|
||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
|
||||
|
||||
struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id);
|
||||
|
@@ -31,4 +31,3 @@ 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);
|
||||
int mgcp_conn_iuup_event_rx_crcx_mdcx(struct mgcp_conn_rtp *conn_rtp);
|
||||
|
@@ -98,6 +98,18 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
|
||||
struct osmo_sockaddr *addr, struct msgb *msg);
|
||||
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
|
||||
|
||||
/* payload processing default functions */
|
||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct msgb *msg);
|
||||
|
||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||
struct mgcp_conn_rtp *conn_dst,
|
||||
struct mgcp_conn_rtp *conn_src);
|
||||
|
||||
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
|
||||
const struct mgcp_rtp_codec **codec,
|
||||
const char **fmtp_extra,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
|
||||
/* internal RTP Annex A counting */
|
||||
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
|
||||
const uint16_t seq, const int32_t transit,
|
||||
|
@@ -8,18 +8,6 @@
|
||||
#include <osmocom/mgcp/mgcp_common.h>
|
||||
#include <osmocom/mgcp/mgcp_codec.h>
|
||||
|
||||
enum mgcp_verb {
|
||||
MGCP_VERB_CRCX,
|
||||
MGCP_VERB_MDCX,
|
||||
MGCP_VERB_DLCX,
|
||||
MGCP_VERB_AUEP,
|
||||
MGCP_VERB_RQNT,
|
||||
MGCP_VERB_RSIP,
|
||||
};
|
||||
extern const struct value_string mgcp_verb_names[];
|
||||
static inline const char *mgcp_verb_name(enum mgcp_verb val)
|
||||
{ return get_value_string(mgcp_verb_names, val); }
|
||||
|
||||
|
||||
#define MGCP_PARSE_SDP_PTIME_UNSET (-1)
|
||||
#define MGCP_PARSE_SDP_MAXPTIME_UNSET (-1)
|
||||
@@ -42,26 +30,12 @@ static inline void mgcp_parse_sdp_init(struct mgcp_parse_sdp *sdp)
|
||||
mgcp_codecset_reset(&sdp->cset);
|
||||
}
|
||||
|
||||
/* Local connection options */
|
||||
struct mgcp_lco {
|
||||
bool present;
|
||||
char *codec; /* talloc-allocated to some parent */
|
||||
int pkt_period_min; /* time in ms */
|
||||
int pkt_period_max; /* time in ms */
|
||||
};
|
||||
static inline void mgcp_lco_init(struct mgcp_lco *lco)
|
||||
{
|
||||
*lco = (struct mgcp_lco){};
|
||||
}
|
||||
char *get_lco_identifier(const char *options);
|
||||
int check_local_cx_options(void *ctx, const char *options);
|
||||
|
||||
#define MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET (-2)
|
||||
#define MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD (-1)
|
||||
|
||||
struct mgcp_parse_hdr_pars {
|
||||
const char *lco_string;
|
||||
struct mgcp_lco lco;
|
||||
const char *local_options;
|
||||
const char *callid;
|
||||
const char *connid;
|
||||
enum mgcp_connection_mode mode;
|
||||
@@ -73,20 +47,20 @@ struct mgcp_parse_hdr_pars {
|
||||
|
||||
static inline void mgcp_parse_hdr_pars_init(struct mgcp_parse_hdr_pars *hpars)
|
||||
{
|
||||
hpars->lco_string = NULL;
|
||||
mgcp_lco_init(&hpars->lco);
|
||||
hpars->callid = NULL;
|
||||
hpars->connid = NULL;
|
||||
hpars->mode = MGCP_CONN_NONE;
|
||||
hpars->remote_osmux_cid = MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
|
||||
hpars->have_sdp = false;
|
||||
hpars->x_osmo_ign = 0;
|
||||
*hpars = (struct mgcp_parse_hdr_pars){
|
||||
.local_options = NULL,
|
||||
.callid = NULL,
|
||||
.connid = NULL,
|
||||
.mode = MGCP_CONN_NONE,
|
||||
.remote_osmux_cid = MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET,
|
||||
.have_sdp = false,
|
||||
.x_osmo_ign = 0,
|
||||
};
|
||||
}
|
||||
|
||||
/* Internal structure while parsing a request */
|
||||
struct mgcp_request_data;
|
||||
struct mgcp_parse_data {
|
||||
struct mgcp_request_data *rq; /* backpointer to request context */
|
||||
struct mgcp_config *cfg;
|
||||
char *save;
|
||||
/* MGCP Header: */
|
||||
char *epname;
|
||||
@@ -96,36 +70,18 @@ struct mgcp_parse_data {
|
||||
struct mgcp_parse_sdp sdp;
|
||||
};
|
||||
|
||||
/* Request data passed to the request handler */
|
||||
struct mgcp_request_data {
|
||||
enum mgcp_verb verb;
|
||||
/* Verb string (e.g. "MDCX") */
|
||||
char name[4+1];
|
||||
|
||||
/* Global MGW config */
|
||||
struct mgcp_config *cfg;
|
||||
|
||||
/* parsing results from the MGCP header (trans id, endpoint name ...) */
|
||||
struct mgcp_parse_data *pdata;
|
||||
|
||||
/* pointer to endpoint resource (may be NULL for wildcarded requests) */
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
/* pointer to trunk resource */
|
||||
struct mgcp_trunk *trunk;
|
||||
|
||||
/* set to true when the request has been classified as wildcarded */
|
||||
bool wildcarded;
|
||||
|
||||
/* Set to true when the request is targeted at the "null" endpoint */
|
||||
bool null_endp;
|
||||
|
||||
/* contains cause code in case of problems during endp/trunk resolution */
|
||||
int mgcp_cause;
|
||||
/* Local connection options */
|
||||
struct mgcp_lco {
|
||||
char *string;
|
||||
char *codec;
|
||||
int pkt_period_min; /* time in ms */
|
||||
int pkt_period_max; /* time in ms */
|
||||
};
|
||||
|
||||
char *mgcp_debug_get_last_endpoint_name(void);
|
||||
|
||||
char *get_lco_identifier(const char *options);
|
||||
int check_local_cx_options(void *ctx, const char *options);
|
||||
|
||||
struct mgcp_rtp_end;
|
||||
struct mgcp_endpoint;
|
||||
|
@@ -43,7 +43,7 @@ enum {
|
||||
MGCP_MDCX_FAIL_INVALID_MODE,
|
||||
MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
|
||||
MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
|
||||
MGCP_MDCX_FAIL_BIND_PORT,
|
||||
MGCP_MDCX_FAIL_START_RTP,
|
||||
MGCP_MDCX_FAIL_AVAIL,
|
||||
};
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
BUILT_SOURCES = \
|
||||
mgcp_common.h \
|
||||
version.h \
|
||||
$(NULL)
|
||||
|
||||
noinst_HEADERS = \
|
||||
@@ -12,20 +11,4 @@ mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h
|
||||
echo -e "/*\n\n DO NOT EDIT THIS FILE!\n THIS IS OVERWRITTEN DURING BUILD\n This is an automatic copy of <osmocom/mgcp/mgcp_common.h>\n\n */" > mgcp_common.h
|
||||
cat $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h >> mgcp_common.h
|
||||
|
||||
version.h: version.h.tpl
|
||||
$(AM_V_GEN)$(MKDIR_P) $(dir $@)
|
||||
$(AM_V_GEN)sed \
|
||||
-e "s/{{VERSION}}/$$(echo '@VERSION@' | cut -d. -f1-3)/g" \
|
||||
-e "s/{{VERSION_MAJOR}}/$$(echo '@VERSION@' | cut -d. -f1)/g" \
|
||||
-e "s/{{VERSION_MINOR}}/$$(echo '@VERSION@' | cut -d. -f2)/g" \
|
||||
-e "s/{{VERSION_PATCH}}/$$(echo '@VERSION@' | cut -d. -f3)/g" \
|
||||
$< > $@
|
||||
|
||||
EXTRA_DIST = \
|
||||
version.h.tpl \
|
||||
$(NULL)
|
||||
|
||||
CLEANFILES = \
|
||||
mgcp_common.h \
|
||||
version.h \
|
||||
$(NULL)
|
||||
CLEANFILES = mgcp_common.h
|
||||
|
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define LIBOSMO_MGCP_CLIENT_VERSION {{VERSION}}
|
||||
#define LIBOSMO_MGCP_CLIENT_VERSION_STR "{{VERSION}}"
|
||||
|
||||
#define LIBOSMO_MGCP_CLIENT_VERSION_MAJOR {{VERSION_MAJOR}}
|
||||
#define LIBOSMO_MGCP_CLIENT_VERSION_MINOR {{VERSION_MINOR}}
|
||||
#define LIBOSMO_MGCP_CLIENT_VERSION_PATCH {{VERSION_PATCH}}
|
||||
|
||||
#define LIBOSMO_MGCP_CLIENT_VERSION_GREATER_EQUAL(major, minor, patch) \
|
||||
(LIBOSMO_MGCP_CLIENT_VERSION_MAJOR > (major) || \
|
||||
(LIBOSMO_MGCP_CLIENT_VERSION_MAJOR == (major) && \
|
||||
LIBOSMO_MGCP_CLIENT_VERSION_MINOR > (minor)) || \
|
||||
(LIBOSMO_MGCP_CLIENT_VERSION_MAJOR == (major) && \
|
||||
LIBOSMO_MGCP_CLIENT_VERSION_MINOR == (minor) && \
|
||||
LIBOSMO_MGCP_CLIENT_VERSION_PATCH >= (patch)))
|
@@ -1426,32 +1426,15 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
|
||||
/* Add optional codec parameters (fmtp) */
|
||||
if (mgcp_msg->param_present) {
|
||||
for (i = 0; i < mgcp_msg->ptmap_len; i++) {
|
||||
/* The following is only applicable for AMR */
|
||||
if (mgcp_msg->ptmap[i].codec != CODEC_AMR_8000_1
|
||||
&& mgcp_msg->ptmap[i].codec != CODEC_AMRWB_16000_1)
|
||||
continue;
|
||||
pt = mgcp_msg->ptmap[i].pt;
|
||||
switch (mgcp_msg->ptmap[i].codec) {
|
||||
case CODEC_AMR_8000_1:
|
||||
case CODEC_AMRWB_16000_1:
|
||||
if (!mgcp_msg->param.amr_octet_aligned_present)
|
||||
break;
|
||||
MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=%d\r\n",
|
||||
pt, (int)mgcp_msg->param.amr_octet_aligned);
|
||||
break;
|
||||
case CODEC_GSM_8000_1:
|
||||
case CODEC_GSMEFR_8000_1:
|
||||
if (!mgcp_msg->param.fr_efr_twts001_present)
|
||||
break;
|
||||
MSGB_PRINTF_OR_RET("a=fmtp:%u tw-ts-001=%d\r\n",
|
||||
pt, (int)mgcp_msg->param.fr_efr_twts001);
|
||||
break;
|
||||
case CODEC_GSMHR_8000_1:
|
||||
if (!mgcp_msg->param.hr_twts002_present)
|
||||
break;
|
||||
MSGB_PRINTF_OR_RET("a=fmtp:%u tw-ts-002=%d\r\n",
|
||||
pt, (int)mgcp_msg->param.hr_twts002);
|
||||
break;
|
||||
default:
|
||||
/* no parameters for the remaining codecs */
|
||||
break;
|
||||
}
|
||||
if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
|
||||
MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=1\r\n", pt);
|
||||
else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
|
||||
MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=0\r\n", pt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,6 @@ AM_CPPFLAGS = \
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOCODEC_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMONETIF_CFLAGS) \
|
||||
|
@@ -40,7 +40,6 @@
|
||||
#include <osmocom/mgcp/debug.h>
|
||||
#include <osmocom/mgcp/mgcp_e1.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
#include <osmocom/gsm/rtp_extensions.h>
|
||||
|
||||
#define DEBUG_BITS_MAX 80
|
||||
#define DEBUG_BYTES_MAX 40
|
||||
@@ -57,6 +56,149 @@ static const struct e1inp_line_ops dummy_e1_line_ops = {
|
||||
.sign_link = NULL,
|
||||
};
|
||||
|
||||
/* The following EFR TRAU-DL frame is a dummy to be transmitted in the absence
|
||||
* of RTP-derived TRAU-DL frames. The payload bit content here is the decoder
|
||||
* homing frame (DHF) of TS 46.060 section 8.2 Table 7 - the best we can do
|
||||
* in the absence of a proper TFO transform for EFR - while the full TRAU-DL
|
||||
* frame was generated by passing said EFR DHF through osmo_rtp2trau().
|
||||
*/
|
||||
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, 1, 1, 1,
|
||||
1, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 1, 1, 1,
|
||||
1, 1, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 1, 0, 1,
|
||||
0, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 1, 1, 1, 0, 1,
|
||||
1, 0, 0, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 1, 1, 1, 1,
|
||||
0, 1, 1, 0, 1, 1, 0, 0,
|
||||
1, 0, 0, 1, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 1,
|
||||
1, 1, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 1, 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, 1, 1, 1, 0,
|
||||
1, 1, 1, 0, 1, 0, 1, 1,
|
||||
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, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
/* The following FRv1 TRAU-DL frame is a dummy to be transmitted in the absence
|
||||
* of RTP-derived TRAU-DL frames. The payload bit content here is the silence
|
||||
* frame of TS 46.011 Table 1 - the best we can do without integrating the
|
||||
* TFO transform for FRv1 from Themyscira libgsmfr2 - while the full TRAU-DL
|
||||
* frame was generated by passing said FRv1 silence frame through
|
||||
* osmo_rtp2trau().
|
||||
*/
|
||||
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, 1, 1, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 1,
|
||||
1, 1, 0, 0, 1, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 1, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 0, 0, 0, 1, 0, 0,
|
||||
1, 1, 1, 0, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 1, 1, 0, 1,
|
||||
1, 1, 0, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 1, 0,
|
||||
0, 0, 1, 1, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 1, 1, 1, 0,
|
||||
1, 1, 0, 1, 1, 0, 1, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 1,
|
||||
1, 1, 0, 1, 1, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 1,
|
||||
1, 1, 1, 0, 1, 1, 0, 1,
|
||||
1, 0, 1, 1, 0, 0, 0, 1,
|
||||
1, 0, 0, 1, 1, 1, 0, 1,
|
||||
1, 0, 0, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 1, 0, 0,
|
||||
1, 0, 1, 1, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 1, 0, 1, 1,
|
||||
0, 0, 0, 1, 0, 0, 1, 1,
|
||||
1, 1, 0, 1, 1, 0, 1, 1,
|
||||
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. */
|
||||
@@ -65,59 +207,33 @@ static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_dat
|
||||
struct mgcp_endpoint *endp = user_data;
|
||||
struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
|
||||
struct msgb *msg = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
|
||||
const uint8_t *dummy_fill_pl;
|
||||
unsigned dummy_fill_pl_len;
|
||||
struct osmo_trau_frame tf;
|
||||
int rc;
|
||||
uint8_t *ptr;
|
||||
const uint8_t *ptr_ft;
|
||||
enum osmo_trau_frame_type ft;
|
||||
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_MUX_EMPTY_CTR));
|
||||
|
||||
/* choose dummy fill frame payload based on current codec */
|
||||
switch (endp->e1.trau_rtp_st->type) {
|
||||
/* Choose an appropiate idle frame type */
|
||||
ft = endp->e1.trau_rtp_st->type;
|
||||
switch (ft) {
|
||||
case OSMO_TRAU16_FT_FR:
|
||||
dummy_fill_pl = osmo_gsm611_silence_frame;
|
||||
dummy_fill_pl_len = GSM_FR_BYTES;
|
||||
ptr_ft = idle_tf_fr;
|
||||
break;
|
||||
case OSMO_TRAU16_FT_EFR:
|
||||
dummy_fill_pl = osmo_gsm660_homing_frame;
|
||||
dummy_fill_pl_len = GSM_EFR_BYTES;
|
||||
break;
|
||||
case OSMO_TRAU16_FT_HR:
|
||||
case OSMO_TRAU8_SPEECH:
|
||||
dummy_fill_pl = osmo_gsm620_silence_frame;
|
||||
dummy_fill_pl_len = GSM_HR_BYTES;
|
||||
ptr_ft = idle_tf_efr;
|
||||
break;
|
||||
default:
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-I.460-IDLE-TX: unsupported frame type\n");
|
||||
goto skip;
|
||||
/* FIXME: What about 8k subslots and AMR frames? */
|
||||
ptr_ft = idle_tf_spch;
|
||||
}
|
||||
|
||||
/* turn it into a TRAU-DL frame */
|
||||
memset(&tf, 0, sizeof(tf));
|
||||
tf.dir = OSMO_TRAU_DIR_DL;
|
||||
rc = osmo_rtp2trau(&tf, dummy_fill_pl, dummy_fill_pl_len, endp->e1.trau_rtp_st);
|
||||
if (rc < 0) {
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR,
|
||||
"E1-I.460-IDLE-TX: error converting dummy fill frame!\n");
|
||||
goto skip;
|
||||
}
|
||||
rc = osmo_trau_frame_encode(msgb_data(msg), msg->data_len, &tf);
|
||||
if (rc < 0) {
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR,
|
||||
"E1-I.460-IDLE-TX: error encoding dummy fill frame!\n");
|
||||
goto skip;
|
||||
}
|
||||
msgb_put(msg, rc);
|
||||
|
||||
/* enqueue it into the I.460 multiplexer */
|
||||
/* 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);
|
||||
return;
|
||||
|
||||
skip:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_TX_FAIL_CTR));
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
/* called by I.460 de-multiplexer; feed output of I.460 demux into TRAU frame sync */
|
||||
@@ -178,7 +294,6 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
|
||||
/* Convert decoded trau frame to RTP frame */
|
||||
struct osmo_trau2rtp_state t2rs = {
|
||||
.type = fr.type,
|
||||
.rtp_extensions = endp->e1.rtp_extensions,
|
||||
};
|
||||
rc = osmo_trau2rtp(msgb_data(msg) + rtp_hdr_len, msg->data_len - rtp_hdr_len, &fr, &t2rs);
|
||||
if (rc <= 0) {
|
||||
@@ -546,7 +661,7 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
|
||||
|
||||
/*! Update E1 related parameters (codec and sync pattern).
|
||||
* \param[in] endp endpoint to update. */
|
||||
int mgcp_e1_endp_update(struct mgcp_endpoint *endp)
|
||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
|
||||
{
|
||||
struct mgcp_conn *conn;
|
||||
struct mgcp_conn_rtp *conn_rtp;
|
||||
@@ -567,17 +682,9 @@ int mgcp_e1_endp_update(struct mgcp_endpoint *endp)
|
||||
determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);
|
||||
endp->e1.last_codec = codec;
|
||||
|
||||
/* possible RTP extensions, codec-associated */
|
||||
endp->e1.rtp_extensions = 0;
|
||||
if (codec->param_present && codec->param.fr_efr_twts001)
|
||||
endp->e1.rtp_extensions |= OSMO_RTP_EXT_TWTS001;
|
||||
if (codec->param_present && codec->param.hr_twts002)
|
||||
endp->e1.rtp_extensions |= OSMO_RTP_EXT_TWTS002;
|
||||
|
||||
/* 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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Remove E1 resources from endpoint
|
||||
|
@@ -24,7 +24,6 @@
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_iuup.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
|
||||
@@ -641,85 +640,20 @@ int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid)
|
||||
|
||||
/*! update endpoint, updates internal endpoint specific data, should be
|
||||
* after when MDCX or CRCX has been executed successuflly.
|
||||
* \param[in] endp endpoint to update.
|
||||
* \returns zero on success, mgcp negative error on failure. */
|
||||
static int mgcp_endp_update_virtual(struct mgcp_endpoint *endp, struct mgcp_conn *conn, enum mgcp_verb verb)
|
||||
* \param[in] endp endpoint to update. */
|
||||
void mgcp_endp_update(struct mgcp_endpoint *endp)
|
||||
{
|
||||
OSMO_ASSERT(conn);
|
||||
OSMO_ASSERT(conn->type == MGCP_CONN_TYPE_RTP);
|
||||
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
||||
|
||||
switch (conn_rtp->type) {
|
||||
case MGCP_RTP_DEFAULT:
|
||||
break;
|
||||
case MGCP_RTP_OSMUX:
|
||||
if (conn_osmux_event_rx_crcx_mdcx(conn_rtp) < 0) {
|
||||
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "CRCX: Osmux handling failed!\n");
|
||||
return -500;
|
||||
}
|
||||
break;
|
||||
case MGCP_RTP_IUUP:
|
||||
return mgcp_conn_iuup_event_rx_crcx_mdcx(conn_rtp);
|
||||
default:
|
||||
return -523;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! update endpoint, updates internal endpoint specific data, should be
|
||||
* after when MDCX or CRCX has been executed successuflly.
|
||||
* \param[in] endp endpoint to update.
|
||||
* \returns zero on success, mgcp negative error on failure. */
|
||||
int mgcp_endp_update(struct mgcp_endpoint *endp, struct mgcp_conn *conn, enum mgcp_verb verb)
|
||||
{
|
||||
OSMO_ASSERT(conn);
|
||||
struct mgcp_trunk *trunk = endp->trunk;
|
||||
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
||||
char new_local_addr[INET6_ADDRSTRLEN];
|
||||
|
||||
/* CRCX: Find a local address for conn based on policy and initial SDP remote
|
||||
* information, then find a free port for it.
|
||||
* MDCX: msg may have provided a new remote address, which means we may need
|
||||
* to update our announced IP addr and re-bind our local end. This can
|
||||
* happen for instance if MGW initially provided an IPv4 during CRCX
|
||||
* ACK, and now MDCX tells us the remote has an IPv6 address.
|
||||
*/
|
||||
if (mgcp_get_local_addr(new_local_addr, conn_rtp) < 0)
|
||||
goto fail_bind_port_ret;
|
||||
|
||||
if (strcmp(new_local_addr, conn_rtp->end.local_addr)) {
|
||||
osmo_strlcpy(conn_rtp->end.local_addr, new_local_addr, sizeof(conn_rtp->end.local_addr));
|
||||
mgcp_rtp_end_free_port(&conn_rtp->end);
|
||||
if (mgcp_trunk_allocate_conn_rtp_ports(trunk, conn_rtp) != 0)
|
||||
goto fail_bind_port_ret;
|
||||
}
|
||||
|
||||
/* Allocate resources */
|
||||
switch (endp->trunk->trunk_type) {
|
||||
case MGCP_TRUNK_VIRTUAL:
|
||||
return mgcp_endp_update_virtual(endp, conn, verb);
|
||||
/* No updating initaliziation required for virtual endpoints. */
|
||||
break;
|
||||
case MGCP_TRUNK_E1:
|
||||
return mgcp_e1_endp_update(endp);
|
||||
mgcp_e1_endp_update(endp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail_bind_port_ret:
|
||||
switch (verb) {
|
||||
case MGCP_VERB_CRCX:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(trunk->ratectr.mgcp_crcx_ctr_group,
|
||||
MGCP_CRCX_FAIL_BIND_PORT));
|
||||
break;
|
||||
case MGCP_VERB_MDCX:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(trunk->ratectr.mgcp_mdcx_ctr_group,
|
||||
MGCP_MDCX_FAIL_BIND_PORT));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -500;
|
||||
}
|
||||
|
||||
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
|
||||
@@ -830,22 +764,6 @@ struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Helps assigning a new lco structure, since "codec" is talloc allocated. */
|
||||
void mgcp_endp_update_lco(struct mgcp_endpoint *endp, const struct mgcp_lco *lco)
|
||||
{
|
||||
/* First free old talloc allocated codec string: */
|
||||
talloc_free(endp->local_options.codec);
|
||||
endp->local_options.codec = NULL;
|
||||
|
||||
if (lco) {
|
||||
endp->local_options = *lco;
|
||||
if (lco->codec)
|
||||
endp->local_options.codec = talloc_strdup(endp, lco->codec);
|
||||
} else {
|
||||
endp->local_options = (struct mgcp_lco){0};
|
||||
}
|
||||
}
|
||||
|
||||
/*! release endpoint, all open connections are closed.
|
||||
* \param[in] endp endpoint to release */
|
||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
|
||||
@@ -867,7 +785,10 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
|
||||
/* Reset endpoint parameters and states */
|
||||
talloc_free(endp->callid);
|
||||
endp->callid = NULL;
|
||||
mgcp_endp_update_lco(endp, NULL);
|
||||
talloc_free(endp->local_options.string);
|
||||
endp->local_options.string = NULL;
|
||||
talloc_free(endp->local_options.codec);
|
||||
endp->local_options.codec = NULL;
|
||||
|
||||
if (endp->trunk->trunk_type == MGCP_TRUNK_E1) {
|
||||
uint8_t ts = e1_ts_nr_from_epname(endp->name);
|
||||
|
@@ -753,44 +753,3 @@ int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* To be called every time an CRCX/MDCX is received.
|
||||
* returns: 0 if conn can continue, MGCP negative code if an error ocurred during setup */
|
||||
int mgcp_conn_iuup_event_rx_crcx_mdcx(struct mgcp_conn_rtp *conn_rtp)
|
||||
{
|
||||
struct mgcp_conn *peer_conn;
|
||||
struct mgcp_conn_rtp *peer_conn_rtp;
|
||||
OSMO_ASSERT(mgcp_conn_rtp_is_iuup(conn_rtp));
|
||||
|
||||
/* keep waiting to receive remote address through CRCX/MDCX */
|
||||
if (!mgcp_rtp_end_remote_addr_available(&conn_rtp->end))
|
||||
return 0;
|
||||
|
||||
/* Conn already IuUP-configured/initialized, nothing to be done. */
|
||||
if (conn_rtp->iuup.configured)
|
||||
return 0;
|
||||
|
||||
/* Reached this point, conn_rtp is an IuUP conn which can be configured
|
||||
* and was not yet configured. If its sister conn in the endpoint was
|
||||
* already configured as IuUP "passive", then we know this one can be
|
||||
* configured as IuUP "active" right now. In that case, do so.
|
||||
* This usually happens on an HNBGW co-located MGW, where during
|
||||
* RAB-ASS-REQ the RAN-side conn (sister conn here) was already
|
||||
* configured and then upon rx of RAB-ASS-RESP it sets up (CRCX) the
|
||||
* CN-side IuUP conn (rt_conn here).
|
||||
*/
|
||||
peer_conn = mgcp_find_dst_conn(conn_rtp->conn);
|
||||
/* No peer conn yet, nothing to be done. */
|
||||
if (!peer_conn)
|
||||
return 0;
|
||||
peer_conn_rtp = mgcp_conn_get_conn_rtp(peer_conn);
|
||||
|
||||
if (mgcp_conn_rtp_is_iuup(peer_conn_rtp) &&
|
||||
peer_conn_rtp->iuup.configured &&
|
||||
!conn_rtp->iuup.active_init) {
|
||||
LOG_CONN_RTP(conn_rtp, LOGL_INFO, "Sister IuUP conn in endp configured as passive, init this one as active\n");
|
||||
OSMO_ASSERT(peer_conn_rtp->iuup.init_ind);
|
||||
_conn_iuup_configure_as_active(conn_rtp, peer_conn_rtp->iuup.init_ind);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@
|
||||
|
||||
/* (same fmt as LOGPENDP()) */
|
||||
#define LOG_MGCP_PDATA(PDATA, LEVEL, FMT, ARGS...) \
|
||||
LOGP(DLMGCP, LEVEL, "%s: endpoint(%s) " FMT, (PDATA)->rq->name, (PDATA)->epname ? : "null-epname", ##ARGS)
|
||||
LOGP(DLMGCP, LEVEL, "endpoint:%s " FMT, (PDATA) ? ((PDATA)->epname ? : "null-epname") : "null-pdata", ##ARGS)
|
||||
|
||||
/*! Display an mgcp message on the log output.
|
||||
* \param[in] message mgcp message string
|
||||
@@ -101,197 +101,6 @@ enum mgcp_connection_mode mgcp_parse_conn_mode(const char *mode)
|
||||
return MGCP_CONN_NONE;
|
||||
}
|
||||
|
||||
/*! Helper function for check_local_cx_options() to get a pointer of the next
|
||||
* lco option identifier
|
||||
* \param[in] lco string
|
||||
* \returns pointer to the beginning of the LCO identifier, NULL on failure */
|
||||
char *get_lco_identifier(const char *options)
|
||||
{
|
||||
char *ptr;
|
||||
unsigned int count = 0;
|
||||
|
||||
/* Jump to the end of the lco identifier */
|
||||
ptr = strstr(options, ":");
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
/* Walk backwards until the pointer points to the beginning of the
|
||||
* lco identifier. We know that we stand at the beginning when we
|
||||
* are either at the beginning of the memory or see a space or
|
||||
* comma. (this is tolerant, it will accept a:10, b:11 as well as
|
||||
* a:10,b:11) */
|
||||
while (1) {
|
||||
/* Endless loop protection */
|
||||
if (count > 10000)
|
||||
return NULL;
|
||||
else if (ptr < options || *ptr == ' ' || *ptr == ',') {
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
ptr--;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Check if we got any result */
|
||||
if (*ptr == ':')
|
||||
return NULL;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*! Check the LCO option. This function checks for multiple appearance of LCO
|
||||
* options, which is illegal
|
||||
* \param[in] ctx talloc context
|
||||
* \param[in] lco string
|
||||
* \returns 0 on success, -1 on failure */
|
||||
int check_local_cx_options(void *ctx, const char *options)
|
||||
{
|
||||
int i;
|
||||
char *options_copy;
|
||||
char *lco_identifier;
|
||||
char *lco_identifier_end;
|
||||
char *next_lco_identifier;
|
||||
|
||||
char **lco_seen;
|
||||
unsigned int lco_seen_n = 0;
|
||||
|
||||
if (!options)
|
||||
return -1;
|
||||
|
||||
lco_seen =
|
||||
(char **)talloc_zero_size(ctx, strlen(options) * sizeof(char *));
|
||||
options_copy = talloc_strdup(ctx, options);
|
||||
lco_identifier = options_copy;
|
||||
|
||||
do {
|
||||
/* Move the lco_identifier pointer to the beginning of the
|
||||
* current lco option identifier */
|
||||
lco_identifier = get_lco_identifier(lco_identifier);
|
||||
if (!lco_identifier)
|
||||
goto error;
|
||||
|
||||
/* Look ahead to the next LCO option early, since we
|
||||
* will parse destructively */
|
||||
next_lco_identifier = strstr(lco_identifier + 1, ",");
|
||||
|
||||
/* Pinch off the end of the lco field identifier name
|
||||
* and see if we still got something, also check if
|
||||
* there is some value after the colon. */
|
||||
lco_identifier_end = strstr(lco_identifier, ":");
|
||||
if (!lco_identifier_end)
|
||||
goto error;
|
||||
if (*(lco_identifier_end + 1) == ' '
|
||||
|| *(lco_identifier_end + 1) == ','
|
||||
|| *(lco_identifier_end + 1) == '\0')
|
||||
goto error;
|
||||
*lco_identifier_end = '\0';
|
||||
if (strlen(lco_identifier) == 0)
|
||||
goto error;
|
||||
|
||||
/* Check if we have already seen the current field identifier
|
||||
* before. If yes, we must bail, an LCO must only appear once
|
||||
* in the LCO string */
|
||||
for (i = 0; i < lco_seen_n; i++) {
|
||||
if (strcasecmp(lco_seen[i], lco_identifier) == 0)
|
||||
goto error;
|
||||
}
|
||||
lco_seen[lco_seen_n] = lco_identifier;
|
||||
lco_seen_n++;
|
||||
|
||||
/* The first identifier must always be found at the beginnning
|
||||
* of the LCO string */
|
||||
if (lco_seen[0] != options_copy)
|
||||
goto error;
|
||||
|
||||
/* Go to the next lco option */
|
||||
lco_identifier = next_lco_identifier;
|
||||
} while (lco_identifier);
|
||||
|
||||
talloc_free(lco_seen);
|
||||
talloc_free(options_copy);
|
||||
return 0;
|
||||
error:
|
||||
talloc_free(lco_seen);
|
||||
talloc_free(options_copy);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the LCO from a string (see RFC 3435).
|
||||
* The string is stored in the 'string' field. A NULL string is handled exactly
|
||||
* like an empty string, the 'string' field is never NULL after this function
|
||||
* has been called. */
|
||||
static int mgcp_parse_lco(void *ctx, struct mgcp_lco *lco, const char *options)
|
||||
{
|
||||
const char *lco_id;
|
||||
char codec[17];
|
||||
char nt[17];
|
||||
int len;
|
||||
|
||||
if (!options)
|
||||
return 0;
|
||||
if (strlen(options) == 0)
|
||||
return 0;
|
||||
|
||||
lco->present = true;
|
||||
|
||||
/* Make sure the encoding of the LCO is consistent before we proceed */
|
||||
if (check_local_cx_options(ctx, options) != 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"local CX options: Internal inconsistency in Local Connection Options!\n");
|
||||
return -524;
|
||||
}
|
||||
|
||||
lco_id = options;
|
||||
while ((lco_id = get_lco_identifier(lco_id))) {
|
||||
switch (tolower(lco_id[0])) {
|
||||
case 'p':
|
||||
if (sscanf(lco_id + 1, ":%d-%d",
|
||||
&lco->pkt_period_min, &lco->pkt_period_max) == 1)
|
||||
lco->pkt_period_max = lco->pkt_period_min;
|
||||
break;
|
||||
case 'a':
|
||||
/* FIXME: LCO also supports the negotiation of more than one codec.
|
||||
* (e.g. a:PCMU;G726-32) But this implementation only supports a single
|
||||
* codec only. Ignoring all but the first codec. */
|
||||
if (sscanf(lco_id + 1, ":%16[^,;]", codec) == 1) {
|
||||
talloc_free(lco->codec);
|
||||
/* MGCP header is case insensive, and we'll need
|
||||
codec in uppercase when using it later: */
|
||||
len = strlen(codec);
|
||||
lco->codec = talloc_size(ctx, len + 1);
|
||||
osmo_str_toupper_buf(lco->codec, len + 1, codec);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (lco_id[1] == 't' && sscanf(lco_id + 2, ":%16[^,]", nt) == 1)
|
||||
break;
|
||||
/* else: fall through to print notice log */
|
||||
default:
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"LCO: unhandled option: '%c'/%d in \"%s\"\n",
|
||||
*lco_id, *lco_id, options);
|
||||
break;
|
||||
}
|
||||
|
||||
lco_id = strchr(lco_id, ',');
|
||||
if (!lco_id)
|
||||
break;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_DEBUG,
|
||||
"local CX options: lco->pkt_period_max: %d, lco->codec: %s\n",
|
||||
lco->pkt_period_max, lco->codec);
|
||||
|
||||
/* Check if the packetization fits the 20ms raster */
|
||||
if (lco->pkt_period_min % 20 && lco->pkt_period_max % 20) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"local CX options: packetization interval is not a multiple of 20ms!\n");
|
||||
return -535;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Analyze and parse the the hader of an MGCP messeage string.
|
||||
* \param[out] pdata caller provided memory to store the parsing results.
|
||||
* \param[in] data mgcp message string.
|
||||
@@ -368,7 +177,6 @@ int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata)
|
||||
{
|
||||
struct mgcp_parse_hdr_pars *hp = &pdata->hpars;
|
||||
char *line;
|
||||
int rc;
|
||||
|
||||
mgcp_parse_hdr_pars_init(hp);
|
||||
|
||||
@@ -380,24 +188,7 @@ int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata)
|
||||
|
||||
switch (toupper(line[0])) {
|
||||
case 'L':
|
||||
hp->lco_string = (const char *)line + 3;
|
||||
rc = mgcp_parse_lco(pdata, &hp->lco, hp->lco_string);
|
||||
if (rc < 0) {
|
||||
LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "Invalid LocalConnectionOptions line: '%s'", line);
|
||||
switch (pdata->rq->verb) {
|
||||
case MGCP_VERB_CRCX:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_crcx_ctr_group,
|
||||
MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS));
|
||||
break;
|
||||
case MGCP_VERB_MDCX:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_mdcx_ctr_group,
|
||||
MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
hp->local_options = (const char *)line + 3;
|
||||
break;
|
||||
case 'C':
|
||||
hp->callid = (const char *)line + 3;
|
||||
@@ -421,23 +212,7 @@ int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata)
|
||||
hp->have_sdp = true;
|
||||
goto mgcp_header_done;
|
||||
default:
|
||||
LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "unhandled option: '%c'/%d\n", *line, *line);
|
||||
switch (pdata->rq->verb) {
|
||||
case MGCP_VERB_CRCX:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_crcx_ctr_group,
|
||||
MGCP_CRCX_FAIL_UNHANDLED_PARAM));
|
||||
break;
|
||||
case MGCP_VERB_MDCX:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_mdcx_ctr_group,
|
||||
MGCP_MDCX_FAIL_UNHANDLED_PARAM));
|
||||
break;
|
||||
case MGCP_VERB_DLCX:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_dlcx_ctr_group,
|
||||
MGCP_DLCX_FAIL_UNHANDLED_PARAM));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "CRCX: unhandled option: '%c'/%d\n", *line, *line);
|
||||
return -539;
|
||||
}
|
||||
}
|
||||
@@ -501,6 +276,10 @@ int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
|
||||
if (!endp)
|
||||
return -1;
|
||||
|
||||
/* Accept any CallID for "X-Osmo-IGN: C" */
|
||||
if (endp->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID)
|
||||
return 0;
|
||||
|
||||
if (!callid)
|
||||
return -1;
|
||||
if (!endp->callid)
|
||||
|
@@ -408,6 +408,31 @@ static int align_rtp_timestamp_offset(const struct mgcp_endpoint *endp,
|
||||
return ts_error;
|
||||
}
|
||||
|
||||
/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
|
||||
* \param[in] associated endpoint.
|
||||
* \param[in] destination RTP end.
|
||||
* \param[in,out] msg message bufffer containing data. Function might change length.
|
||||
* \returns ignores input parameters, return always 0. */
|
||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
struct msgb *msg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! dummy callback to disable transcoding (see also cfg->setup_rtp_processing_cb).
|
||||
* \param[in] associated endpoint.
|
||||
* \param[in] destination RTP connnection.
|
||||
* \param[in] source RTP connection.
|
||||
* \returns ignores input parameters, return always 0. */
|
||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||
struct mgcp_conn_rtp *conn_dst,
|
||||
struct mgcp_conn_rtp *conn_src)
|
||||
{
|
||||
LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -1162,7 +1187,13 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
|
||||
* header is present, we will generate one. */
|
||||
gen_rtp_header(msg, rtp_end, rtp_state);
|
||||
|
||||
/* TODO: Run transcoder */
|
||||
/* Run transcoder */
|
||||
rc = endp->trunk->cfg->rtp_processing_cb(endp, rtp_end, msg);
|
||||
if (rc < 0) {
|
||||
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error %d during transcoding\n", rc);
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (addr)
|
||||
mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg);
|
||||
|
@@ -211,7 +211,6 @@ osmux_handle_find_or_create(const struct mgcp_trunk *trunk, const struct osmo_so
|
||||
int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
|
||||
{
|
||||
int ret;
|
||||
size_t msg_len;
|
||||
|
||||
if (!conn->end.output_enabled) {
|
||||
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
|
||||
@@ -235,17 +234,15 @@ int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg_len = msgb_length(msg);
|
||||
while ((ret = osmux_xfrm_input(conn->osmux.in, msg, conn->osmux.remote_cid)) > 0) {
|
||||
/* batch full, build and deliver it */
|
||||
osmux_xfrm_input_deliver(conn->osmux.in);
|
||||
}
|
||||
/* NOTE: At this point msg is now owned by osmux subsystem and may have been potentially freed. */
|
||||
if (ret < 0) {
|
||||
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
|
||||
} else {
|
||||
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_CTR);
|
||||
rtpconn_osmux_rate_ctr_add(conn, OSMUX_AMR_OCTETS_TX_CTR, msg_len - sizeof(struct rtp_hdr));
|
||||
rtpconn_osmux_rate_ctr_add(conn, OSMUX_AMR_OCTETS_TX_CTR, msgb_length(msg) - sizeof(struct rtp_hdr));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -498,9 +495,6 @@ int osmux_init(struct mgcp_trunk *trunk)
|
||||
int ret, fd;
|
||||
struct mgcp_config *cfg = trunk->cfg;
|
||||
|
||||
if (cfg->osmux.initialized)
|
||||
return 0;
|
||||
|
||||
/* So far we only support running on one trunk: */
|
||||
OSMO_ASSERT(trunk == mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID));
|
||||
|
||||
@@ -513,19 +507,19 @@ int osmux_init(struct mgcp_trunk *trunk)
|
||||
ret = mgcp_create_bind(cfg->osmux.local_addr_v4, cfg->osmux.local_port,
|
||||
cfg->endp_dscp, cfg->endp_priority);
|
||||
if (ret < 0) {
|
||||
LOGPTRUNK(trunk, DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv4 socket to %s:%u\n",
|
||||
cfg->osmux.local_addr_v4, cfg->osmux.local_port);
|
||||
LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv4 socket to %s:%u\n",
|
||||
cfg->osmux.local_addr_v4, cfg->osmux.local_port);
|
||||
goto out_free_v4;
|
||||
}
|
||||
fd = ret;
|
||||
|
||||
ret = osmo_iofd_register(osmux_fd_v4, fd);
|
||||
if (ret < 0) {
|
||||
LOGPTRUNK(trunk, DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n", osmo_sock_get_name2(fd));
|
||||
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n", osmo_sock_get_name2(fd));
|
||||
close(fd);
|
||||
goto out_free_v4;
|
||||
}
|
||||
LOGPTRUNK(trunk, DOSMUX, LOGL_INFO, "OSMUX IPv4 socket listening on %s\n", osmo_sock_get_name2(fd));
|
||||
LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv4 socket listening on %s\n", osmo_sock_get_name2(fd));
|
||||
}
|
||||
|
||||
osmux_fd_v6 = osmo_iofd_setup(trunk, -1, "osmux_fd_v6", OSMO_IO_FD_MODE_RECVFROM_SENDTO, &osmux_ioops, trunk);
|
||||
@@ -537,8 +531,8 @@ int osmux_init(struct mgcp_trunk *trunk)
|
||||
ret = mgcp_create_bind(cfg->osmux.local_addr_v6, cfg->osmux.local_port,
|
||||
cfg->endp_dscp, cfg->endp_priority);
|
||||
if (ret < 0) {
|
||||
LOGPTRUNK(trunk, DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv6 socket to [%s]:%u\n",
|
||||
cfg->osmux.local_addr_v6, cfg->osmux.local_port);
|
||||
LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv6 socket to [%s]:%u\n",
|
||||
cfg->osmux.local_addr_v6, cfg->osmux.local_port);
|
||||
goto out_free_v6;
|
||||
}
|
||||
fd = ret;
|
||||
@@ -549,10 +543,9 @@ int osmux_init(struct mgcp_trunk *trunk)
|
||||
close(fd);
|
||||
goto out_free_v6;
|
||||
}
|
||||
LOGPTRUNK(trunk, DOSMUX, LOGL_INFO, "OSMUX IPv6 socket listening on %s\n", osmo_sock_get_name2(fd));
|
||||
LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv6 socket listening on %s\n", osmo_sock_get_name2(fd));
|
||||
}
|
||||
cfg->osmux.initialized = true;
|
||||
LOGPTRUNK(trunk, DOSMUX, LOGL_NOTICE, "OSMUX socket has been set up\n");
|
||||
return 0;
|
||||
|
||||
out_free_v6:
|
||||
@@ -564,7 +557,6 @@ out_free_v4:
|
||||
osmo_iofd_free(osmux_fd_v4);
|
||||
osmux_fd_v4 = NULL;
|
||||
out:
|
||||
LOGPTRUNK(trunk, DOSMUX, LOGL_ERROR, "Cannot init OSMUX\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -93,7 +93,7 @@ static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
|
||||
[MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS] = { "mdcx:conn_opt", "connection options invalid." },
|
||||
[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
|
||||
{ "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
|
||||
[MGCP_MDCX_FAIL_BIND_PORT] = { "mdcx:bind_port", "port bind failure." },
|
||||
[MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
|
||||
[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
|
||||
};
|
||||
|
||||
|
@@ -199,7 +199,7 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
|
||||
unsigned int pt;
|
||||
unsigned int count = 0;
|
||||
char delimiter;
|
||||
unsigned int param_val;
|
||||
unsigned int amr_octet_aligned;
|
||||
|
||||
memset(fmtp_param, 0, sizeof(*fmtp_param));
|
||||
|
||||
@@ -239,30 +239,12 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
|
||||
if (delimiter == ';' || delimiter == ',')
|
||||
str_ptr[strlen(str_ptr) - 1] = '\0';
|
||||
|
||||
/* We support the following codec parameters:
|
||||
*
|
||||
* AMR: octet-align parameter of RFC 4867 section 8.3;
|
||||
* FR & EFR: tw-ts-001 parameter, Osmocom private;
|
||||
* HR: tw-ts-002 parameter, Osmocom private.
|
||||
*
|
||||
* tw-ts-001 and tw-ts-002 Osmocom-private parameters are used
|
||||
* only in the context of OsmoBSC driving an E1 MGW endpoint.
|
||||
*/
|
||||
if (sscanf(param_str, "octet-align=%d", ¶m_val) == 1) {
|
||||
/* AMR octet aligned parameter (see also RFC 3267, section 8.3) */
|
||||
if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
|
||||
fmtp_param->param.amr_octet_aligned_present = true;
|
||||
fmtp_param->param.amr_octet_aligned = false;
|
||||
if (param_val == 1)
|
||||
if (amr_octet_aligned == 1)
|
||||
fmtp_param->param.amr_octet_aligned = true;
|
||||
} else if (sscanf(param_str, "tw-ts-001=%d", ¶m_val) == 1) {
|
||||
fmtp_param->param.fr_efr_twts001_present = true;
|
||||
fmtp_param->param.fr_efr_twts001 = false;
|
||||
if (param_val == 1)
|
||||
fmtp_param->param.fr_efr_twts001 = true;
|
||||
} else if (sscanf(param_str, "tw-ts-002=%d", ¶m_val) == 1) {
|
||||
fmtp_param->param.hr_twts002_present = true;
|
||||
fmtp_param->param.hr_twts002 = false;
|
||||
if (param_val == 1)
|
||||
fmtp_param->param.hr_twts002 = true;
|
||||
}
|
||||
|
||||
param_str = strtok(NULL, " ");
|
||||
@@ -577,23 +559,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
||||
goto buffer_too_small;
|
||||
}
|
||||
|
||||
/* Include a=fmtp line in MGCP response only for AMR
|
||||
* octet-align parameter, not for tw-ts-* parameters.
|
||||
* Rationale:
|
||||
*
|
||||
* - tw-ts-* parameters exist meaningfully only for E1
|
||||
* endpoints driven by OsmoBSC, not in any other
|
||||
* context. libosmo-mgcp-client used by OsmoBSC
|
||||
* completely ignores all fmtp lines, has no code
|
||||
* to parse them at all.
|
||||
*
|
||||
* - The SDP we return is supposed to indicate what
|
||||
* _we_ accept, conceptually independent from what
|
||||
* the remote accepts. And we always accept TW-TS-001
|
||||
* and TW-TS-002 RTP formats going to E1 DL, whether
|
||||
* or not we send them in UL per client request.
|
||||
*/
|
||||
if (codec->param_present && codec->param.amr_octet_aligned_present) {
|
||||
if (codec->param_present) {
|
||||
fmtp_param.payload_type = payload_type;
|
||||
fmtp_param.param = codec->param;
|
||||
fmtp_params[0] = fmtp_param;
|
||||
|
@@ -27,7 +27,6 @@ osmo_mgw_SOURCES = \
|
||||
osmo_mgw_LDADD = \
|
||||
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOCODEC_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) \
|
||||
|
@@ -36,7 +36,6 @@ mgcp_test_SOURCES = \
|
||||
mgcp_test_LDADD = \
|
||||
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOCODEC_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
|
@@ -43,8 +43,6 @@
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
|
||||
void *tall_mgw_ctx;
|
||||
|
||||
char *strline_r(char *str, char **saveptr);
|
||||
|
||||
const char *strline_test_data =
|
||||
@@ -2325,7 +2323,7 @@ void test_conn_id_matching(void)
|
||||
|
||||
INIT_LLIST_HEAD(&endp.conns);
|
||||
|
||||
conn = talloc_zero(tall_mgw_ctx, struct mgcp_conn);
|
||||
conn = talloc_zero(NULL, struct mgcp_conn);
|
||||
OSMO_ASSERT(conn);
|
||||
osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
|
||||
llist_add(&conn->entry, &endp.conns);
|
||||
|
Reference in New Issue
Block a user