mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-03 21:43:32 +00:00 
			
		
		
		
	Compare commits
	
		
			46 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2eacae8f2e | ||
| 
						 | 
					403d5f1489 | ||
| 
						 | 
					f227633959 | ||
| 
						 | 
					83c8846728 | ||
| 
						 | 
					78ee99adcf | ||
| 
						 | 
					de4090d920 | ||
| 
						 | 
					732cadd2c8 | ||
| 
						 | 
					6747b60a95 | ||
| 
						 | 
					90ae9ed0a2 | ||
| 
						 | 
					206be49c69 | ||
| 
						 | 
					45559e9230 | ||
| 
						 | 
					f94b846224 | ||
| 
						 | 
					3ea3a69821 | ||
| 
						 | 
					46ddc65626 | ||
| 
						 | 
					71f313749e | ||
| 
						 | 
					80a5abbbe3 | ||
| 
						 | 
					ba812f7e86 | ||
| 
						 | 
					345c37a543 | ||
| 
						 | 
					b3457cd250 | ||
| 
						 | 
					fcf1864db3 | ||
| 
						 | 
					9221b67f3b | ||
| 
						 | 
					732d595a26 | ||
| 
						 | 
					3bc9d53628 | ||
| 
						 | 
					b5a4f45dbf | ||
| 
						 | 
					e6bafbf3e3 | ||
| 
						 | 
					5c7b128166 | ||
| 
						 | 
					5469edc278 | ||
| 
						 | 
					66952183a9 | ||
| 
						 | 
					cc97f58d96 | ||
| 
						 | 
					5d6931881a | ||
| 
						 | 
					0f4be7699b | ||
| 
						 | 
					546983cdbc | ||
| 
						 | 
					c04de4e7bb | ||
| 
						 | 
					d46cdd80de | ||
| 
						 | 
					6676e63c89 | ||
| 
						 | 
					1f99c3aaae | ||
| 
						 | 
					e6ef4e7484 | ||
| 
						 | 
					b0fa041a28 | ||
| 
						 | 
					e17bf77bdd | ||
| 
						 | 
					802b1fad61 | ||
| 
						 | 
					8a8973eec2 | ||
| 
						 | 
					17e7ea66e4 | ||
| 
						 | 
					9c3fad2c42 | ||
| 
						 | 
					227a800d26 | ||
| 
						 | 
					24cae67f3e | ||
| 
						 | 
					0d47c408ac | 
							
								
								
									
										14
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								configure.ac
									
									
									
									
									
								
							@@ -44,13 +44,13 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
 | 
			
		||||
AC_SUBST(LIBRARY_DLSYM)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.10.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.10.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.10.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.10.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.5.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.6.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.6.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 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)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.6.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 2.0.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 2.0.0)
 | 
			
		||||
 | 
			
		||||
CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
			
		||||
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ export deps inst
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
 | 
			
		||||
mkdir "$deps" || true
 | 
			
		||||
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
 | 
			
		||||
osmo-build-dep.sh libosmocore "" --disable-doxygen
 | 
			
		||||
 | 
			
		||||
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
 | 
			
		||||
 | 
			
		||||
@@ -30,8 +30,8 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
			
		||||
export LD_LIBRARY_PATH="$inst/lib"
 | 
			
		||||
export PATH="$inst/bin:$PATH"
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmo-netif "" --disable-doxygen
 | 
			
		||||
osmo-build-dep.sh libosmo-abis
 | 
			
		||||
osmo-build-dep.sh libosmo-netif
 | 
			
		||||
 | 
			
		||||
# Additional configure options and depends
 | 
			
		||||
CONFIG=""
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,63 @@
 | 
			
		||||
osmo-mgw (1.14.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * jenkins.sh: libosmo-netif no longer depends on libosmo-abis
 | 
			
		||||
  * jenkins.sh: Use --disable-doxygen configure param
 | 
			
		||||
  * mgcp-client: Fix wrong value passed to strerror()
 | 
			
		||||
  * mgcp_client_internal.h: Add missing header dependency
 | 
			
		||||
  * mgcp-cli: Mark iofd ptr as NULL when freed
 | 
			
		||||
  * mgcp-cli: Improve error handling around mgcp_msg_gen() return
 | 
			
		||||
  * mgcp-cli: Fix filling in wrong local IP address of SDP Origin o=
 | 
			
		||||
  * mgw: Drop own MGCP extension 'noanswer'
 | 
			
		||||
  * cosmetic: mgw: Fix indentation whitespace
 | 
			
		||||
  * mgcp-client: Fix regression checking null ptr
 | 
			
		||||
  * mgw: Rename and move code freeing endp connection
 | 
			
		||||
  * mgw: Rename and move several get_conn funcs acting on endp object
 | 
			
		||||
  * mgw: mgcp_network.c: Simplify use of conn_rtp ptr
 | 
			
		||||
  * mgw: Clean up access to conn_rtp from conn
 | 
			
		||||
  * mgw: Avoid 2nd lookup of conn in endp during CRCX
 | 
			
		||||
  * cosmetic: mgw: iuup: Update comment
 | 
			
		||||
  * mgw: constify mgcp_endp_avail() param
 | 
			
		||||
  * mgcp_endp: Add helpers accessing endp connections
 | 
			
		||||
  * mgw: mgcp_protocol: assert freeing last conn allows creating new conn
 | 
			
		||||
  * mgw: Split conn mode parsing and applying into conn
 | 
			
		||||
  * mgw: CRCXMDCX/DLCX: rename conn and conn_rtp variables
 | 
			
		||||
  * mgw: Use bool instead of int in local var
 | 
			
		||||
  * Rename mgcp_free_rtp_port() to mgcp_rtp_end_free_port()
 | 
			
		||||
  * mgw: Split mgcp_rtp_end to its own file
 | 
			
		||||
  * mgw: Introduce mgcp_rtp_end_init()
 | 
			
		||||
  * mgw: Introduce struct mgcp_codecset struct
 | 
			
		||||
  * mgw: Cleanup rtp_endp fields in its own function
 | 
			
		||||
  * mgw: Move force_ptime logic outside of main CRCX func handler
 | 
			
		||||
  * mgw: Move several params setting to mgcp_rtp_end_init()
 | 
			
		||||
  * mgw: Simplify and redo code around ssrc patch feature
 | 
			
		||||
  * mgw: Clean up code allocating conn_rtp rtp/rtcp sockets
 | 
			
		||||
  * mgw: Rename and cleanup code allocating rtp/rtcp ports in trunk
 | 
			
		||||
  * mgw: CRCX: Split mgcp header pars parsing into a previous step
 | 
			
		||||
  * mgw: MDCX: Split mgcp header pars parsing into a previous step
 | 
			
		||||
  * mgw: DLCX: Split mgcp header pars parsing into a previous step
 | 
			
		||||
  * mgw: Decouple SDP parsing step from conn obj update
 | 
			
		||||
  * mgw: Remove wrong TODO comment
 | 
			
		||||
  * mgw: MDCX: Simplify early return code paths
 | 
			
		||||
 | 
			
		||||
  [ Mychaela N. Falconia ]
 | 
			
		||||
  * E1 cosmetic: reduce white space in hard-coded TRAU-DL frames
 | 
			
		||||
  * E1: replace idle_tf_efr[] with a better version
 | 
			
		||||
  * E1: replace idle_tf_fr[] with a better version
 | 
			
		||||
 | 
			
		||||
 -- Oliver Smith <osmith@sysmocom.de>  Wed, 12 Feb 2025 12:30:33 +0100
 | 
			
		||||
 | 
			
		||||
osmo-mgw (1.13.1) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Philipp Maier ]
 | 
			
		||||
  * mgcp_network: use an uint16_t to store the port number
 | 
			
		||||
  * mgcp_network: add missing ntohs
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * tests/mgcp/mgcp_test: Add some extra asserts in code
 | 
			
		||||
 | 
			
		||||
 -- Oliver Smith <osmith@sysmocom.de>  Thu, 12 Sep 2024 13:53:19 +0200
 | 
			
		||||
 | 
			
		||||
osmo-mgw (1.13.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Neels Hofmeyr ]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -6,9 +6,9 @@ Build-Depends: debhelper (>= 10),
 | 
			
		||||
               dh-autoreconf,
 | 
			
		||||
               pkg-config,
 | 
			
		||||
               autotools-dev,
 | 
			
		||||
               libosmocore-dev (>= 1.10.0),
 | 
			
		||||
               libosmo-netif-dev (>= 1.5.0),
 | 
			
		||||
               libosmo-abis-dev (>= 1.6.0),
 | 
			
		||||
               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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
noinst_HEADERS = \
 | 
			
		||||
	vty.h \
 | 
			
		||||
	mgcp_msg.h \
 | 
			
		||||
	mgcp_codec.h \
 | 
			
		||||
	mgcp_conn.h \
 | 
			
		||||
	mgcp_stat.h \
 | 
			
		||||
	mgcp_endp.h \
 | 
			
		||||
@@ -13,4 +14,5 @@ noinst_HEADERS = \
 | 
			
		||||
	mgcp_network.h \
 | 
			
		||||
	mgcp_protocol.h \
 | 
			
		||||
	mgcp_iuup.h \
 | 
			
		||||
	mgcp_rtp_end.h \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,9 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 | 
			
		||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
 | 
			
		||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
 | 
			
		||||
@@ -8,14 +12,37 @@
 | 
			
		||||
 | 
			
		||||
#define PTYPE_UNDEFINED (-1)
 | 
			
		||||
 | 
			
		||||
struct mgcp_conn_rtp;
 | 
			
		||||
struct mgcp_rtp_codec {
 | 
			
		||||
	uint32_t rate;
 | 
			
		||||
	int channels;
 | 
			
		||||
	uint32_t frame_duration_num;
 | 
			
		||||
	uint32_t frame_duration_den;
 | 
			
		||||
 | 
			
		||||
	int payload_type;
 | 
			
		||||
	char audio_name[64];
 | 
			
		||||
	char subtype_name[64];
 | 
			
		||||
 | 
			
		||||
	bool param_present;
 | 
			
		||||
	struct mgcp_codec_param param;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 | 
			
		||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
 | 
			
		||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
 | 
			
		||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst);
 | 
			
		||||
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_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
 | 
			
		||||
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
 | 
			
		||||
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type);
 | 
			
		||||
 | 
			
		||||
struct mgcp_rtp_codecset {
 | 
			
		||||
	/* currently selected audio codec */
 | 
			
		||||
	struct mgcp_rtp_codec *codec;
 | 
			
		||||
	/* array with assigned audio codecs to choose from (SDP) */
 | 
			
		||||
	struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
 | 
			
		||||
	/* number of assigned audio codecs (SDP) */
 | 
			
		||||
	unsigned int codecs_assigned;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset);
 | 
			
		||||
void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str);
 | 
			
		||||
int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type,
 | 
			
		||||
			    const char *audio_name, const struct mgcp_codec_param *param);
 | 
			
		||||
int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst);
 | 
			
		||||
const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
 | 
			
		||||
								const char *subtype_name, unsigned int match_nr);
 | 
			
		||||
struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type);
 | 
			
		||||
 
 | 
			
		||||
@@ -24,11 +24,14 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <osmocom/mgcp/mgcp.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_network.h>
 | 
			
		||||
#include <osmocom/mgcp/osmux.h>
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
#include <osmocom/gsm/iuup.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_rtp_end.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
			
		||||
@@ -237,15 +240,16 @@ static inline bool mgcp_conn_rtp_is_iuup(const struct mgcp_conn_rtp *conn)
 | 
			
		||||
	return conn->type == MGCP_RTP_IUUP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct mgcp_conn_rtp *mgcp_conn_get_conn_rtp(struct mgcp_conn *conn)
 | 
			
		||||
{
 | 
			
		||||
	OSMO_ASSERT(conn->type == MGCP_CONN_TYPE_RTP);
 | 
			
		||||
	return &conn->u.rtp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
 | 
			
		||||
					const char *id);
 | 
			
		||||
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id);
 | 
			
		||||
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp);
 | 
			
		||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp);
 | 
			
		||||
void mgcp_conn_free(struct mgcp_conn *conn);
 | 
			
		||||
int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode);
 | 
			
		||||
char *mgcp_conn_dump(struct mgcp_conn *conn);
 | 
			
		||||
struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);
 | 
			
		||||
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp);
 | 
			
		||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
 | 
			
		||||
 
 | 
			
		||||
@@ -138,11 +138,20 @@ struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
			
		||||
					      const struct mgcp_trunk *trunk);
 | 
			
		||||
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
			
		||||
					struct mgcp_config *cfg);
 | 
			
		||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
 | 
			
		||||
bool mgcp_endp_avail(const struct mgcp_endpoint *endp);
 | 
			
		||||
unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp);
 | 
			
		||||
bool mgcp_endp_is_full(const struct mgcp_endpoint *endp);
 | 
			
		||||
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
			
		||||
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
			
		||||
void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp);
 | 
			
		||||
void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp);
 | 
			
		||||
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_release(struct mgcp_endpoint *endp);
 | 
			
		||||
 | 
			
		||||
struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id);
 | 
			
		||||
struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp);
 | 
			
		||||
struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
 | 
			
		||||
					const char *id);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,8 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
			
		||||
 | 
			
		||||
struct mgcp_conn;
 | 
			
		||||
struct mgcp_parse_data;
 | 
			
		||||
struct mgcp_endpoint;
 | 
			
		||||
@@ -34,14 +36,14 @@ struct mgcp_trunk;
 | 
			
		||||
 | 
			
		||||
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
 | 
			
		||||
 | 
			
		||||
int mgcp_parse_conn_mode(const char *msg, struct mgcp_endpoint *endp,
 | 
			
		||||
			 struct mgcp_conn *conn);
 | 
			
		||||
enum mgcp_connection_mode mgcp_parse_conn_mode(const char *msg);
 | 
			
		||||
 | 
			
		||||
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
 | 
			
		||||
int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata);
 | 
			
		||||
 | 
			
		||||
int mgcp_parse_osmux_cid(const char *line);
 | 
			
		||||
 | 
			
		||||
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line);
 | 
			
		||||
bool mgcp_check_param(const char *line);
 | 
			
		||||
 | 
			
		||||
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -74,65 +74,6 @@ struct mgcp_rtp_state {
 | 
			
		||||
	uint32_t alt_rtp_tx_ssrc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mgcp_rtp_codec {
 | 
			
		||||
	uint32_t rate;
 | 
			
		||||
	int channels;
 | 
			
		||||
	uint32_t frame_duration_num;
 | 
			
		||||
	uint32_t frame_duration_den;
 | 
			
		||||
 | 
			
		||||
	int payload_type;
 | 
			
		||||
	char audio_name[64];
 | 
			
		||||
	char subtype_name[64];
 | 
			
		||||
 | 
			
		||||
	bool param_present;
 | 
			
		||||
	struct mgcp_codec_param param;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
			
		||||
struct mgcp_rtp_end {
 | 
			
		||||
	/* remote IP address of the RTP socket */
 | 
			
		||||
	struct osmo_sockaddr addr;
 | 
			
		||||
 | 
			
		||||
	/* in network byte order */
 | 
			
		||||
	int rtcp_port;
 | 
			
		||||
 | 
			
		||||
	/* currently selected audio codec */
 | 
			
		||||
	struct mgcp_rtp_codec *codec;
 | 
			
		||||
 | 
			
		||||
	/* array with assigned audio codecs to choose from (SDP) */
 | 
			
		||||
	struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
 | 
			
		||||
 | 
			
		||||
	/* number of assigned audio codecs (SDP) */
 | 
			
		||||
	unsigned int codecs_assigned;
 | 
			
		||||
 | 
			
		||||
	/* per endpoint data */
 | 
			
		||||
	int  frames_per_packet;
 | 
			
		||||
	uint32_t packet_duration_ms;
 | 
			
		||||
	int maximum_packet_time; /* -1: not set */
 | 
			
		||||
	/* are we transmitting packets (true) or dropping (false) outbound packets */
 | 
			
		||||
	bool output_enabled;
 | 
			
		||||
	/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
			
		||||
	int force_output_ptime;
 | 
			
		||||
 | 
			
		||||
	/* RTP patching */
 | 
			
		||||
	int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
 | 
			
		||||
	/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
 | 
			
		||||
	int force_aligned_timing;
 | 
			
		||||
	bool rfc5993_hr_convert;
 | 
			
		||||
 | 
			
		||||
	/* Each end has a separate socket for RTP and RTCP */
 | 
			
		||||
	struct osmo_io_fd *rtp;
 | 
			
		||||
	struct osmo_io_fd *rtcp;
 | 
			
		||||
 | 
			
		||||
	/* local UDP port number of the RTP socket; RTCP is +1 */
 | 
			
		||||
	int local_port;
 | 
			
		||||
	/* where the endpoint RTP connection binds to, set during CRCX and
 | 
			
		||||
	 * possibly updated during MDCX */
 | 
			
		||||
	char local_addr[INET6_ADDRSTRLEN];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
 | 
			
		||||
 | 
			
		||||
struct mgcp_rtp_tap {
 | 
			
		||||
	/* is this tap active (1) or not (0) */
 | 
			
		||||
	int enabled;
 | 
			
		||||
@@ -150,9 +91,7 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
 | 
			
		||||
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
			
		||||
int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
 | 
			
		||||
void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
			
		||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
			
		||||
			   struct mgcp_conn_rtp *conn);
 | 
			
		||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
 | 
			
		||||
int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn, int rtp_port);
 | 
			
		||||
void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
			
		||||
			  struct mgcp_rtp_state *state,
 | 
			
		||||
			  struct mgcp_rtp_end *rtp_end,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,73 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
#include <osmocom/core/socket.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define MGCP_PARSE_SDP_PTIME_UNSET (-1)
 | 
			
		||||
#define MGCP_PARSE_SDP_MAXPTIME_UNSET (-1)
 | 
			
		||||
#define MGCP_PARSE_SDP_RTP_PORT_UNSET (0)
 | 
			
		||||
 | 
			
		||||
struct mgcp_parse_sdp {
 | 
			
		||||
	int ptime;
 | 
			
		||||
	int maxptime;
 | 
			
		||||
	int rtp_port;
 | 
			
		||||
	struct osmo_sockaddr rem_addr; /* Only IP address, port is in rtp_port above */
 | 
			
		||||
	struct mgcp_rtp_codecset cset;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline void mgcp_parse_sdp_init(struct mgcp_parse_sdp *sdp)
 | 
			
		||||
{
 | 
			
		||||
	sdp->ptime = MGCP_PARSE_SDP_PTIME_UNSET;
 | 
			
		||||
	sdp->maxptime = MGCP_PARSE_SDP_MAXPTIME_UNSET;
 | 
			
		||||
	sdp->rtp_port = MGCP_PARSE_SDP_RTP_PORT_UNSET;
 | 
			
		||||
	sdp->rem_addr = (struct osmo_sockaddr){ .u.sa.sa_family = AF_UNSPEC };
 | 
			
		||||
	mgcp_codecset_reset(&sdp->cset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#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 *local_options;
 | 
			
		||||
	const char *callid;
 | 
			
		||||
	const char *connid;
 | 
			
		||||
	enum mgcp_connection_mode mode;
 | 
			
		||||
	int remote_osmux_cid;
 | 
			
		||||
	bool have_sdp;
 | 
			
		||||
	/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
 | 
			
		||||
	uint32_t x_osmo_ign;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline void mgcp_parse_hdr_pars_init(struct mgcp_parse_hdr_pars *hpars)
 | 
			
		||||
{
 | 
			
		||||
	*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_parse_data {
 | 
			
		||||
	struct mgcp_config *cfg;
 | 
			
		||||
	char *save;
 | 
			
		||||
	/* MGCP Header: */
 | 
			
		||||
	char *epname;
 | 
			
		||||
	char *trans;
 | 
			
		||||
	char *save;
 | 
			
		||||
	struct mgcp_parse_hdr_pars hpars;
 | 
			
		||||
	/* MGCP Body: */
 | 
			
		||||
	struct mgcp_parse_sdp sdp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Local connection options */
 | 
			
		||||
@@ -23,8 +85,12 @@ int check_local_cx_options(void *ctx, const char *options);
 | 
			
		||||
 | 
			
		||||
struct mgcp_rtp_end;
 | 
			
		||||
struct mgcp_endpoint;
 | 
			
		||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
			
		||||
			 struct mgcp_rtp_end *rtp);
 | 
			
		||||
 | 
			
		||||
uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
 | 
			
		||||
				  const struct mgcp_rtp_end *rtp);
 | 
			
		||||
 | 
			
		||||
extern const struct value_string mgcp_connection_mode_strs[];
 | 
			
		||||
static inline const char *mgcp_cmode_name(enum mgcp_connection_mode mode)
 | 
			
		||||
{
 | 
			
		||||
	return get_value_string(mgcp_connection_mode_strs, mode);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								include/osmocom/mgcp/mgcp_rtp_end.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								include/osmocom/mgcp/mgcp_rtp_end.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/socket.h>
 | 
			
		||||
#include <osmocom/core/osmo_io.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/mgcp/mgcp.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
			
		||||
 | 
			
		||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
			
		||||
struct mgcp_rtp_end {
 | 
			
		||||
	struct mgcp_conn_rtp *conn_rtp; /* backpointer */
 | 
			
		||||
	/* remote IP address of the RTP socket */
 | 
			
		||||
	struct osmo_sockaddr addr;
 | 
			
		||||
 | 
			
		||||
	/* in network byte order */
 | 
			
		||||
	uint16_t rtcp_port;
 | 
			
		||||
 | 
			
		||||
	struct mgcp_rtp_codecset cset;
 | 
			
		||||
 | 
			
		||||
	/* per endpoint data */
 | 
			
		||||
	int  frames_per_packet;
 | 
			
		||||
	uint32_t packet_duration_ms;
 | 
			
		||||
	int maximum_packet_time; /* -1: not set */
 | 
			
		||||
	/* are we transmitting packets (true) or dropping (false) outbound packets */
 | 
			
		||||
	bool output_enabled;
 | 
			
		||||
	/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
			
		||||
	int force_output_ptime;
 | 
			
		||||
 | 
			
		||||
	/* RTP patching */
 | 
			
		||||
	bool force_constant_ssrc;
 | 
			
		||||
	/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
 | 
			
		||||
	int force_aligned_timing;
 | 
			
		||||
	bool rfc5993_hr_convert;
 | 
			
		||||
 | 
			
		||||
	/* Each end has a separate socket for RTP and RTCP */
 | 
			
		||||
	struct osmo_io_fd *rtp;
 | 
			
		||||
	struct osmo_io_fd *rtcp;
 | 
			
		||||
 | 
			
		||||
	/* local UDP port number of the RTP socket; RTCP is +1 */
 | 
			
		||||
	int local_port;
 | 
			
		||||
	/* where the endpoint RTP connection binds to, set during CRCX and
 | 
			
		||||
	 * possibly updated during MDCX */
 | 
			
		||||
	char local_addr[INET6_ADDRSTRLEN];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp);
 | 
			
		||||
void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end);
 | 
			
		||||
void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms);
 | 
			
		||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
 | 
			
		||||
void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end);
 | 
			
		||||
@@ -22,9 +22,9 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
			
		||||
			struct mgcp_conn_rtp *conn,
 | 
			
		||||
			struct mgcp_parse_data *p);
 | 
			
		||||
struct mgcp_parse_data;
 | 
			
		||||
 | 
			
		||||
int mgcp_parse_sdp_data(struct mgcp_parse_data *p);
 | 
			
		||||
 | 
			
		||||
int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
			
		||||
			    const struct mgcp_conn_rtp *conn, struct msgb *sdp,
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,10 @@
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/i460_mux.h>
 | 
			
		||||
#include <osmocom/abis/e1_input.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_network.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_ratectr.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
 | 
			
		||||
LOGP(cat, level, "trunk:%u " fmt, \
 | 
			
		||||
     trunk ? trunk->trunk_nr : 0, \
 | 
			
		||||
@@ -34,7 +35,7 @@ struct mgcp_trunk {
 | 
			
		||||
	int keepalive_interval;
 | 
			
		||||
 | 
			
		||||
	/* RTP patching */
 | 
			
		||||
	int force_constant_ssrc; /* 0: don't, 1: once */
 | 
			
		||||
	bool force_constant_ssrc;
 | 
			
		||||
	int force_aligned_timing;
 | 
			
		||||
	bool rfc5993_hr_convert;
 | 
			
		||||
 | 
			
		||||
@@ -78,6 +79,7 @@ struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_tr
 | 
			
		||||
struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);
 | 
			
		||||
int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname);
 | 
			
		||||
struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);
 | 
			
		||||
int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp);
 | 
			
		||||
 | 
			
		||||
/* The virtual trunk is always created on trunk id 0 for historical reasons,
 | 
			
		||||
 * use this define constant as ID when allocating a virtual trunk. Other
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,8 @@
 | 
			
		||||
#include <osmocom/core/osmo_io.h>
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/mgcp_client/mgcp_client.h>
 | 
			
		||||
 | 
			
		||||
#define MSGB_CB_MGCP_TRANS_ID 0
 | 
			
		||||
 | 
			
		||||
/* Struct that holds one endpoint name */
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ AM_LDFLAGS = \
 | 
			
		||||
 | 
			
		||||
# This is not at all related to the release version, but a range of supported
 | 
			
		||||
# API versions. Read TODO_RELEASE in the source tree's root!
 | 
			
		||||
MGCP_CLIENT_LIBVERSION=14:0:0
 | 
			
		||||
MGCP_CLIENT_LIBVERSION=14:1:0
 | 
			
		||||
 | 
			
		||||
lib_LTLIBRARIES = \
 | 
			
		||||
	libosmo-mgcp-client.la \
 | 
			
		||||
 
 | 
			
		||||
@@ -786,8 +786,10 @@ static void mgcp_read_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
 | 
			
		||||
	struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
 | 
			
		||||
 | 
			
		||||
	if (res <= 0) {
 | 
			
		||||
		char errbuf[128] = "";
 | 
			
		||||
		strerror_r(-res, errbuf, sizeof(errbuf));
 | 
			
		||||
		LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
 | 
			
		||||
			osmo_iofd_get_name(iofd), res, strerror(res));
 | 
			
		||||
			osmo_iofd_get_name(iofd), res, errbuf);
 | 
			
		||||
 | 
			
		||||
		msgb_free(msg);
 | 
			
		||||
		return;
 | 
			
		||||
@@ -822,8 +824,10 @@ static void mgcp_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
 | 
			
		||||
	struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
 | 
			
		||||
 | 
			
		||||
	if (OSMO_UNLIKELY(res != msg->len)) {
 | 
			
		||||
		char errbuf[128] = "";
 | 
			
		||||
		strerror_r(-res, errbuf, sizeof(errbuf));
 | 
			
		||||
		LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
 | 
			
		||||
			osmo_iofd_get_name(mgcp->iofd), res, strerror(res),
 | 
			
		||||
			osmo_iofd_get_name(mgcp->iofd), res, errbuf,
 | 
			
		||||
			msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -860,6 +864,10 @@ static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
 | 
			
		||||
	};
 | 
			
		||||
	osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
 | 
			
		||||
	msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
 | 
			
		||||
	if (!msgb_dlcx) {
 | 
			
		||||
		LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP DLCX %s\n", epname);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -873,6 +881,10 @@ static void _mgcp_client_send_auep(struct mgcp_client *mgcp, const char *epname)
 | 
			
		||||
	};
 | 
			
		||||
	OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname);
 | 
			
		||||
	msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep);
 | 
			
		||||
	if (!msgb_auep) {
 | 
			
		||||
		LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP AUEP %s\n", epname);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1047,6 +1059,7 @@ void mgcp_client_disconnect(struct mgcp_client *mgcp)
 | 
			
		||||
	osmo_iofd_txqueue_clear(mgcp->iofd);
 | 
			
		||||
	LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_iofd_get_name(mgcp->iofd));
 | 
			
		||||
	osmo_iofd_free(mgcp->iofd);
 | 
			
		||||
	mgcp->iofd = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Get the IP-Aaddress of the associated MGW as string.
 | 
			
		||||
@@ -1307,6 +1320,36 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
 | 
			
		||||
#undef MSGB_PRINTF_OR_RET
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Helper function to obtain local IP address used in MGCP towards MGW,
 | 
			
		||||
 * in string format, to fill the SDP "Origin" ("o=") field.
 | 
			
		||||
 * return 0 on success, negative on error.
 | 
			
		||||
 */
 | 
			
		||||
static int get_mgcp_local_addr(const struct mgcp_client *mgcp, char *local_ip, size_t local_ip_len)
 | 
			
		||||
{
 | 
			
		||||
	int fd;
 | 
			
		||||
 | 
			
		||||
	/* Try to get the socket local IP address if available: */
 | 
			
		||||
	if (mgcp->iofd && ((fd = osmo_iofd_get_fd(mgcp->iofd)) >= 0)) {
 | 
			
		||||
		if (osmo_sock_get_local_ip(fd, local_ip, local_ip_len) == 0)
 | 
			
		||||
			return 0;
 | 
			
		||||
		/* else: continue below */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If MGCP local address was explicitly specified in config, use it: */
 | 
			
		||||
	if (mgcp->actual.local_addr) {
 | 
			
		||||
		osmo_strlcpy(local_ip, mgcp->actual.local_addr, local_ip_len);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Guess our local address based on system routing towards MGW: */
 | 
			
		||||
	OSMO_ASSERT(local_ip_len >= INET6_ADDRSTRLEN);
 | 
			
		||||
	if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	LOGPMGW(mgcp, LOGL_ERROR, "Could not determine local IP-Address!\n");
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
 | 
			
		||||
static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_client *mgcp)
 | 
			
		||||
{
 | 
			
		||||
@@ -1316,6 +1359,7 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
			
		||||
	const char *codec;
 | 
			
		||||
	unsigned int pt;
 | 
			
		||||
	uint16_t audio_port;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
 | 
			
		||||
		if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
 | 
			
		||||
@@ -1331,11 +1375,9 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
			
		||||
	MSGB_PRINTF_OR_RET("v=0\r\n");
 | 
			
		||||
 | 
			
		||||
	/* Determine local IP-Address */
 | 
			
		||||
	if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
 | 
			
		||||
		LOGPMGW(mgcp, LOGL_ERROR,
 | 
			
		||||
			"Could not determine local IP-Address!\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	rc = get_mgcp_local_addr(mgcp, local_ip, sizeof(local_ip));
 | 
			
		||||
	if (rc < 0)
 | 
			
		||||
		return rc;
 | 
			
		||||
	local_ip_family = osmo_ip_str_type(local_ip);
 | 
			
		||||
	if (local_ip_family == AF_UNSPEC)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 
 | 
			
		||||
@@ -157,6 +157,7 @@ static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer
 | 
			
		||||
		mgcp_msg->conn_mode = conn_mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* returns message buffer containing MGXP MDCX on success, NULL on error. */
 | 
			
		||||
static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_msg mgcp_msg;
 | 
			
		||||
@@ -192,6 +193,7 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
			
		||||
	return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* returns message buffer containing MGXP DLCX on success, NULL on error. */
 | 
			
		||||
struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_msg mgcp_msg;
 | 
			
		||||
@@ -231,8 +233,10 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
		set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
			
		||||
 | 
			
		||||
		msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
			
		||||
		OSMO_ASSERT(msg);
 | 
			
		||||
 | 
			
		||||
		if (!msg) {
 | 
			
		||||
			osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
 | 
			
		||||
		mgcp_ctx->mgw_trans_pending = true;
 | 
			
		||||
		rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ libosmo_mgcp_a_SOURCES = \
 | 
			
		||||
	mgcp_endp.c \
 | 
			
		||||
	mgcp_trunk.c \
 | 
			
		||||
	mgcp_ratectr.c \
 | 
			
		||||
	mgcp_rtp_end.c \
 | 
			
		||||
	mgcp_e1.c \
 | 
			
		||||
	mgcp_iuup.c \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
 | 
			
		||||
/* Helper function to dump codec information of a specified codec to a printable
 | 
			
		||||
 * string, used by dump_codec_summary() */
 | 
			
		||||
static char *dump_codec(struct mgcp_rtp_codec *codec)
 | 
			
		||||
static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
 | 
			
		||||
{
 | 
			
		||||
	static char str[256];
 | 
			
		||||
	char *pt_str;
 | 
			
		||||
@@ -49,31 +49,25 @@ static char *dump_codec(struct mgcp_rtp_codec *codec)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Dump a summary of all negotiated codecs to debug log
 | 
			
		||||
 *  \param[in] conn related rtp-connection. */
 | 
			
		||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
 | 
			
		||||
 *  \param[in] cset related codecset.
 | 
			
		||||
 *  \param[in] prefix_str Prefix string to print during logging.
 | 
			
		||||
 * */
 | 
			
		||||
void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_rtp_end *rtp;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	struct mgcp_rtp_codec *codec;
 | 
			
		||||
	struct mgcp_endpoint *endp;
 | 
			
		||||
 | 
			
		||||
	rtp = &conn->end;
 | 
			
		||||
	endp = conn->conn->endp;
 | 
			
		||||
 | 
			
		||||
	if (rtp->codecs_assigned == 0) {
 | 
			
		||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR, "conn:%s no codecs available\n",
 | 
			
		||||
			 mgcp_conn_dump(conn->conn));
 | 
			
		||||
	if (cset->codecs_assigned == 0) {
 | 
			
		||||
		LOGP(DLMGCP, LOGL_ERROR, "%s no codecs available\n", prefix_str);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Store parsed codec information */
 | 
			
		||||
	for (i = 0; i < rtp->codecs_assigned; i++) {
 | 
			
		||||
		codec = &rtp->codecs[i];
 | 
			
		||||
	for (i = 0; i < cset->codecs_assigned; i++) {
 | 
			
		||||
		struct mgcp_rtp_codec *codec = &cset->codecs[i];
 | 
			
		||||
 | 
			
		||||
		LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s",
 | 
			
		||||
			 mgcp_conn_dump(conn->conn), i, dump_codec(codec));
 | 
			
		||||
		LOGP(DLMGCP, LOGL_DEBUG, "%s codecs[%u]:%s", prefix_str, i, mgcp_codec_dump(codec));
 | 
			
		||||
 | 
			
		||||
		if (codec == rtp->codec)
 | 
			
		||||
		if (codec == cset->codec)
 | 
			
		||||
			LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
 | 
			
		||||
 | 
			
		||||
		LOGPC(DLMGCP, LOGL_DEBUG, "\n");
 | 
			
		||||
@@ -81,7 +75,7 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initalize or reset codec information with default data. */
 | 
			
		||||
static void codec_init(struct mgcp_rtp_codec *codec)
 | 
			
		||||
static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
 | 
			
		||||
{
 | 
			
		||||
	*codec = (struct mgcp_rtp_codec){
 | 
			
		||||
		.payload_type = -1,
 | 
			
		||||
@@ -94,20 +88,20 @@ static void codec_init(struct mgcp_rtp_codec *codec)
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void codec_free(struct mgcp_rtp_codec *codec)
 | 
			
		||||
static void mgcp_codec_free(struct mgcp_rtp_codec *codec)
 | 
			
		||||
{
 | 
			
		||||
	*codec = (struct mgcp_rtp_codec){};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Initalize or reset codec information with default data.
 | 
			
		||||
 *  \param[out] conn related rtp-connection. */
 | 
			
		||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
 | 
			
		||||
void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i = 0; i < conn->end.codecs_assigned; i++)
 | 
			
		||||
		codec_free(&conn->end.codecs[i]);
 | 
			
		||||
	conn->end.codecs_assigned = 0;
 | 
			
		||||
	conn->end.codec = NULL;
 | 
			
		||||
	for (i = 0; i < cset->codecs_assigned; i++)
 | 
			
		||||
		mgcp_codec_free(&cset->codecs[i]);
 | 
			
		||||
	cset->codecs_assigned = 0;
 | 
			
		||||
	cset->codec = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Add codec configuration depending on payload type and/or codec name. This
 | 
			
		||||
@@ -118,23 +112,23 @@ void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
 | 
			
		||||
 *  \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
 | 
			
		||||
 *  \param[in] param optional codec parameters (set to NULL when unused).
 | 
			
		||||
 *  \returns 0 on success, -EINVAL on failure. */
 | 
			
		||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
 | 
			
		||||
int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
 | 
			
		||||
{
 | 
			
		||||
	int rate;
 | 
			
		||||
	int channels;
 | 
			
		||||
	struct mgcp_rtp_codec *codec;
 | 
			
		||||
	unsigned int pt_offset = conn->end.codecs_assigned;
 | 
			
		||||
	unsigned int pt_offset = cset->codecs_assigned;
 | 
			
		||||
 | 
			
		||||
	/* The amount of codecs we can store is limited, make sure we do not
 | 
			
		||||
	 * overrun this limit. */
 | 
			
		||||
	if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
 | 
			
		||||
	if (cset->codecs_assigned >= MGCP_MAX_CODECS)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	/* First unused entry */
 | 
			
		||||
	codec = &conn->end.codecs[conn->end.codecs_assigned];
 | 
			
		||||
	codec = &cset->codecs[cset->codecs_assigned];
 | 
			
		||||
 | 
			
		||||
	/* Initalize the codec struct with some default data to begin with */
 | 
			
		||||
	codec_init(codec);
 | 
			
		||||
	mgcp_codec_init(codec);
 | 
			
		||||
 | 
			
		||||
	if (payload_type != PTYPE_UNDEFINED) {
 | 
			
		||||
		/* Make sure we do not get any reserved or undefined type numbers */
 | 
			
		||||
@@ -268,11 +262,11 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
 | 
			
		||||
	} else
 | 
			
		||||
		codec->param_present = false;
 | 
			
		||||
 | 
			
		||||
	conn->end.codecs_assigned++;
 | 
			
		||||
	cset->codecs_assigned++;
 | 
			
		||||
	return 0;
 | 
			
		||||
error:
 | 
			
		||||
	/* Make sure we leave a clean codec entry on error. */
 | 
			
		||||
	codec_free(codec);
 | 
			
		||||
	mgcp_codec_free(codec);
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -296,7 +290,7 @@ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Compare two codecs, all parameters must match up */
 | 
			
		||||
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
			
		||||
static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
 | 
			
		||||
{
 | 
			
		||||
	/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers
 | 
			
		||||
	 * exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal
 | 
			
		||||
@@ -325,7 +319,7 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
 | 
			
		||||
static bool codecs_convertible(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
			
		||||
static bool codecs_convertible(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
 | 
			
		||||
{
 | 
			
		||||
	/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to
 | 
			
		||||
	 * translate between different payload formats as long as the encoded voice data itself does not change.
 | 
			
		||||
@@ -354,21 +348,18 @@ iufp:
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
 | 
			
		||||
struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_rtp_end *rtp_end;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	unsigned int codecs_assigned;
 | 
			
		||||
 | 
			
		||||
	rtp_end = &conn->end;
 | 
			
		||||
 | 
			
		||||
	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
 | 
			
		||||
	 * the first run we will look for an exact match. */
 | 
			
		||||
	codecs_assigned = rtp_end->codecs_assigned;
 | 
			
		||||
	codecs_assigned = cset->codecs_assigned;
 | 
			
		||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
			
		||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
			
		||||
		if (codecs_same(codec, &rtp_end->codecs[i])) {
 | 
			
		||||
			return &rtp_end->codecs[i];
 | 
			
		||||
		if (codecs_same(codec, &cset->codecs[i])) {
 | 
			
		||||
			return &cset->codecs[i];
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -377,28 +368,26 @@ struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* For a given codec, find a convertible codec in the given connection. */
 | 
			
		||||
static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
 | 
			
		||||
static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_rtp_end *rtp_end;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	unsigned int codecs_assigned;
 | 
			
		||||
	struct mgcp_rtp_codec *codec_convertible = NULL;
 | 
			
		||||
 | 
			
		||||
	rtp_end = &conn->end;
 | 
			
		||||
 | 
			
		||||
	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
 | 
			
		||||
	 * the first run we will look for an exact match. */
 | 
			
		||||
	codec_convertible = mgcp_codec_find_same(conn, codec);
 | 
			
		||||
	codec_convertible = mgcp_codecset_find_same(cset, codec);
 | 
			
		||||
	if (codec_convertible)
 | 
			
		||||
		return codec_convertible;
 | 
			
		||||
 | 
			
		||||
	/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the
 | 
			
		||||
	 * payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
 | 
			
		||||
	codecs_assigned = rtp_end->codecs_assigned;
 | 
			
		||||
	codecs_assigned = cset->codecs_assigned;
 | 
			
		||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
			
		||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
			
		||||
		if (codecs_convertible(codec, &rtp_end->codecs[i])) {
 | 
			
		||||
			codec_convertible = &rtp_end->codecs[i];
 | 
			
		||||
		if (codecs_convertible(codec, &cset->codecs[i])) {
 | 
			
		||||
			codec_convertible = &cset->codecs[i];
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -408,20 +397,20 @@ static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn,
 | 
			
		||||
 | 
			
		||||
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
 | 
			
		||||
 *  a tentative decision is made.
 | 
			
		||||
 *  \param[inout] conn_src related rtp-connection.
 | 
			
		||||
 *  \param[inout] conn_dst related destination rtp-connection (NULL if not present).
 | 
			
		||||
 *  \param[in] cset_src related codec set.
 | 
			
		||||
 *  \param[inout] cset_dst related destination codec set (NULL if not present).
 | 
			
		||||
 *  \returns 0 on success, -EINVAL on failure. */
 | 
			
		||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
 | 
			
		||||
int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	/* In case no destination connection is available (yet), or in case the destination connection exists but has
 | 
			
		||||
	 * no codecs assigned, we are forced to make a simple tentative decision:
 | 
			
		||||
	 * We just use the first codec of the source connection (conn_src) */
 | 
			
		||||
	OSMO_ASSERT(conn_src->end.codecs_assigned <= MGCP_MAX_CODECS);
 | 
			
		||||
	if (!conn_dst || conn_dst->end.codecs_assigned == 0) {
 | 
			
		||||
		if (conn_src->end.codecs_assigned >= 1) {
 | 
			
		||||
			conn_src->end.codec = &conn_src->end.codecs[0];
 | 
			
		||||
	OSMO_ASSERT(cset_src->codecs_assigned <= MGCP_MAX_CODECS);
 | 
			
		||||
	if (!cset_dst || cset_dst->codecs_assigned == 0) {
 | 
			
		||||
		if (cset_src->codecs_assigned >= 1) {
 | 
			
		||||
			cset_src->codec = &cset_src->codecs[0];
 | 
			
		||||
			return 0;
 | 
			
		||||
		} else
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
@@ -430,38 +419,38 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn
 | 
			
		||||
	/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
 | 
			
		||||
	 * of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
 | 
			
		||||
	 * required. */
 | 
			
		||||
	for (i = 0; i < conn_src->end.codecs_assigned; i++) {
 | 
			
		||||
		struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
 | 
			
		||||
		struct mgcp_rtp_codec *codec_conn_dst = mgcp_codec_find_same(conn_dst, codec_conn_src);
 | 
			
		||||
		if (codec_conn_dst) {
 | 
			
		||||
	for (i = 0; i < cset_src->codecs_assigned; i++) {
 | 
			
		||||
		struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
 | 
			
		||||
		struct mgcp_rtp_codec *codec_cset_dst = mgcp_codecset_find_same(cset_dst, codec_cset_src);
 | 
			
		||||
		if (codec_cset_dst) {
 | 
			
		||||
			/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both
 | 
			
		||||
			 * sides. We now set this codec on both connections. */
 | 
			
		||||
			conn_dst->end.codec = codec_conn_dst;
 | 
			
		||||
			conn_src->end.codec = codec_conn_src;
 | 
			
		||||
			cset_dst->codec = codec_cset_dst;
 | 
			
		||||
			cset_src->codec = codec_cset_src;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* In case we could not find a codec that is exactly the same, let's at least try to find a codec that we are able
 | 
			
		||||
	 * to convert. */
 | 
			
		||||
	for (i = 0; i < conn_src->end.codecs_assigned; i++) {
 | 
			
		||||
		struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
 | 
			
		||||
		struct mgcp_rtp_codec *codec_conn_dst = codec_find_convertible(conn_dst, codec_conn_src);
 | 
			
		||||
		if (codec_conn_dst) {
 | 
			
		||||
	for (i = 0; i < cset_src->codecs_assigned; i++) {
 | 
			
		||||
		struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
 | 
			
		||||
		struct mgcp_rtp_codec *codec_cset_dst = codecset_find_convertible(cset_dst, codec_cset_src);
 | 
			
		||||
		if (codec_cset_dst) {
 | 
			
		||||
			/* We found the a codec that we can convert to. Set each side to its codec. */
 | 
			
		||||
			conn_dst->end.codec = codec_conn_dst;
 | 
			
		||||
			conn_src->end.codec = codec_conn_src;
 | 
			
		||||
			cset_dst->codec = codec_cset_dst;
 | 
			
		||||
			cset_src->codec = codec_cset_src;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (conn_dst->end.codecs_assigned)
 | 
			
		||||
		conn_dst->end.codec = &conn_dst->end.codecs[0];
 | 
			
		||||
	if (cset_dst->codecs_assigned)
 | 
			
		||||
		cset_dst->codec = &cset_dst->codecs[0];
 | 
			
		||||
	else
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (conn_src->end.codecs_assigned)
 | 
			
		||||
		conn_src->end.codec = &conn_src->end.codecs[0];
 | 
			
		||||
	if (cset_src->codecs_assigned)
 | 
			
		||||
		cset_src->codec = &cset_src->codecs[0];
 | 
			
		||||
	else
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
@@ -488,38 +477,36 @@ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
 | 
			
		||||
 * \param match_nr  Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
 | 
			
		||||
 *                  with incrementing match_nr.
 | 
			
		||||
 * \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found. */
 | 
			
		||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
			
		||||
const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
 | 
			
		||||
								const char *subtype_name, unsigned int match_nr)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i = 0; i < conn->end.codecs_assigned; i++) {
 | 
			
		||||
		if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
 | 
			
		||||
	for (i = 0; i < cset->codecs_assigned; i++) {
 | 
			
		||||
		if (!strcmp(cset->codecs[i].subtype_name, subtype_name)) {
 | 
			
		||||
			if (match_nr) {
 | 
			
		||||
				match_nr--;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			return &conn->end.codecs[i];
 | 
			
		||||
			return &cset->codecs[i];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Lookup a codec that is assigned to a connection by its payload type number.
 | 
			
		||||
 *  \param[in] conn related rtp-connection.
 | 
			
		||||
 *  \param[in] cset related codec set.
 | 
			
		||||
 *  \param[in] payload_type number of the codec to look up.
 | 
			
		||||
 *  \returns pointer to codec struct on success, NULL on failure. */
 | 
			
		||||
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type)
 | 
			
		||||
struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_rtp_end *rtp_end = &conn->end;
 | 
			
		||||
	unsigned int codecs_assigned = rtp_end->codecs_assigned;
 | 
			
		||||
	struct mgcp_rtp_codec *codec = NULL;
 | 
			
		||||
	size_t i;
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
			
		||||
	OSMO_ASSERT(cset->codecs_assigned <= MGCP_MAX_CODECS);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
			
		||||
		if (payload_type == rtp_end->codecs[i].payload_type) {
 | 
			
		||||
			codec = &rtp_end->codecs[i];
 | 
			
		||||
	for (i = 0; i < cset->codecs_assigned; i++) {
 | 
			
		||||
		if (payload_type == cset->codecs[i].payload_type) {
 | 
			
		||||
			codec = &cset->codecs[i];
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,7 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
 | 
			
		||||
 | 
			
		||||
		/* ensure that the generated conn_id is unique
 | 
			
		||||
		 * for this endpoint */
 | 
			
		||||
		if (!mgcp_conn_get_rtp(endp, id_hex)) {
 | 
			
		||||
		if (!mgcp_endp_get_conn_rtp(endp, id_hex)) {
 | 
			
		||||
			osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
@@ -88,7 +88,6 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
 | 
			
		||||
/* Initialize rtp connection struct with default values */
 | 
			
		||||
static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_rtp_end *end = &conn_rtp->end;
 | 
			
		||||
	/* FIXME: Each new rate counter group requires an unique index. At the
 | 
			
		||||
	 * moment we generate this index using this counter, but perhaps there
 | 
			
		||||
	 * is a more concious way to assign the indexes. */
 | 
			
		||||
@@ -106,17 +105,6 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
 | 
			
		||||
	/* backpointer to the generic part of the connection */
 | 
			
		||||
	conn->u.rtp.conn = conn;
 | 
			
		||||
 | 
			
		||||
	end->rtp = NULL;
 | 
			
		||||
	end->rtcp = NULL;
 | 
			
		||||
	memset(&end->addr, 0, sizeof(end->addr));
 | 
			
		||||
	end->rtcp_port = 0;
 | 
			
		||||
 | 
			
		||||
	/* Set default values */
 | 
			
		||||
	end->frames_per_packet = 0;	/* unknown */
 | 
			
		||||
	end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
			
		||||
	end->output_enabled = false;
 | 
			
		||||
	end->maximum_packet_time = -1;
 | 
			
		||||
 | 
			
		||||
	conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
 | 
			
		||||
	if (!conn_rtp->ctrg)
 | 
			
		||||
		return -1;
 | 
			
		||||
@@ -124,9 +112,7 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
 | 
			
		||||
	conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR);
 | 
			
		||||
	conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
 | 
			
		||||
 | 
			
		||||
	/* Make sure codec table is reset */
 | 
			
		||||
	mgcp_codec_reset_all(conn_rtp);
 | 
			
		||||
 | 
			
		||||
	mgcp_rtp_end_init(&conn_rtp->end, conn_rtp);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -137,16 +123,15 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *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);
 | 
			
		||||
	mgcp_rtp_end_cleanup(&conn_rtp->end);
 | 
			
		||||
	rate_ctr_group_free(conn_rtp->ctrg);
 | 
			
		||||
	mgcp_codec_reset_all(conn_rtp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mgcp_conn_watchdog_cb(void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn = data;
 | 
			
		||||
	LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
 | 
			
		||||
	mgcp_conn_free(conn->endp, conn->id);
 | 
			
		||||
	mgcp_conn_free(conn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
 | 
			
		||||
@@ -212,58 +197,6 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
			
		||||
	return conn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! find a connection by its ID.
 | 
			
		||||
 *  \param[in] endp associated endpoint
 | 
			
		||||
 *  \param[in] id identification number of the connection
 | 
			
		||||
 *  \returns pointer to allocated connection, NULL if not found */
 | 
			
		||||
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
	const char *id_upper;
 | 
			
		||||
	const char *conn_id;
 | 
			
		||||
 | 
			
		||||
	if (!id || !*id)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* Ignore leading zeros in needle */
 | 
			
		||||
	while (*id == '0')
 | 
			
		||||
		id++;
 | 
			
		||||
 | 
			
		||||
	/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
 | 
			
		||||
	 * Connections" defines the id as a hex string, so clients may return lower case hex even though
 | 
			
		||||
	 * we sent upper case hex in the CRCX response. */
 | 
			
		||||
	id_upper = osmo_str_toupper(id);
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(conn, &endp->conns, entry) {
 | 
			
		||||
		/* Ignore leading zeros in haystack */
 | 
			
		||||
		for (conn_id=conn->id; *conn_id == '0'; conn_id++);
 | 
			
		||||
 | 
			
		||||
		if (strcmp(conn_id, id_upper) == 0)
 | 
			
		||||
			return conn;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! find an RTP connection by its ID.
 | 
			
		||||
 *  \param[in] endp associated endpoint
 | 
			
		||||
 *  \param[in] id identification number of the connection
 | 
			
		||||
 *  \returns pointer to allocated connection, NULL if not found */
 | 
			
		||||
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
 | 
			
		||||
					const char *id)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
 | 
			
		||||
	conn = mgcp_conn_get(endp, id);
 | 
			
		||||
	if (!conn)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (conn->type == MGCP_CONN_TYPE_RTP)
 | 
			
		||||
		return &conn->u.rtp;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
			
		||||
{
 | 
			
		||||
	struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
			
		||||
@@ -286,21 +219,21 @@ static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_con
 | 
			
		||||
	rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! free a connection by its ID.
 | 
			
		||||
 *  \param[in] endp associated endpoint
 | 
			
		||||
 *  \param[in] id identification number of the connection */
 | 
			
		||||
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
 | 
			
		||||
/*! free a connection
 | 
			
		||||
 *  \param[in] conn the conn to free. May be NULL.
 | 
			
		||||
*/
 | 
			
		||||
void mgcp_conn_free(struct mgcp_conn *conn)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
	struct mgcp_conn_rtp *conn_rtp;
 | 
			
		||||
 | 
			
		||||
	conn = mgcp_conn_get(endp, id);
 | 
			
		||||
	if (!conn)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	switch (conn->type) {
 | 
			
		||||
	case MGCP_CONN_TYPE_RTP:
 | 
			
		||||
		aggregate_rtp_conn_stats(endp, &conn->u.rtp);
 | 
			
		||||
		mgcp_rtp_conn_cleanup(&conn->u.rtp);
 | 
			
		||||
		conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
			
		||||
		aggregate_rtp_conn_stats(conn->endp, conn_rtp);
 | 
			
		||||
		mgcp_rtp_conn_cleanup(conn_rtp);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		/* NOTE: This should never be called with an
 | 
			
		||||
@@ -310,43 +243,40 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	osmo_timer_del(&conn->watchdog);
 | 
			
		||||
	mgcp_endp_remove_conn(endp, conn);
 | 
			
		||||
	mgcp_endp_remove_conn(conn->endp, conn);
 | 
			
		||||
	/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
 | 
			
		||||
	talloc_free(conn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! free oldest connection in the list.
 | 
			
		||||
 *  \param[in] endp associated endpoint */
 | 
			
		||||
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
 | 
			
		||||
/*! Parse connection mode.
 | 
			
		||||
 *  \param[in] conn Connection whose mode is being set
 | 
			
		||||
 *  \param[in] mode Mode to set
 | 
			
		||||
 *  \returns 0 on success, -1 on error */
 | 
			
		||||
int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	if (mode == MGCP_CONN_NONE) {
 | 
			
		||||
		LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
			
		||||
			 "missing connection mode\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	conn->mode = mode;
 | 
			
		||||
	LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
 | 
			
		||||
		 mgcp_cmode_name(mode), conn->mode);
 | 
			
		||||
 | 
			
		||||
	if (llist_empty(&endp->conns))
 | 
			
		||||
		return;
 | 
			
		||||
	/* Special handling for RTP connections */
 | 
			
		||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
			
		||||
		struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
			
		||||
		conn_rtp->end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
 | 
			
		||||
		LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
 | 
			
		||||
			 conn_rtp->end.output_enabled);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
			
		||||
	if (!conn)
 | 
			
		||||
		return;
 | 
			
		||||
	/* The VTY might change the connection mode at any time, so we have
 | 
			
		||||
	 * to hold a copy of the original connection mode */
 | 
			
		||||
	conn->mode_orig = conn->mode;
 | 
			
		||||
 | 
			
		||||
	mgcp_conn_free(endp, conn->id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! free all connections at once.
 | 
			
		||||
 *  \param[in] endp associated endpoint */
 | 
			
		||||
#if defined(__has_attribute)
 | 
			
		||||
#if __has_attribute(no_sanitize)
 | 
			
		||||
__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
 | 
			
		||||
	/* Drop all items in the list, might be consecutive! */
 | 
			
		||||
	while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
 | 
			
		||||
		mgcp_conn_free(endp, conn->id);
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! dump basic connection information to human readable string.
 | 
			
		||||
@@ -357,24 +287,26 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
 | 
			
		||||
	static char str[sizeof(conn->name)+sizeof(conn->id)+256];
 | 
			
		||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
			
		||||
	struct osmo_strbuf sb = { .buf = str, .len = sizeof(str) };
 | 
			
		||||
	struct mgcp_conn_rtp *conn_rtp;
 | 
			
		||||
 | 
			
		||||
	if (!conn)
 | 
			
		||||
		return "NULL";
 | 
			
		||||
 | 
			
		||||
	switch (conn->type) {
 | 
			
		||||
	case MGCP_CONN_TYPE_RTP:
 | 
			
		||||
		conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
			
		||||
		OSMO_STRBUF_PRINTF(sb, "(%s/%s C:%s r=%s:%u<->l=%s:%u",
 | 
			
		||||
				   conn->name,
 | 
			
		||||
				   mgcp_conn_rtp_type_name(conn->type),
 | 
			
		||||
				   conn->id,
 | 
			
		||||
				   osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf) ? : "NULL",
 | 
			
		||||
				   osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
 | 
			
		||||
				   conn->u.rtp.end.local_addr ? : "NULL",
 | 
			
		||||
				   conn->u.rtp.end.local_port);
 | 
			
		||||
				   osmo_sockaddr_ntop(&conn_rtp->end.addr.u.sa, ipbuf) ? : "NULL",
 | 
			
		||||
				   osmo_sockaddr_port(&conn_rtp->end.addr.u.sa),
 | 
			
		||||
				   conn_rtp->end.local_addr ? : "NULL",
 | 
			
		||||
				   conn_rtp->end.local_port);
 | 
			
		||||
 | 
			
		||||
		switch (conn->u.rtp.type) {
 | 
			
		||||
		switch (conn_rtp->type) {
 | 
			
		||||
		case MGCP_RTP_OSMUX:
 | 
			
		||||
			OSMO_STRBUF_PRINTF(sb, " CID=%u", conn->u.rtp.osmux.local_cid);
 | 
			
		||||
			OSMO_STRBUF_PRINTF(sb, " CID=%u", conn_rtp->osmux.local_cid);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
@@ -414,16 +346,6 @@ struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn)
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! get oldest connection in the list.
 | 
			
		||||
 *  \param[in] endp associated endpoint */
 | 
			
		||||
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	if (llist_empty(&endp->conns))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct value_string mgcp_conn_rtp_type_names[] = {
 | 
			
		||||
	{ MGCP_RTP_DEFAULT, "rtp" },
 | 
			
		||||
	{ MGCP_RTP_OSMUX, "osmux" },
 | 
			
		||||
 
 | 
			
		||||
@@ -56,133 +56,147 @@ static const struct e1inp_line_ops dummy_e1_line_ops = {
 | 
			
		||||
	.sign_link = NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* EFR idle frame */
 | 
			
		||||
static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 1, 1, 0, 1, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 1, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				      1, 0, 0, 0, 0, 0, 1, 0,
 | 
			
		||||
				      1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
/* 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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* FR idle frame */
 | 
			
		||||
static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 1, 1, 1, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 1, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
				     1, 0, 0, 0, 0, 0, 1, 0,
 | 
			
		||||
				     1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
/* 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,
 | 
			
		||||
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
 | 
			
		||||
@@ -650,15 +664,17 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
 | 
			
		||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
	struct mgcp_conn_rtp *conn_rtp;
 | 
			
		||||
	struct mgcp_rtp_codec *codec;
 | 
			
		||||
	enum osmo_tray_sync_pat_id sync_pat_id;
 | 
			
		||||
 | 
			
		||||
	/* In order to determine the codec, find the oldest connection on
 | 
			
		||||
	 * the endpoint and use its codec information. Normally on an E1
 | 
			
		||||
	 * endpoint no more than one connection should exist. */
 | 
			
		||||
	conn = mgcp_conn_get_oldest(endp);
 | 
			
		||||
	conn = mgcp_endp_get_conn_oldest(endp);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	codec = conn->u.rtp.end.codec;
 | 
			
		||||
	conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
			
		||||
	codec = conn_rtp->end.cset.codec;
 | 
			
		||||
	OSMO_ASSERT(codec);
 | 
			
		||||
 | 
			
		||||
	/* Update codec information */
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ static char *gen_virtual_epname(void *ctx, const char *domain,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Generate E1 endpoint name from given numeric parameters */
 | 
			
		||||
static char *gen_e1_epname(void *ctx, const char *domain, unsigned int trunk_nr,
 | 
			
		||||
static char *gen_e1_epname(const void *ctx, const char *domain, unsigned int trunk_nr,
 | 
			
		||||
			   uint8_t ts_nr, uint8_t ss_nr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int rate;
 | 
			
		||||
@@ -446,7 +446,7 @@ static uint8_t e1_ss_nr_from_epname(const char *epname)
 | 
			
		||||
/* Check if the selected E1 endpoint is avalable, which means that none of
 | 
			
		||||
 * the overlapping endpoints are currently serving a call. (if the system
 | 
			
		||||
 * is properly configured such a situation should never ocurr!) */
 | 
			
		||||
static bool endp_avail_e1(struct mgcp_endpoint *endp)
 | 
			
		||||
static bool endp_avail_e1(const struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	/* The following map shows the overlapping of the subslots and their
 | 
			
		||||
	 * respective rates. The numbers on the right running from top to bottom
 | 
			
		||||
@@ -552,7 +552,7 @@ static bool endp_avail_e1(struct mgcp_endpoint *endp)
 | 
			
		||||
/*! check if an endpoint is available for any kind of operation.
 | 
			
		||||
 *  \param[in] endp endpoint to check.
 | 
			
		||||
 *  \returns true if endpoint is avalable, false it is blocked for any reason. */
 | 
			
		||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp)
 | 
			
		||||
bool mgcp_endp_avail(const struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	switch (endp->trunk->trunk_type) {
 | 
			
		||||
	case MGCP_TRUNK_VIRTUAL:
 | 
			
		||||
@@ -569,6 +569,24 @@ bool mgcp_endp_avail(struct mgcp_endpoint *endp)
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Get number of conns in an endpoint.
 | 
			
		||||
 *  \param[in] endp endpoint to check.
 | 
			
		||||
 *  \returns Number of connections present in the endpoint. */
 | 
			
		||||
unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	return llist_count(&endp->conns);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! check if an endpoint can in current state allocate new conns.
 | 
			
		||||
 *  \param[in] endp endpoint to check.
 | 
			
		||||
 *  \returns true if more connections can be allowed on endpoint, false if it is already busy. */
 | 
			
		||||
bool mgcp_endp_is_full(const struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	if (endp->type->max_conns == 0)
 | 
			
		||||
		return false;
 | 
			
		||||
	return mgcp_endp_num_conns(endp) >= endp->type->max_conns;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! claim endpoint, sets callid and activates endpoint, should be called at the
 | 
			
		||||
 *  beginning of the CRCX procedure when it is clear that a new call should be
 | 
			
		||||
 *  created.
 | 
			
		||||
@@ -655,6 +673,97 @@ void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
 | 
			
		||||
		mgcp_endp_release(endp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! free oldest connection in the list.
 | 
			
		||||
 *  \param[in] endp associated endpoint */
 | 
			
		||||
void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
 | 
			
		||||
	if (llist_empty(&endp->conns))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
			
		||||
	mgcp_conn_free(conn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! free all connections at once.
 | 
			
		||||
 *  \param[in] endp associated endpoint */
 | 
			
		||||
#if defined(__has_attribute)
 | 
			
		||||
#if __has_attribute(no_sanitize)
 | 
			
		||||
__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
 | 
			
		||||
	/* Drop all items in the list, might be consecutive! */
 | 
			
		||||
	while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
 | 
			
		||||
		mgcp_conn_free(conn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! find a connection by its ID.
 | 
			
		||||
 *  \param[in] endp associated endpoint
 | 
			
		||||
 *  \param[in] id identification number of the connection
 | 
			
		||||
 *  \returns pointer to allocated connection, NULL if not found */
 | 
			
		||||
struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
	const char *id_upper;
 | 
			
		||||
	const char *conn_id;
 | 
			
		||||
 | 
			
		||||
	if (!id || !*id)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* Ignore leading zeros in needle */
 | 
			
		||||
	while (*id == '0')
 | 
			
		||||
		id++;
 | 
			
		||||
 | 
			
		||||
	/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
 | 
			
		||||
	 * Connections" defines the id as a hex string, so clients may return lower case hex even though
 | 
			
		||||
	 * we sent upper case hex in the CRCX response. */
 | 
			
		||||
	id_upper = osmo_str_toupper(id);
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(conn, &endp->conns, entry) {
 | 
			
		||||
		/* Ignore leading zeros in haystack */
 | 
			
		||||
		for (conn_id = conn->id; *conn_id == '0'; conn_id++);
 | 
			
		||||
 | 
			
		||||
		if (strcmp(conn_id, id_upper) == 0)
 | 
			
		||||
			return conn;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! get oldest connection in the list.
 | 
			
		||||
 *  \param[in] endp associated endpoint */
 | 
			
		||||
struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	if (llist_empty(&endp->conns))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! find an RTP connection by its ID.
 | 
			
		||||
 *  \param[in] endp associated endpoint
 | 
			
		||||
 *  \param[in] id identification number of the connection
 | 
			
		||||
 *  \returns pointer to allocated connection, NULL if not found */
 | 
			
		||||
struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
 | 
			
		||||
					const char *id)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_conn *conn;
 | 
			
		||||
 | 
			
		||||
	conn = mgcp_endp_get_conn(endp, id);
 | 
			
		||||
	if (!conn)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (conn->type == MGCP_CONN_TYPE_RTP)
 | 
			
		||||
		return mgcp_conn_get_conn_rtp(conn);
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! release endpoint, all open connections are closed.
 | 
			
		||||
 *  \param[in] endp endpoint to release */
 | 
			
		||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
			
		||||
@@ -665,7 +774,7 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
			
		||||
	 * all connections have been removed already. In case
 | 
			
		||||
	 * that there are still connections open (e.g. when
 | 
			
		||||
	 * RSIP is executed), free them all at once. */
 | 
			
		||||
	mgcp_conn_free_all(endp);
 | 
			
		||||
	mgcp_endp_free_conn_all(endp);
 | 
			
		||||
 | 
			
		||||
	/* We must only decrement the stat item when the endpoint as actually
 | 
			
		||||
	 * claimed. An endpoint is claimed when a call-id is set */
 | 
			
		||||
 
 | 
			
		||||
@@ -264,6 +264,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
 | 
			
		||||
	uint8_t *amr_data;
 | 
			
		||||
	struct rtp_hdr *rtp_hdr;
 | 
			
		||||
	struct amr_hdr *amr_hdr;
 | 
			
		||||
	struct mgcp_rtp_codec *dst_codec;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
 | 
			
		||||
@@ -275,7 +276,8 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
 | 
			
		||||
	}
 | 
			
		||||
	msgb_pull_to_l3(msg);
 | 
			
		||||
 | 
			
		||||
	if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
 | 
			
		||||
	dst_codec = conn_rtp_dst->end.cset.codec;
 | 
			
		||||
	if (mgcp_codec_amr_is_octet_aligned(dst_codec)) {
 | 
			
		||||
		LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
 | 
			
		||||
		amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
 | 
			
		||||
		amr_hdr->cmr = 15; /* no change */
 | 
			
		||||
@@ -303,7 +305,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
 | 
			
		||||
		.extension = 0,
 | 
			
		||||
		.padding = 0,
 | 
			
		||||
		.version = 0,
 | 
			
		||||
		.payload_type = conn_rtp_dst->end.codec->payload_type,
 | 
			
		||||
		.payload_type = dst_codec->payload_type,
 | 
			
		||||
		.marker = 0,
 | 
			
		||||
		.sequence = frame_nr,
 | 
			
		||||
		.timestamp = 0,
 | 
			
		||||
@@ -502,7 +504,7 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
			
		||||
	 * 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->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
 | 
			
		||||
	hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
 | 
			
		||||
	hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
 | 
			
		||||
	rtp_state->alt_rtp_tx_sequence++;
 | 
			
		||||
@@ -544,13 +546,13 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
 | 
			
		||||
 | 
			
		||||
	msgb_pull_to_l2(msg);
 | 
			
		||||
	rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
 | 
			
		||||
	/* TODO: fill rtph properly: */
 | 
			
		||||
	/* rtph is further filled in mgcp_send_iuup() below. */
 | 
			
		||||
	*rtph = (struct rtp_hdr){
 | 
			
		||||
		.csrc_count = 0,
 | 
			
		||||
		.extension = 0,
 | 
			
		||||
		.padding = 0,
 | 
			
		||||
		.version = 2,
 | 
			
		||||
		.payload_type = conn_rtp_dst->end.codec->payload_type,
 | 
			
		||||
		.payload_type = conn_rtp_dst->end.cset.codec->payload_type,
 | 
			
		||||
		.marker = 0,
 | 
			
		||||
		.sequence = 0,
 | 
			
		||||
		.timestamp = 0,
 | 
			
		||||
@@ -645,6 +647,7 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
 | 
			
		||||
	struct rtp_hdr *rtph;
 | 
			
		||||
	int rc = -1;
 | 
			
		||||
	int iuup_length = 0;
 | 
			
		||||
	struct mgcp_rtp_codec *src_codec;
 | 
			
		||||
	int8_t rfci;
 | 
			
		||||
 | 
			
		||||
	/* Tx RNL-DATA.req */
 | 
			
		||||
@@ -657,13 +660,14 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
 | 
			
		||||
 | 
			
		||||
	/* TODO: CMR handling & multiple frames handling */
 | 
			
		||||
 | 
			
		||||
	if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) {
 | 
			
		||||
	src_codec = conn_src_rtp->end.cset.codec;
 | 
			
		||||
	if (strcmp(src_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);
 | 
			
		||||
			     src_codec->subtype_name);
 | 
			
		||||
		goto free_ret;
 | 
			
		||||
	}
 | 
			
		||||
	if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
 | 
			
		||||
	if (mgcp_codec_amr_is_octet_aligned(src_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,
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/mgcp/mgcp.h>
 | 
			
		||||
#include <osmocom/mgcp/osmux.h>
 | 
			
		||||
@@ -33,6 +34,10 @@
 | 
			
		||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
			
		||||
 | 
			
		||||
/* (same fmt as LOGPENDP()) */
 | 
			
		||||
#define LOG_MGCP_PDATA(PDATA, LEVEL, FMT, 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
 | 
			
		||||
 *  \param[in] len message mgcp message string length
 | 
			
		||||
@@ -76,61 +81,24 @@ void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
 | 
			
		||||
 | 
			
		||||
/*! Parse connection mode.
 | 
			
		||||
 *  \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback)
 | 
			
		||||
 *  \param[in] endp pointer to endpoint (only used for log output)
 | 
			
		||||
 *  \param[out] associated connection to be modified accordingly
 | 
			
		||||
 *  \returns 0 on success, -1 on error */
 | 
			
		||||
int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
			
		||||
			 struct mgcp_conn *conn)
 | 
			
		||||
 *  \returns MGCP_CONN_* on success, MGCP_CONN_NONE on error */
 | 
			
		||||
enum mgcp_connection_mode mgcp_parse_conn_mode(const char *mode)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (!mode) {
 | 
			
		||||
		LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
			
		||||
			 "missing connection mode\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (!conn)
 | 
			
		||||
		return -1;
 | 
			
		||||
	if (!endp)
 | 
			
		||||
		return -1;
 | 
			
		||||
	if (!mode)
 | 
			
		||||
		return MGCP_CONN_NONE;
 | 
			
		||||
 | 
			
		||||
	if (strcasecmp(mode, "recvonly") == 0)
 | 
			
		||||
		conn->mode = MGCP_CONN_RECV_ONLY;
 | 
			
		||||
	else if (strcasecmp(mode, "sendrecv") == 0)
 | 
			
		||||
		conn->mode = MGCP_CONN_RECV_SEND;
 | 
			
		||||
	else if (strcasecmp(mode, "sendonly") == 0)
 | 
			
		||||
		conn->mode = MGCP_CONN_SEND_ONLY;
 | 
			
		||||
	else if (strcasecmp(mode, "confecho") == 0)
 | 
			
		||||
		conn->mode = MGCP_CONN_CONFECHO;
 | 
			
		||||
	else if (strcasecmp(mode, "loopback") == 0)
 | 
			
		||||
		conn->mode = MGCP_CONN_LOOPBACK;
 | 
			
		||||
	else {
 | 
			
		||||
		LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
			
		||||
			 "unknown connection mode: '%s'\n", mode);
 | 
			
		||||
		ret = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Special handling for RTP connections */
 | 
			
		||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
			
		||||
		conn->u.rtp.end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
 | 
			
		||||
 | 
			
		||||
	LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
 | 
			
		||||
		 mode, conn->mode);
 | 
			
		||||
 | 
			
		||||
	/* Special handling für RTP connections */
 | 
			
		||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
			
		||||
		LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
 | 
			
		||||
			 conn->u.rtp.end.output_enabled);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* The VTY might change the connection mode at any time, so we have
 | 
			
		||||
	 * to hold a copy of the original connection mode */
 | 
			
		||||
	conn->mode_orig = conn->mode;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
		return MGCP_CONN_RECV_ONLY;
 | 
			
		||||
	if (strcasecmp(mode, "sendrecv") == 0)
 | 
			
		||||
		return MGCP_CONN_RECV_SEND;
 | 
			
		||||
	if (strcasecmp(mode, "sendonly") == 0)
 | 
			
		||||
		return MGCP_CONN_SEND_ONLY;
 | 
			
		||||
	if (strcasecmp(mode, "confecho") == 0)
 | 
			
		||||
		return MGCP_CONN_CONFECHO;
 | 
			
		||||
	if (strcasecmp(mode, "loopback") == 0)
 | 
			
		||||
		return MGCP_CONN_LOOPBACK;
 | 
			
		||||
	return MGCP_CONN_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Analyze and parse the the hader of an MGCP messeage string.
 | 
			
		||||
@@ -159,8 +127,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:
 | 
			
		||||
			if (strcasecmp("MGCP", elem)) {
 | 
			
		||||
				LOGP(DLMGCP, LOGL_ERROR,
 | 
			
		||||
				     "MGCP header parsing error\n");
 | 
			
		||||
				LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP header parsing error\n");
 | 
			
		||||
				return -510;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
@@ -173,13 +140,87 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (i != 4) {
 | 
			
		||||
		LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
 | 
			
		||||
		LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP status line too short.\n");
 | 
			
		||||
		return -510;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool parse_x_osmo_ign(struct mgcp_parse_data *pdata, char *line)
 | 
			
		||||
{
 | 
			
		||||
	char *saveptr = NULL;
 | 
			
		||||
 | 
			
		||||
	if (strncasecmp(line, MGCP_X_OSMO_IGN_HEADER, strlen(MGCP_X_OSMO_IGN_HEADER)))
 | 
			
		||||
		return false;
 | 
			
		||||
	line += strlen(MGCP_X_OSMO_IGN_HEADER);
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		char *token = strtok_r(line, " ", &saveptr);
 | 
			
		||||
		line = NULL;
 | 
			
		||||
		if (!token)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (!strcasecmp(token, "C"))
 | 
			
		||||
			pdata->hpars.x_osmo_ign |= MGCP_X_OSMO_IGN_CALLID;
 | 
			
		||||
		else
 | 
			
		||||
			LOG_MGCP_PDATA(pdata, LOGL_ERROR, "received unknown X-Osmo-IGN item '%s'\n", token);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Analyze and parse the the header of an MGCP message string.
 | 
			
		||||
 *  \param[inout] pdata caller provided memory to store the parsing results.
 | 
			
		||||
 *  \returns 0 when parsing was successful, negative (MGCP cause code) on error. */
 | 
			
		||||
int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_parse_hdr_pars *hp = &pdata->hpars;
 | 
			
		||||
	char *line;
 | 
			
		||||
 | 
			
		||||
	mgcp_parse_hdr_pars_init(hp);
 | 
			
		||||
 | 
			
		||||
	for_each_line(line, pdata->save) {
 | 
			
		||||
		if (!mgcp_check_param(line)) {
 | 
			
		||||
			LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch (toupper(line[0])) {
 | 
			
		||||
		case 'L':
 | 
			
		||||
			hp->local_options = (const char *)line + 3;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'C':
 | 
			
		||||
			hp->callid = (const char *)line + 3;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'I':
 | 
			
		||||
			hp->connid = (const char *)line + 3;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'M':
 | 
			
		||||
			hp->mode = mgcp_parse_conn_mode((const char *)line + 3);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'X':
 | 
			
		||||
			if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
			
		||||
				hp->remote_osmux_cid = mgcp_parse_osmux_cid(line);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			if (parse_x_osmo_ign(pdata, line))
 | 
			
		||||
				break;
 | 
			
		||||
			/* Ignore unknown X-headers */
 | 
			
		||||
			break;
 | 
			
		||||
		case '\0':
 | 
			
		||||
			hp->have_sdp = true;
 | 
			
		||||
			goto mgcp_header_done;
 | 
			
		||||
		default:
 | 
			
		||||
			LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "CRCX: unhandled option: '%c'/%d\n", *line, *line);
 | 
			
		||||
			return -539;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
mgcp_header_done:
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Extract OSMUX CID from an MGCP parameter line (string).
 | 
			
		||||
 *  \param[in] line single parameter line from the MGCP message
 | 
			
		||||
 *  \returns OSMUX CID, -1 wildcard, -2 on error */
 | 
			
		||||
@@ -190,19 +231,19 @@ int mgcp_parse_osmux_cid(const char *line)
 | 
			
		||||
 | 
			
		||||
	if (strcasecmp(line + 2, "Osmux: *") == 0) {
 | 
			
		||||
		LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
		return MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
 | 
			
		||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
 | 
			
		||||
		     line);
 | 
			
		||||
		return -2;
 | 
			
		||||
		return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (osmux_cid > OSMUX_CID_MAX) {
 | 
			
		||||
		LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
 | 
			
		||||
		     osmux_cid, OSMUX_CID_MAX);
 | 
			
		||||
		return -2;
 | 
			
		||||
		return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
 | 
			
		||||
	}
 | 
			
		||||
	LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
 | 
			
		||||
 | 
			
		||||
@@ -210,20 +251,13 @@ int mgcp_parse_osmux_cid(const char *line)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Check MGCP parameter line (string) for plausibility.
 | 
			
		||||
 *  \param[in] endp pointer to endpoint (only used for log output, may be NULL)
 | 
			
		||||
 *  \param[in] trunk pointer to trunk (only used for log output, may be NULL if endp is not NULL)
 | 
			
		||||
 *  \param[in] line single parameter line from the MGCP message
 | 
			
		||||
 *  \returns true when line seems plausible, false on error */
 | 
			
		||||
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line)
 | 
			
		||||
bool mgcp_check_param(const char *line)
 | 
			
		||||
{
 | 
			
		||||
	const size_t line_len = strlen(line);
 | 
			
		||||
	if (line[0] != '\0' && line_len < 2) {
 | 
			
		||||
		if (endp)
 | 
			
		||||
			LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
 | 
			
		||||
		else
 | 
			
		||||
			LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
 | 
			
		||||
	if (line[0] != '\0' && line_len < 2)
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME: A couple more checks wouldn't hurt... */
 | 
			
		||||
 | 
			
		||||
@@ -294,7 +328,7 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check if connection exists */
 | 
			
		||||
	if (mgcp_conn_get(endp, conn_id))
 | 
			
		||||
	if (mgcp_endp_get_conn(endp, conn_id))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
			
		||||
 
 | 
			
		||||
@@ -85,12 +85,6 @@ static inline struct msgb *mgw_msgb_copy_c(void *ctx, struct msgb *msg, const ch
 | 
			
		||||
 | 
			
		||||
static int rx_rtp(struct msgb *msg);
 | 
			
		||||
 | 
			
		||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
 | 
			
		||||
{
 | 
			
		||||
	return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
 | 
			
		||||
	       (osmo_sockaddr_is_any(&rtp_end->addr) == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Determine the local rtp bind IP-address.
 | 
			
		||||
 *  \param[out] addr caller provided memory to store the resulting IP-Address.
 | 
			
		||||
 *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
 | 
			
		||||
@@ -338,7 +332,7 @@ static int adjust_rtp_timestamp_offset(const struct mgcp_endpoint *endp,
 | 
			
		||||
				 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
 | 
			
		||||
				 osmo_sockaddr_port(&addr->u.sa));
 | 
			
		||||
		} else {
 | 
			
		||||
			tsdelta = rtp_end->codec->rate * 20 / 1000;
 | 
			
		||||
			tsdelta = rtp_end->cset.codec->rate * 20 / 1000;
 | 
			
		||||
			LOGPENDP(endp, DRTP, LOGL_NOTICE,
 | 
			
		||||
				 "Fixed packet duration and last timestamp delta "
 | 
			
		||||
				 "are not available, "
 | 
			
		||||
@@ -502,11 +496,11 @@ static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
			
		||||
	}
 | 
			
		||||
	rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
			
		||||
 | 
			
		||||
	if (!conn_dst->end.codec) {
 | 
			
		||||
	if (!conn_dst->end.cset.codec) {
 | 
			
		||||
		LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "no codec set on destination connection!\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	rtp_hdr->payload_type = (uint8_t) conn_dst->end.codec->payload_type;
 | 
			
		||||
	rtp_hdr->payload_type = (uint8_t) conn_dst->end.cset.codec->payload_type;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -529,7 +523,8 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
			
		||||
	uint32_t timestamp, ssrc;
 | 
			
		||||
	bool marker_bit;
 | 
			
		||||
	struct rtp_hdr *rtp_hdr;
 | 
			
		||||
	int payload = rtp_end->codec->payload_type;
 | 
			
		||||
	struct mgcp_rtp_codec *codec = rtp_end->cset.codec;
 | 
			
		||||
	int payload = codec->payload_type;
 | 
			
		||||
	unsigned int len = msgb_length(msg);
 | 
			
		||||
 | 
			
		||||
	if (len < sizeof(*rtp_hdr))
 | 
			
		||||
@@ -538,7 +533,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 = mgcp_get_current_ts(codec->rate);
 | 
			
		||||
	ssrc = ntohl(rtp_hdr->ssrc);
 | 
			
		||||
	marker_bit = !!rtp_hdr->marker;
 | 
			
		||||
	transit = arrival_time - timestamp;
 | 
			
		||||
@@ -547,16 +542,16 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
			
		||||
 | 
			
		||||
	if (!state->initialized) {
 | 
			
		||||
		state->initialized = 1;
 | 
			
		||||
		state->packet_duration = mgcp_rtp_packet_duration(endp, rtp_end);
 | 
			
		||||
		state->in_stream.last_seq = seq - 1;
 | 
			
		||||
		state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
 | 
			
		||||
		state->in_stream.ssrc = ssrc;
 | 
			
		||||
		state->in_stream.last_tsdelta = 0;
 | 
			
		||||
		state->packet_duration =
 | 
			
		||||
		    mgcp_rtp_packet_duration(endp, rtp_end);
 | 
			
		||||
		state->out_stream.last_seq = seq - 1;
 | 
			
		||||
		state->out_stream.ssrc = state->patch.orig_ssrc = ssrc;
 | 
			
		||||
		state->out_stream.last_tsdelta = 0;
 | 
			
		||||
		state->out_stream.last_timestamp = timestamp;
 | 
			
		||||
		state->out_stream.ssrc = ssrc - 1;	/* force output SSRC change */
 | 
			
		||||
		state->patch.orig_ssrc = ssrc;
 | 
			
		||||
		state->patch.patch_ssrc = rtp_end->force_constant_ssrc;
 | 
			
		||||
		LOGPENDP(endp, DRTP, LOGL_INFO,
 | 
			
		||||
			 "initializing stream, SSRC: %u timestamp: %u "
 | 
			
		||||
			 "pkt-duration: %d, from %s:%d\n",
 | 
			
		||||
@@ -566,7 +561,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
			
		||||
			 osmo_sockaddr_port(&addr->u.sa));
 | 
			
		||||
		if (state->packet_duration == 0) {
 | 
			
		||||
			state->packet_duration =
 | 
			
		||||
			    rtp_end->codec->rate * 20 / 1000;
 | 
			
		||||
			    codec->rate * 20 / 1000;
 | 
			
		||||
			LOGPENDP(endp, DRTP, LOGL_NOTICE,
 | 
			
		||||
				 "fixed packet duration is not available, "
 | 
			
		||||
				 "using fixed 20ms instead: %d from %s:%d\n",
 | 
			
		||||
@@ -583,7 +578,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
			
		||||
			 osmo_sockaddr_port(&addr->u.sa));
 | 
			
		||||
 | 
			
		||||
		state->in_stream.ssrc = ssrc;
 | 
			
		||||
		if (rtp_end->force_constant_ssrc) {
 | 
			
		||||
		if (state->patch.patch_ssrc) {
 | 
			
		||||
			int16_t delta_seq;
 | 
			
		||||
 | 
			
		||||
			/* Always increment seqno by 1 */
 | 
			
		||||
@@ -599,10 +594,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
			
		||||
			adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
 | 
			
		||||
						    delta_seq, timestamp, marker_bit);
 | 
			
		||||
 | 
			
		||||
			state->patch.patch_ssrc = true;
 | 
			
		||||
			ssrc = state->patch.orig_ssrc;
 | 
			
		||||
			if (rtp_end->force_constant_ssrc != -1)
 | 
			
		||||
				rtp_end->force_constant_ssrc -= 1;
 | 
			
		||||
 | 
			
		||||
			LOGPENDP(endp, DRTP, LOGL_NOTICE,
 | 
			
		||||
				 "SSRC patching enabled, SSRC: %u "
 | 
			
		||||
@@ -822,8 +814,8 @@ static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	hdr->version = 2;
 | 
			
		||||
	hdr->payload_type = rtp_end->codec->payload_type;
 | 
			
		||||
	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
 | 
			
		||||
	hdr->payload_type = rtp_end->cset.codec->payload_type;
 | 
			
		||||
	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
 | 
			
		||||
	hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
 | 
			
		||||
	hdr->ssrc = state->alt_rtp_tx_ssrc;
 | 
			
		||||
}
 | 
			
		||||
@@ -1189,6 +1181,8 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
			
		||||
			 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
			
		||||
		    );
 | 
			
		||||
	} else if (is_rtp) {
 | 
			
		||||
		struct mgcp_rtp_codec *src_codec;
 | 
			
		||||
		struct mgcp_rtp_codec *dst_codec;
 | 
			
		||||
		/* Make sure we have a valid RTP header, in cases where no RTP
 | 
			
		||||
		 * header is present, we will generate one. */
 | 
			
		||||
		gen_rtp_header(msg, rtp_end, rtp_state);
 | 
			
		||||
@@ -1204,19 +1198,21 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
			
		||||
		if (addr)
 | 
			
		||||
			mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg);
 | 
			
		||||
 | 
			
		||||
		src_codec = conn_src->end.cset.codec;
 | 
			
		||||
		dst_codec = conn_dst->end.cset.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 (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
 | 
			
		||||
			rc = amr_oa_bwe_convert(endp, msg, conn_dst->end.codec->param.amr_octet_aligned);
 | 
			
		||||
		} else if (mgcp_codec_amr_align_mode_is_indicated(dst_codec)) {
 | 
			
		||||
			rc = amr_oa_bwe_convert(endp, msg, dst_codec->param.amr_octet_aligned);
 | 
			
		||||
			if (rc < 0) {
 | 
			
		||||
				LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
			
		||||
					 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
 | 
			
		||||
					 conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
 | 
			
		||||
					 dst_codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
 | 
			
		||||
				msgb_free(msg);
 | 
			
		||||
				return rc;
 | 
			
		||||
			}
 | 
			
		||||
		} else if (rtp_end->rfc5993_hr_convert &&
 | 
			
		||||
			   strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) {
 | 
			
		||||
			   strcmp(src_codec->subtype_name, "GSM-HR-08") == 0) {
 | 
			
		||||
			rc = rfc5993_hr_convert(endp, msg);
 | 
			
		||||
			if (rc < 0) {
 | 
			
		||||
				LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
 | 
			
		||||
@@ -1251,7 +1247,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else if (!trunk->omit_rtcp) {
 | 
			
		||||
		struct osmo_sockaddr rtcp_addr = rtp_end->addr;
 | 
			
		||||
		osmo_sockaddr_set_port(&rtcp_addr.u.sa, rtp_end->rtcp_port);
 | 
			
		||||
		osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(rtp_end->rtcp_port));
 | 
			
		||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
			
		||||
			 "send to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
			
		||||
			 dest_name, osmo_sockaddr_ntop(&rtcp_addr.u.sa, ipbuf),
 | 
			
		||||
@@ -1343,13 +1339,13 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
			
		||||
		 * packets back to their origin. We will use the originating
 | 
			
		||||
		 * address data from the UDP packet header to patch the
 | 
			
		||||
		 * outgoing address in connection on the fly */
 | 
			
		||||
		if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
 | 
			
		||||
			memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
			
		||||
			       sizeof(conn->u.rtp.end.addr));
 | 
			
		||||
		if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) {
 | 
			
		||||
			memcpy(&conn_src->end.addr, from_addr,
 | 
			
		||||
			       sizeof(conn_src->end.addr));
 | 
			
		||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
			
		||||
				     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
			
		||||
				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
			
		||||
				     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
			
		||||
				     osmo_sockaddr_port(&conn_src->end.addr.u.sa));
 | 
			
		||||
		}
 | 
			
		||||
		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
			
		||||
	}
 | 
			
		||||
@@ -1428,19 +1424,19 @@ int mgcp_dispatch_e1_bridge_cb(struct msgb *msg)
 | 
			
		||||
		 * packets back to their origin. We will use the originating
 | 
			
		||||
		 * address data from the UDP packet header to patch the
 | 
			
		||||
		 * outgoing address in connection on the fly */
 | 
			
		||||
		if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
 | 
			
		||||
			memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
			
		||||
			       sizeof(conn->u.rtp.end.addr));
 | 
			
		||||
		if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) {
 | 
			
		||||
			memcpy(&conn_src->end.addr, from_addr,
 | 
			
		||||
			       sizeof(conn_src->end.addr));
 | 
			
		||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
			
		||||
				     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
			
		||||
				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
			
		||||
				     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
			
		||||
				     osmo_sockaddr_port(&conn_src->end.addr.u.sa));
 | 
			
		||||
		}
 | 
			
		||||
		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Forward to E1 */
 | 
			
		||||
	return mgcp_e1_send_rtp(conn->endp, conn->u.rtp.end.codec, msg);
 | 
			
		||||
	return mgcp_e1_send_rtp(conn->endp, conn_src->end.cset.codec, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
 | 
			
		||||
@@ -1562,18 +1558,18 @@ static int rx_rtp(struct msgb *msg)
 | 
			
		||||
 | 
			
		||||
	/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */
 | 
			
		||||
	if (mc->proto == MGCP_PROTO_RTP
 | 
			
		||||
	    && conn_src->end.codec
 | 
			
		||||
	    && mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
 | 
			
		||||
	    && conn_src->end.cset.codec
 | 
			
		||||
	    && mgcp_codec_amr_align_mode_is_indicated(conn_src->end.cset.codec)) {
 | 
			
		||||
		/* Make sure that the incoming AMR frame format matches the frame format that the call agent has
 | 
			
		||||
		 * communicated via SDP when the connection was created/modfied. */
 | 
			
		||||
		int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
 | 
			
		||||
		if (oa < 0)
 | 
			
		||||
			goto out_free;
 | 
			
		||||
		if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) {
 | 
			
		||||
		if (((bool)oa) != conn_src->end.cset.codec->param.amr_octet_aligned) {
 | 
			
		||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
			
		||||
				     "rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
 | 
			
		||||
				     " check the config of your call-agent!\n",
 | 
			
		||||
				     msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa);
 | 
			
		||||
				     msgb_length(msg), conn_src->end.cset.codec->param.amr_octet_aligned, oa);
 | 
			
		||||
			goto out_free;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -1629,78 +1625,23 @@ int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t pr
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
 | 
			
		||||
static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
 | 
			
		||||
		    struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp)
 | 
			
		||||
{
 | 
			
		||||
	int rc, rtp_fd, rtcp_fd;
 | 
			
		||||
 | 
			
		||||
	/* NOTE: The port that is used for RTCP is the RTP port incremented by one
 | 
			
		||||
	 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
 | 
			
		||||
 | 
			
		||||
	rc = mgcp_create_bind(source_addr, rtp_end->local_port, cfg->endp_dscp, cfg->endp_priority);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
			
		||||
			 "failed to create RTP port: %s:%d\n",
 | 
			
		||||
			 source_addr, rtp_end->local_port);
 | 
			
		||||
		goto cleanup0;
 | 
			
		||||
	}
 | 
			
		||||
	rtp_fd = rc;
 | 
			
		||||
 | 
			
		||||
	rc = mgcp_create_bind(source_addr, rtp_end->local_port + 1, cfg->endp_dscp, cfg->endp_priority);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
			
		||||
			 "failed to create RTCP port: %s:%d\n",
 | 
			
		||||
			 source_addr, rtp_end->local_port + 1);
 | 
			
		||||
		goto cleanup1;
 | 
			
		||||
	}
 | 
			
		||||
	rtcp_fd = rc;
 | 
			
		||||
 | 
			
		||||
	if (osmo_iofd_register(rtp_end->rtp, rtp_fd) < 0) {
 | 
			
		||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
			
		||||
			 "failed to register RTP port %d\n",
 | 
			
		||||
			 rtp_end->local_port);
 | 
			
		||||
		goto cleanup2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (osmo_iofd_register(rtp_end->rtcp, rtcp_fd) != 0) {
 | 
			
		||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
			
		||||
			 "failed to register RTCP port %d\n",
 | 
			
		||||
			 rtp_end->local_port + 1);
 | 
			
		||||
		goto cleanup3;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
cleanup3:
 | 
			
		||||
	osmo_iofd_unregister(rtp_end->rtp);
 | 
			
		||||
cleanup2:
 | 
			
		||||
	close(rtcp_fd);
 | 
			
		||||
cleanup1:
 | 
			
		||||
	close(rtp_fd);
 | 
			
		||||
cleanup0:
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! bind RTP port to endpoint/connection.
 | 
			
		||||
 *  \param[in] endp endpoint that holds the RTP connection.
 | 
			
		||||
 *  \param[in] rtp_port port number to bind on.
 | 
			
		||||
 *  \param[in] conn associated RTP connection.
 | 
			
		||||
 *  \param[in] rtp_port port number to bind on.
 | 
			
		||||
 *  \returns 0 on success, -1 on ERROR. */
 | 
			
		||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
			
		||||
			   struct mgcp_conn_rtp *conn)
 | 
			
		||||
int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn_rtp, int rtp_port)
 | 
			
		||||
{
 | 
			
		||||
	char name[512];
 | 
			
		||||
	struct mgcp_rtp_end *end;
 | 
			
		||||
	struct mgcp_conn *conn = conn_rtp->conn;
 | 
			
		||||
	struct mgcp_config *cfg = conn->endp->trunk->cfg;
 | 
			
		||||
	struct mgcp_rtp_end *end = &conn_rtp->end;
 | 
			
		||||
	int rc, rtp_fd, rtcp_fd;
 | 
			
		||||
 | 
			
		||||
	snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
 | 
			
		||||
	end = &conn->end;
 | 
			
		||||
	snprintf(name, sizeof(name), "%s-%s", conn->name, conn->id);
 | 
			
		||||
 | 
			
		||||
	if ((end->rtp && osmo_iofd_get_fd(end->rtp) != -1) ||
 | 
			
		||||
	    (end->rtcp && osmo_iofd_get_fd(end->rtcp) != -1)) {
 | 
			
		||||
		LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
 | 
			
		||||
			 rtp_port, mgcp_conn_dump(conn->conn));
 | 
			
		||||
 | 
			
		||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%u was already bound\n", rtp_port);
 | 
			
		||||
		/* Double bindings should never occour! Since we always allocate
 | 
			
		||||
		 * connections dynamically and free them when they are not
 | 
			
		||||
		 * needed anymore, there must be no previous binding leftover.
 | 
			
		||||
@@ -1710,33 +1651,55 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	end->local_port = rtp_port;
 | 
			
		||||
	end->rtp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
 | 
			
		||||
	end->rtp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp);
 | 
			
		||||
	if (!end->rtp)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
		goto free_iofd_ret;
 | 
			
		||||
	osmo_iofd_set_alloc_info(end->rtp, RTP_BUF_SIZE, 0);
 | 
			
		||||
	end->rtcp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
 | 
			
		||||
	if (!end->rtcp) {
 | 
			
		||||
		osmo_iofd_free(end->rtp);
 | 
			
		||||
		end->rtp = NULL;
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
	end->rtcp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp);
 | 
			
		||||
	if (!end->rtcp)
 | 
			
		||||
		goto free_iofd_ret;
 | 
			
		||||
	osmo_iofd_set_alloc_info(end->rtcp, RTP_BUF_SIZE, 0);
 | 
			
		||||
	osmo_iofd_set_priv_nr(end->rtcp, 1); /* we use priv_nr as identifier for RTCP */
 | 
			
		||||
 | 
			
		||||
	return bind_rtp(endp->trunk->cfg, conn->end.local_addr, end, endp);
 | 
			
		||||
}
 | 
			
		||||
	/* NOTE: The port that is used for RTCP is the RTP port incremented by one
 | 
			
		||||
	 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
 | 
			
		||||
 | 
			
		||||
/*! free allocated RTP and RTCP ports.
 | 
			
		||||
 *  \param[in] end RTP end */
 | 
			
		||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
 | 
			
		||||
{
 | 
			
		||||
	if (end->rtp) {
 | 
			
		||||
		osmo_iofd_free(end->rtp);
 | 
			
		||||
		end->rtp = NULL;
 | 
			
		||||
	rc = mgcp_create_bind(end->local_addr, end->local_port, cfg->endp_dscp, cfg->endp_priority);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTP port: %s:%d\n", end->local_addr, end->local_port);
 | 
			
		||||
		goto free_iofd_ret;
 | 
			
		||||
	}
 | 
			
		||||
	rtp_fd = rc;
 | 
			
		||||
 | 
			
		||||
	rc = mgcp_create_bind(end->local_addr, end->local_port + 1, cfg->endp_dscp, cfg->endp_priority);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTCP port: %s:%d\n", end->local_addr, end->local_port + 1);
 | 
			
		||||
		goto cleanup1;
 | 
			
		||||
	}
 | 
			
		||||
	rtcp_fd = rc;
 | 
			
		||||
 | 
			
		||||
	if (osmo_iofd_register(end->rtp, rtp_fd) < 0) {
 | 
			
		||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTP port %d\n", end->local_port);
 | 
			
		||||
		goto cleanup2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (end->rtcp) {
 | 
			
		||||
		osmo_iofd_free(end->rtcp);
 | 
			
		||||
		end->rtcp = NULL;
 | 
			
		||||
	if (osmo_iofd_register(end->rtcp, rtcp_fd) != 0) {
 | 
			
		||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTCP port %d\n", end->local_port + 1);
 | 
			
		||||
		goto cleanup3;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
cleanup3:
 | 
			
		||||
	osmo_iofd_unregister(end->rtp);
 | 
			
		||||
cleanup2:
 | 
			
		||||
	close(rtcp_fd);
 | 
			
		||||
cleanup1:
 | 
			
		||||
	close(rtp_fd);
 | 
			
		||||
free_iofd_ret:
 | 
			
		||||
	osmo_iofd_free(end->rtcp);
 | 
			
		||||
	end->rtcp = NULL;
 | 
			
		||||
	osmo_iofd_free(end->rtp);
 | 
			
		||||
	end->rtp = NULL;
 | 
			
		||||
	return -EIO;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -265,7 +265,7 @@ osmux_conn_lookup(const struct mgcp_trunk *trunk, uint8_t local_cid, const struc
 | 
			
		||||
			if (conn->type != MGCP_CONN_TYPE_RTP)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			conn_rtp = &conn->u.rtp;
 | 
			
		||||
			conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
			
		||||
			if (!mgcp_conn_rtp_is_osmux(conn_rtp))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
@@ -651,7 +651,7 @@ int conn_osmux_enable(struct mgcp_conn_rtp *conn)
 | 
			
		||||
	osmux_xfrm_output_set_rtp_ssrc(conn->osmux.out,
 | 
			
		||||
				       (conn->osmux.remote_cid * rtp_ssrc_winlen) +
 | 
			
		||||
				       (random() % rtp_ssrc_winlen));
 | 
			
		||||
	osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.codec->payload_type);
 | 
			
		||||
	osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.cset.codec->payload_type);
 | 
			
		||||
	osmux_xfrm_output_set_tx_cb(conn->osmux.out,
 | 
			
		||||
				    scheduled_from_osmux_tx_rtp_cb, conn);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										104
									
								
								src/libosmo-mgcp/mgcp_rtp_end.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/libosmo-mgcp/mgcp_rtp_end.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
			
		||||
/*
 | 
			
		||||
 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
			
		||||
 * (C) 2009-2012 by On-Waves
 | 
			
		||||
 * (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/select.h>
 | 
			
		||||
#include <osmocom/core/socket.h>
 | 
			
		||||
#include <osmocom/core/osmo_io.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_rtp_end.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
			
		||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
			
		||||
 | 
			
		||||
/***********************
 | 
			
		||||
 * mgcp_rtp_end
 | 
			
		||||
 **********************/
 | 
			
		||||
 | 
			
		||||
void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_trunk *trunk = conn_rtp->conn->endp->trunk;
 | 
			
		||||
	struct mgcp_config *cfg = trunk->cfg;
 | 
			
		||||
 | 
			
		||||
	end->conn_rtp = conn_rtp;
 | 
			
		||||
	end->rtp = NULL;
 | 
			
		||||
	end->rtcp = NULL;
 | 
			
		||||
	memset(&end->addr, 0, sizeof(end->addr));
 | 
			
		||||
	end->rtcp_port = 0;
 | 
			
		||||
 | 
			
		||||
	/* Set default values */
 | 
			
		||||
	end->frames_per_packet = 0;	/* unknown */
 | 
			
		||||
	end->output_enabled = false;
 | 
			
		||||
	end->maximum_packet_time = -1;
 | 
			
		||||
 | 
			
		||||
	end->force_aligned_timing = trunk->force_aligned_timing;
 | 
			
		||||
	end->force_constant_ssrc = trunk->force_constant_ssrc;
 | 
			
		||||
	end->rfc5993_hr_convert = trunk->rfc5993_hr_convert;
 | 
			
		||||
 | 
			
		||||
	if (cfg->force_ptime) {
 | 
			
		||||
		end->packet_duration_ms = cfg->force_ptime;
 | 
			
		||||
		end->force_output_ptime = 1;
 | 
			
		||||
	} else {
 | 
			
		||||
		end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Make sure codec table is reset */
 | 
			
		||||
	mgcp_codecset_reset(&end->cset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end)
 | 
			
		||||
{
 | 
			
		||||
	mgcp_rtp_end_free_port(end);
 | 
			
		||||
	mgcp_codecset_reset(&end->cset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms)
 | 
			
		||||
{
 | 
			
		||||
	if (end->force_output_ptime)
 | 
			
		||||
		return;
 | 
			
		||||
	end->packet_duration_ms = packet_duration_ms;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
 | 
			
		||||
{
 | 
			
		||||
	return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
 | 
			
		||||
	       (osmo_sockaddr_is_any(&rtp_end->addr) == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! free allocated RTP and RTCP ports.
 | 
			
		||||
 *  \param[in] end RTP end */
 | 
			
		||||
void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end)
 | 
			
		||||
{
 | 
			
		||||
	if (end->rtp) {
 | 
			
		||||
		osmo_iofd_free(end->rtp);
 | 
			
		||||
		end->rtp = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (end->rtcp) {
 | 
			
		||||
		osmo_iofd_free(end->rtcp);
 | 
			
		||||
		end->rtcp = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -312,16 +312,13 @@ static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Analyze SDP input string.
 | 
			
		||||
 *  \param[in] endp trunk endpoint.
 | 
			
		||||
 *  \param[out] conn associated rtp connection.
 | 
			
		||||
 *  \param[out] caller provided memory to store the parsing results.
 | 
			
		||||
 *  \param[inout] p provided memory to store the parsing results.
 | 
			
		||||
 *
 | 
			
		||||
 *  Note: In conn (conn->end) the function returns the packet duration,
 | 
			
		||||
 *  rtp port, rtcp port and the codec information.
 | 
			
		||||
 *  \returns 0 on success, -1 on failure. */
 | 
			
		||||
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
			
		||||
			struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
 | 
			
		||||
int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
 | 
			
		||||
{
 | 
			
		||||
	OSMO_ASSERT(p);
 | 
			
		||||
	struct mgcp_parse_sdp *sdp = &p->sdp;
 | 
			
		||||
	struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
 | 
			
		||||
	unsigned int codecs_used = 0;
 | 
			
		||||
	struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
 | 
			
		||||
@@ -331,19 +328,14 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
			
		||||
	char *line;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	void *tmp_ctx = talloc_new(NULL);
 | 
			
		||||
	struct mgcp_rtp_end *rtp;
 | 
			
		||||
 | 
			
		||||
	int payload_type;
 | 
			
		||||
	int ptime, ptime2 = 0;
 | 
			
		||||
	char audio_name[64];
 | 
			
		||||
	int port, rc;
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(endp);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	OSMO_ASSERT(p);
 | 
			
		||||
 | 
			
		||||
	rtp = &conn->end;
 | 
			
		||||
	memset(&codecs, 0, sizeof(codecs));
 | 
			
		||||
	mgcp_parse_sdp_init(sdp);
 | 
			
		||||
 | 
			
		||||
	for_each_line(line, p->save) {
 | 
			
		||||
		switch (line[0]) {
 | 
			
		||||
@@ -361,19 +353,19 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
			
		||||
 | 
			
		||||
			if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
 | 
			
		||||
				if (ptime2 > 0 && ptime2 != ptime)
 | 
			
		||||
					rtp->packet_duration_ms = 0;
 | 
			
		||||
					sdp->ptime = 0;
 | 
			
		||||
				else
 | 
			
		||||
					rtp->packet_duration_ms = ptime;
 | 
			
		||||
					sdp->ptime = ptime;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
 | 
			
		||||
				rtp->maximum_packet_time = ptime2;
 | 
			
		||||
				sdp->maxptime = ptime2;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (strncmp("a=fmtp:", line, 6) == 0) {
 | 
			
		||||
				rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
 | 
			
		||||
				rc = fmtp_from_sdp(tmp_ctx, &fmtp_params[fmtp_used], line);
 | 
			
		||||
				if (rc >= 0)
 | 
			
		||||
					fmtp_used++;
 | 
			
		||||
				break;
 | 
			
		||||
@@ -382,33 +374,23 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
			
		||||
			break;
 | 
			
		||||
		case 'm':
 | 
			
		||||
			rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
			
		||||
			if (rc == 1) {
 | 
			
		||||
				osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
 | 
			
		||||
				rtp->rtcp_port = htons(port + 1);
 | 
			
		||||
			}
 | 
			
		||||
			if (rc == 1)
 | 
			
		||||
				sdp->rtp_port = port;
 | 
			
		||||
 | 
			
		||||
			rc = pt_from_sdp(conn->conn, codecs,
 | 
			
		||||
					 ARRAY_SIZE(codecs), line);
 | 
			
		||||
			rc = pt_from_sdp(tmp_ctx, codecs, ARRAY_SIZE(codecs), line);
 | 
			
		||||
			if (rc > 0)
 | 
			
		||||
				codecs_used = rc;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'c':
 | 
			
		||||
			if (audio_ip_from_sdp(&rtp->addr, line) < 0) {
 | 
			
		||||
			if (audio_ip_from_sdp(&sdp->rem_addr, line) < 0) {
 | 
			
		||||
				talloc_free(tmp_ctx);
 | 
			
		||||
				return -1;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			if (endp)
 | 
			
		||||
				/* TODO: Check spec: We used the bare endpoint number before,
 | 
			
		||||
				 * now we use the endpoint name as a whole? Is this allowed? */
 | 
			
		||||
				LOGP(DLMGCP, LOGL_NOTICE,
 | 
			
		||||
				     "Unhandled SDP option: '%c'/%d on %s\n",
 | 
			
		||||
				     line[0], line[0], endp->name);
 | 
			
		||||
			else
 | 
			
		||||
				LOGP(DLMGCP, LOGL_NOTICE,
 | 
			
		||||
				     "Unhandled SDP option: '%c'/%d\n",
 | 
			
		||||
				     line[0], line[0]);
 | 
			
		||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
			
		||||
			     "Unhandled SDP option: '%c'/%d on %s\n",
 | 
			
		||||
			     line[0], line[0], p->epname);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -422,23 +404,22 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
			
		||||
	/* Store parsed codec information */
 | 
			
		||||
	for (i = 0; i < codecs_used; i++) {
 | 
			
		||||
		codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
 | 
			
		||||
		rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
 | 
			
		||||
		rc = mgcp_codecset_add_codec(&sdp->cset, codecs[i].payload_type, codecs[i].map_line, codec_param);
 | 
			
		||||
		if (rc < 0)
 | 
			
		||||
			LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
 | 
			
		||||
			LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to add codec\n", p->epname);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	talloc_free(tmp_ctx);
 | 
			
		||||
 | 
			
		||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
			
		||||
	     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
			
		||||
	     osmo_sockaddr_port(&rtp->addr.u.sa), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
 | 
			
		||||
	     rtp->packet_duration_ms);
 | 
			
		||||
	LOGP(DLMGCP, LOGL_NOTICE,
 | 
			
		||||
	     "%s: Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
			
		||||
	     p->epname, sdp->rtp_port, osmo_sockaddr_ntop(&sdp->rem_addr.u.sa, ipbuf), sdp->ptime);
 | 
			
		||||
	if (codecs_used == 0)
 | 
			
		||||
		LOGPC(DLMGCP, LOGL_NOTICE, "none");
 | 
			
		||||
	for (i = 0; i < codecs_used; i++) {
 | 
			
		||||
		LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
 | 
			
		||||
		      rtp->codecs[i].payload_type,
 | 
			
		||||
		      strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown");
 | 
			
		||||
		      sdp->cset.codecs[i].payload_type,
 | 
			
		||||
		      strlen(sdp->cset.codecs[i].subtype_name) ? sdp->cset.codecs[i].subtype_name : "unknown");
 | 
			
		||||
		LOGPC(DLMGCP, LOGL_NOTICE, " ");
 | 
			
		||||
	}
 | 
			
		||||
	LOGPC(DLMGCP, LOGL_NOTICE, "\n");
 | 
			
		||||
@@ -542,7 +523,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
			
		||||
	OSMO_ASSERT(sdp);
 | 
			
		||||
	OSMO_ASSERT(addr);
 | 
			
		||||
 | 
			
		||||
	codec = conn->end.codec;
 | 
			
		||||
	codec = conn->end.cset.codec;
 | 
			
		||||
 | 
			
		||||
	audio_name = codec->audio_name;
 | 
			
		||||
	payload_type = codec->payload_type;
 | 
			
		||||
 
 | 
			
		||||
@@ -141,7 +141,7 @@ void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn)
 | 
			
		||||
	 * keep this option open: */
 | 
			
		||||
	switch (conn->type) {
 | 
			
		||||
	case MGCP_CONN_TYPE_RTP:
 | 
			
		||||
		mgcp_format_stats_rtp(str, str_len, &conn->u.rtp);
 | 
			
		||||
		mgcp_format_stats_rtp(str, str_len, mgcp_conn_get_conn_rtp(conn));
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
 
 | 
			
		||||
@@ -306,3 +306,43 @@ struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigne
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Try to find a free port by attempting to bind on it. Also handle the
 | 
			
		||||
 * counter that points on the next free port. Since we have a pointer
 | 
			
		||||
 * to the next free port, binding should in work on the first attempt in
 | 
			
		||||
 * general. In case of failure the next port is tried until the whole port
 | 
			
		||||
 * range is tried once. */
 | 
			
		||||
int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct mgcp_port_range *range;
 | 
			
		||||
	unsigned int tries;
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(trunk);
 | 
			
		||||
	OSMO_ASSERT(conn_rtp);
 | 
			
		||||
 | 
			
		||||
	range = &trunk->cfg->net_ports;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&range->lock);
 | 
			
		||||
	/* attempt to find a port */
 | 
			
		||||
	tries = (range->range_end - range->range_start) / 2;
 | 
			
		||||
	for (i = 0; i < tries; ++i) {
 | 
			
		||||
		int rc;
 | 
			
		||||
 | 
			
		||||
		if (range->last_port >= range->range_end)
 | 
			
		||||
			range->last_port = range->range_start;
 | 
			
		||||
 | 
			
		||||
		rc = mgcp_conn_rtp_bind_rtp_ports(conn_rtp, range->last_port);
 | 
			
		||||
 | 
			
		||||
		range->last_port += 2;
 | 
			
		||||
		if (rc == 0) {
 | 
			
		||||
			pthread_mutex_unlock(&range->lock);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	pthread_mutex_unlock(&range->lock);
 | 
			
		||||
	LOGPCONN(conn_rtp->conn, DLMGCP, LOGL_ERROR,
 | 
			
		||||
		 "Allocating a RTP/RTCP port failed %u times.\n", tries);
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -165,7 +165,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_rtp_state *state = &conn->state;
 | 
			
		||||
	struct mgcp_rtp_end *end = &conn->end;
 | 
			
		||||
	struct mgcp_rtp_codec *codec = end->codec;
 | 
			
		||||
	struct mgcp_rtp_codec *codec = end->cset.codec;
 | 
			
		||||
	struct rate_ctr *tx_packets, *tx_bytes;
 | 
			
		||||
	struct rate_ctr *rx_packets, *rx_bytes;
 | 
			
		||||
	struct rate_ctr *dropped_packets;
 | 
			
		||||
@@ -254,7 +254,8 @@ static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
			
		||||
			 * connection types (E1) as soon as
 | 
			
		||||
			 * the implementation is available */
 | 
			
		||||
			if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
			
		||||
				dump_rtp_end(vty, &conn->u.rtp);
 | 
			
		||||
				struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
			
		||||
				dump_rtp_end(vty, conn_rtp);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -856,7 +857,7 @@ DEFUN_USRATTR(cfg_mgcp_patch_rtp_ssrc,
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
			
		||||
	OSMO_ASSERT(trunk);
 | 
			
		||||
	trunk->force_constant_ssrc = 1;
 | 
			
		||||
	trunk->force_constant_ssrc = true;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -867,7 +868,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp_ssrc,
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
			
		||||
	OSMO_ASSERT(trunk);
 | 
			
		||||
	trunk->force_constant_ssrc = 0;
 | 
			
		||||
	trunk->force_constant_ssrc = false;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -922,7 +923,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp,
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
			
		||||
	OSMO_ASSERT(trunk);
 | 
			
		||||
	trunk->force_constant_ssrc = 0;
 | 
			
		||||
	trunk->force_constant_ssrc = false;
 | 
			
		||||
	trunk->force_aligned_timing = 0;
 | 
			
		||||
	trunk->rfc5993_hr_convert = false;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
@@ -1196,7 +1197,7 @@ DEFUN_USRATTR(cfg_trunk_patch_rtp_ssrc,
 | 
			
		||||
	      "rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_trunk *trunk = vty->index;
 | 
			
		||||
	trunk->force_constant_ssrc = 1;
 | 
			
		||||
	trunk->force_constant_ssrc = true;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1206,7 +1207,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp_ssrc,
 | 
			
		||||
	      "no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_trunk *trunk = vty->index;
 | 
			
		||||
	trunk->force_constant_ssrc = 0;
 | 
			
		||||
	trunk->force_constant_ssrc = false;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1256,7 +1257,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp,
 | 
			
		||||
	      "no rtp-patch", NO_STR RTP_PATCH_STR)
 | 
			
		||||
{
 | 
			
		||||
	struct mgcp_trunk *trunk = vty->index;
 | 
			
		||||
	trunk->force_constant_ssrc = 0;
 | 
			
		||||
	trunk->force_constant_ssrc = false;
 | 
			
		||||
	trunk->force_aligned_timing = 0;
 | 
			
		||||
	trunk->rfc5993_hr_convert = false;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
@@ -1357,10 +1358,11 @@ DEFUN(loop_conn,
 | 
			
		||||
	endp = trunk->endpoints[endp_no];
 | 
			
		||||
	int loop = atoi(argv[2]);
 | 
			
		||||
	llist_for_each_entry(conn, &endp->conns, entry) {
 | 
			
		||||
		if (conn->type == MGCP_CONN_TYPE_RTP)
 | 
			
		||||
		if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
			
		||||
			/* Handle it like a MDCX, switch on SSRC patching if enabled */
 | 
			
		||||
			mgcp_rtp_end_config(endp, 1, &conn->u.rtp.end);
 | 
			
		||||
		else {
 | 
			
		||||
			struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
			
		||||
			conn_rtp->state.patch.patch_ssrc = true;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* FIXME: Introduce support for other connection (E1)
 | 
			
		||||
			 * types when implementation is available */
 | 
			
		||||
			vty_out(vty, "%%Can't enable SSRC patching,"
 | 
			
		||||
@@ -1418,7 +1420,7 @@ DEFUN(tap_rtp,
 | 
			
		||||
	endp = trunk->endpoints[endp_no];
 | 
			
		||||
 | 
			
		||||
	conn_id = argv[2];
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
			
		||||
	if (!conn) {
 | 
			
		||||
		vty_out(vty, "Conn ID %s is invalid.%s",
 | 
			
		||||
			conn_id, VTY_NEWLINE);
 | 
			
		||||
 
 | 
			
		||||
@@ -965,7 +965,7 @@ static void test_messages(void)
 | 
			
		||||
			endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
			
		||||
			OSMO_ASSERT(endp);
 | 
			
		||||
 | 
			
		||||
			conn = mgcp_conn_get_rtp(endp, "1");
 | 
			
		||||
			conn = mgcp_endp_get_conn_rtp(endp, "1");
 | 
			
		||||
			if (conn) {
 | 
			
		||||
				OSMO_ASSERT(conn);
 | 
			
		||||
 | 
			
		||||
@@ -1023,14 +1023,14 @@ static void test_messages(void)
 | 
			
		||||
			fprintf(stderr, "endpoint:%s: "
 | 
			
		||||
				"payload type %d (expected %d)\n",
 | 
			
		||||
				last_endpoint,
 | 
			
		||||
				conn->end.codec->payload_type, t->ptype);
 | 
			
		||||
				conn->end.cset.codec->payload_type, t->ptype);
 | 
			
		||||
 | 
			
		||||
			if (t->ptype != PTYPE_IGNORE)
 | 
			
		||||
				OSMO_ASSERT(conn->end.codec->payload_type ==
 | 
			
		||||
				OSMO_ASSERT(conn->end.cset.codec->payload_type ==
 | 
			
		||||
					    t->ptype);
 | 
			
		||||
 | 
			
		||||
			/* Reset them again for next test */
 | 
			
		||||
			conn->end.codec->payload_type = PTYPE_NONE;
 | 
			
		||||
			conn->end.cset.codec->payload_type = PTYPE_NONE;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1208,7 +1208,9 @@ static void test_packet_loss_calc(void)
 | 
			
		||||
		_conn =
 | 
			
		||||
		    mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
			
		||||
				    "test-connection");
 | 
			
		||||
		conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
			
		||||
		OSMO_ASSERT(_conn);
 | 
			
		||||
		conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
 | 
			
		||||
		OSMO_ASSERT(conn);
 | 
			
		||||
		state = &conn->state;
 | 
			
		||||
		packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
			
		||||
 | 
			
		||||
@@ -1228,7 +1230,7 @@ static void test_packet_loss_calc(void)
 | 
			
		||||
			     pl_test_dat[i].expected);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mgcp_conn_free_all(&endp);
 | 
			
		||||
		mgcp_endp_free_conn_all(&endp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	talloc_free(trunk);
 | 
			
		||||
@@ -1459,13 +1461,13 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
			
		||||
	_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
			
		||||
				"test-connection");
 | 
			
		||||
	OSMO_ASSERT(_conn);
 | 
			
		||||
	conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
 | 
			
		||||
	rtp = &conn->end;
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
 | 
			
		||||
	rtp->codec = &rtp->codecs[0];
 | 
			
		||||
	OSMO_ASSERT(mgcp_codecset_add_codec(&conn->end.cset, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
 | 
			
		||||
	rtp->cset.codec = &rtp->cset.codecs[0];
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
 | 
			
		||||
		struct rtp_packet_info *info = test_rtp_packets1 + i;
 | 
			
		||||
@@ -1477,7 +1479,6 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
			
		||||
		OSMO_ASSERT(info->len >= 0);
 | 
			
		||||
		msg->l3h = msgb_put(msg, info->len);
 | 
			
		||||
		memcpy((char*)msgb_l3(msg), info->data, info->len);
 | 
			
		||||
		mgcp_rtp_end_config(&endp, 1, rtp);
 | 
			
		||||
 | 
			
		||||
		mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
 | 
			
		||||
 | 
			
		||||
@@ -1511,7 +1512,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	force_monotonic_time_us = -1;
 | 
			
		||||
	mgcp_conn_free_all(&endp);
 | 
			
		||||
	mgcp_endp_free_conn_all(&endp);
 | 
			
		||||
	talloc_free(trunk);
 | 
			
		||||
	talloc_free(cfg);
 | 
			
		||||
}
 | 
			
		||||
@@ -1546,9 +1547,9 @@ static void test_multilple_codec(void)
 | 
			
		||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
 | 
			
		||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
			
		||||
	OSMO_ASSERT(endp);
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
			
		||||
	OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
 | 
			
		||||
 | 
			
		||||
	/* Allocate 2@mgw with three codecs, last one ignored */
 | 
			
		||||
	last_endpoint[0] = '\0';
 | 
			
		||||
@@ -1562,9 +1563,9 @@ static void test_multilple_codec(void)
 | 
			
		||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
 | 
			
		||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
			
		||||
	OSMO_ASSERT(endp);
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
			
		||||
	OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
 | 
			
		||||
 | 
			
		||||
	/* Allocate 3@mgw with no codecs, check for PT == 0 */
 | 
			
		||||
	/* Note: It usually makes no sense to leave the payload type list
 | 
			
		||||
@@ -1583,9 +1584,9 @@ static void test_multilple_codec(void)
 | 
			
		||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
 | 
			
		||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
			
		||||
	OSMO_ASSERT(endp);
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
			
		||||
	OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
 | 
			
		||||
 | 
			
		||||
	/* Allocate 4@mgw with a single codec */
 | 
			
		||||
	last_endpoint[0] = '\0';
 | 
			
		||||
@@ -1599,9 +1600,9 @@ static void test_multilple_codec(void)
 | 
			
		||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
 | 
			
		||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
			
		||||
	OSMO_ASSERT(endp);
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
			
		||||
	OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
 | 
			
		||||
 | 
			
		||||
	/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
 | 
			
		||||
	last_endpoint[0] = '\0';
 | 
			
		||||
@@ -1615,9 +1616,9 @@ static void test_multilple_codec(void)
 | 
			
		||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
			
		||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
			
		||||
	OSMO_ASSERT(endp);
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
			
		||||
	OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
 | 
			
		||||
 | 
			
		||||
	inp = create_msg(MDCX_NAT_DUMMY, conn_id);
 | 
			
		||||
	last_endpoint[0] = '\0';
 | 
			
		||||
@@ -1627,9 +1628,9 @@ static void test_multilple_codec(void)
 | 
			
		||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
			
		||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
			
		||||
	OSMO_ASSERT(endp);
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	OSMO_ASSERT(conn->end.codec->payload_type == 3);
 | 
			
		||||
	OSMO_ASSERT(conn->end.cset.codec->payload_type == 3);
 | 
			
		||||
	OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
 | 
			
		||||
	memset(&addr, 0, sizeof(addr));
 | 
			
		||||
	inet_aton("8.8.8.8", &addr);
 | 
			
		||||
@@ -1644,7 +1645,7 @@ static void test_multilple_codec(void)
 | 
			
		||||
	talloc_free(endp->last_response);
 | 
			
		||||
	talloc_free(endp->last_trans);
 | 
			
		||||
	endp->last_response = endp->last_trans = NULL;
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
			
		||||
	OSMO_ASSERT(!conn);
 | 
			
		||||
 | 
			
		||||
	last_endpoint[0] = '\0';
 | 
			
		||||
@@ -1658,9 +1659,9 @@ static void test_multilple_codec(void)
 | 
			
		||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
			
		||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
			
		||||
	OSMO_ASSERT(endp);
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
	OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
			
		||||
	OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
 | 
			
		||||
 | 
			
		||||
	mgcp_endpoints_release(trunk);
 | 
			
		||||
	talloc_free(cfg);
 | 
			
		||||
@@ -1687,7 +1688,7 @@ static void test_no_cycle(void)
 | 
			
		||||
	_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
 | 
			
		||||
				"test-connection");
 | 
			
		||||
	OSMO_ASSERT(_conn);
 | 
			
		||||
	conn = mgcp_conn_get_rtp(endp, _conn->id);
 | 
			
		||||
	conn = mgcp_endp_get_conn_rtp(endp, _conn->id);
 | 
			
		||||
	OSMO_ASSERT(conn);
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(conn->state.stats.initialized == 0);
 | 
			
		||||
@@ -2193,7 +2194,7 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
 | 
			
		||||
	int payload_type_conn_dst;
 | 
			
		||||
 | 
			
		||||
	printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
 | 
			
		||||
	if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
 | 
			
		||||
	if (mgcp_codecset_decide(&conn[index_conn_src].end.cset, &conn[index_conn_dst].end.cset) != 0) {
 | 
			
		||||
		if (expect->payload_type_map[index_conn_src] == -EINVAL
 | 
			
		||||
		    && expect->payload_type_map[index_conn_dst] == -EINVAL)
 | 
			
		||||
			printf("    codec decision failed (expected)!\n");
 | 
			
		||||
@@ -2203,19 +2204,19 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		printf("    Codec decision result:\n");
 | 
			
		||||
		if (conn[index_conn_src].end.codec) {
 | 
			
		||||
			payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
 | 
			
		||||
		if (conn[index_conn_src].end.cset.codec) {
 | 
			
		||||
			payload_type_conn_src = conn[index_conn_src].end.cset.codec->payload_type;
 | 
			
		||||
			printf("    conn[%u]: codec:%s, pt:%d\n",
 | 
			
		||||
			       index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
 | 
			
		||||
			       index_conn_src, conn[index_conn_src].end.cset.codec->subtype_name, payload_type_conn_src);
 | 
			
		||||
		} else {
 | 
			
		||||
			payload_type_conn_src = -EINVAL;
 | 
			
		||||
			printf("    conn[%u]: codec:none, pt:none\n", index_conn_src);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (conn[index_conn_dst].end.codec) {
 | 
			
		||||
			payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
 | 
			
		||||
		if (conn[index_conn_dst].end.cset.codec) {
 | 
			
		||||
			payload_type_conn_dst = conn[index_conn_dst].end.cset.codec->payload_type;
 | 
			
		||||
			printf("    conn[%u]: codec:%s, pt:%d\n",
 | 
			
		||||
			       index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
 | 
			
		||||
			       index_conn_dst, conn[index_conn_dst].end.cset.codec->subtype_name,
 | 
			
		||||
			       payload_type_conn_dst);
 | 
			
		||||
		} else {
 | 
			
		||||
			payload_type_conn_dst = -EINVAL;
 | 
			
		||||
@@ -2263,8 +2264,8 @@ static void test_mgcp_codec_decide(void)
 | 
			
		||||
				if (!codec->audio_name)
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
 | 
			
		||||
						    codec->param);
 | 
			
		||||
				rc = mgcp_codecset_add_codec(&conn[conn_i].end.cset, codec->payload_type,
 | 
			
		||||
							     codec->audio_name, codec->param);
 | 
			
		||||
 | 
			
		||||
				printf("   %2d: %3d %s%s  -> rc=%d\n", c, codec->payload_type, codec->audio_name,
 | 
			
		||||
				       codec->param ?
 | 
			
		||||
@@ -2330,7 +2331,7 @@ void test_conn_id_matching(void)
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
 | 
			
		||||
		const char *needle = conn_id_request[i];
 | 
			
		||||
		printf("needle='%s' ", needle);
 | 
			
		||||
		conn_match = mgcp_conn_get(&endp, needle);
 | 
			
		||||
		conn_match = mgcp_endp_get_conn(&endp, needle);
 | 
			
		||||
		OSMO_ASSERT(conn_match);
 | 
			
		||||
		printf("found '%s'\n", conn_match->id);
 | 
			
		||||
		OSMO_ASSERT(conn_match == conn);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user